From 94c0564fe8c46a3d3fc273376c31bc64f07e7ecc Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Tue, 17 Jul 2018 16:42:38 -0700 Subject: [PATCH] Goodbye drive speed finders (#101) * Goodbye drive speed finders * More accurate scaling * Ensure disposal --- DICUI/MainWindow.xaml.cs | 110 +++++++++---------- DICUI/Utilities/DumpEnvironment.cs | 52 ++------- DICUI/Utilities/Validators.cs | 164 ----------------------------- 3 files changed, 57 insertions(+), 269 deletions(-) diff --git a/DICUI/MainWindow.xaml.cs b/DICUI/MainWindow.xaml.cs index 11b21618..238e77c1 100644 --- a/DICUI/MainWindow.xaml.cs +++ b/DICUI/MainWindow.xaml.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.IO; using System.Linq; using System.Windows; @@ -8,25 +9,12 @@ using WinForms = System.Windows.Forms; using DICUI.Data; using DICUI.Utilities; using DICUI.UI; -using System.Runtime.InteropServices; + namespace DICUI { public partial class MainWindow : Window { - [DllImport("gdi32.dll")] - public static extern int GetDeviceCaps(IntPtr hDc, int nIndex); - - [DllImport("user32.dll")] - public static extern IntPtr GetDC(IntPtr hWnd); - - [DllImport("user32.dll")] - public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDc); - - public const int LOGPIXELSX = 88; - public const int LOGPIXELSY = 90; - - // Private UI-related variables private List _drives; private MediaType? _currentMediaType; @@ -42,27 +30,6 @@ namespace DICUI private LogWindow _logWindow; - - public void TransformToUnit(double pixelX, - double pixelY, - out int unitX, - out int unitY) - { - IntPtr hDc = GetDC(IntPtr.Zero); - if (hDc != IntPtr.Zero) - { - int dpiX = GetDeviceCaps(hDc, LOGPIXELSX); - int dpiY = GetDeviceCaps(hDc, LOGPIXELSY); - - ReleaseDC(IntPtr.Zero, hDc); - - unitX = (int)(pixelX / ((double)dpiX / 96)); - unitY = (int)(pixelY / ((double)dpiY / 96)); - } - else - throw new ArgumentNullException("Failed to get DC."); - } - public MainWindow() { InitializeComponent(); @@ -82,17 +49,13 @@ namespace DICUI if (_options.OpenLogWindowAtStartup) { - System.Drawing.Rectangle bounds = WinForms.Screen.PrimaryScreen.WorkingArea; - this.WindowStartupLocation = WindowStartupLocation.Manual; double combinedHeight = this.Height + _logWindow.Height + UIElements.LogWindowMarginFromMainWindow; - TransformToUnit(bounds.Left, bounds.Top, out int unitLeft, out int unitTop); - TransformToUnit(bounds.Width, bounds.Height, out int unitWidth, out int unitHeight); + Rectangle bounds = GetScaledCoordinates(WinForms.Screen.PrimaryScreen.WorkingArea); - this.Left = unitLeft + (unitWidth - this.Width) / 2; - this.Top = unitTop + (unitHeight - combinedHeight) / 2; + this.Left = bounds.Left + (bounds.Width - this.Width) / 2; + this.Top = bounds.Top + (bounds.Height - combinedHeight) / 2; } - } #region Events @@ -422,6 +385,11 @@ namespace DICUI { _env = DetermineEnvironment(); + // Check for the firmware first + // TODO: Remove this (and method) once DIC end-to-end logging becomes a thing + if (!await _env.DriveHasLatestFimrware()) + return; + StartStopButton.Content = UIElements.StopDumping; CopyProtectScanButton.IsEnabled = false; StatusLabel.Content = "Beginning dumping process"; @@ -549,36 +517,20 @@ namespace DICUI /// /// Set the drive speed based on reported maximum and user-defined option /// - private async void SetSupportedDriveSpeed() + private void SetSupportedDriveSpeed() { // Set the drive speed list that's appropriate var values = AllowedSpeeds.GetForMediaType(_currentMediaType); - - // Get the current environment - _env = DetermineEnvironment(); - - // Get the drive speed - int speed = await _env.GetDiscSpeed(); - - // If we have an invalid speed, we need to jump out - if (speed == -1) - { - DriveSpeedComboBox.ItemsSource = values; - DriveSpeedComboBox.SelectedIndex = values.Count / 2; - return; - } - - ViewModels.LoggerViewModel.VerboseLogLn("Determined max drive speed for {0} ({1}): {2}", _env.Drive.Letter, _currentMediaType.Name(), speed); - - DriveSpeedComboBox.ItemsSource = values.Where(s => s <= speed); - ViewModels.LoggerViewModel.VerboseLogLn("Supported drive speeds: {0}", string.Join(",", values.Where(s => s <= speed))); + DriveSpeedComboBox.ItemsSource = values; + ViewModels.LoggerViewModel.VerboseLogLn("Supported media speeds: {0}", string.Join(",", values)); // Choose the lower of the two speeds between the allowed speeds and the user-defined one int chosenSpeed = Math.Min( - values.Where(s => s <= speed).Last(), + values.Where(s => s <= values[values.Count / 2]).Last(), _options.preferredDumpSpeedCD ); + // Set the selected speed ViewModels.LoggerViewModel.VerboseLogLn("Setting drive speed to: {0}", chosenSpeed); DriveSpeedComboBox.SelectedValue = chosenSpeed; } @@ -620,5 +572,37 @@ namespace DICUI } #endregion + + #region UI Helpers + + /// + /// Get pixel coordinates based on DPI scaling + /// + /// Rectangle representing the bounds to transform + /// Rectangle representing the scaled bounds + private Rectangle GetScaledCoordinates(Rectangle bounds) + { + using (Graphics g = Graphics.FromHwnd(IntPtr.Zero)) + { + return new Rectangle( + TransformCoordinate(bounds.Left, g.DpiX), + TransformCoordinate(bounds.Top, g.DpiY), + TransformCoordinate(bounds.Width, g.DpiX), + TransformCoordinate(bounds.Height, g.DpiY)); + } + } + + /// + /// Transform an individual coordinate using DPI scaling + /// + /// Current integer coordinate + /// DPI scaling factor + /// Scaled integer coordinate + private int TransformCoordinate(int coord, float dpi) + { + return (int)(coord / ((double)dpi / 96)); + } + + #endregion } } diff --git a/DICUI/Utilities/DumpEnvironment.cs b/DICUI/Utilities/DumpEnvironment.cs index 87c0d88b..cbea2c6b 100644 --- a/DICUI/Utilities/DumpEnvironment.cs +++ b/DICUI/Utilities/DumpEnvironment.cs @@ -125,32 +125,16 @@ namespace DICUI.Utilities } /// - /// Get disc speed using DIC + /// Gets if the current drive has the latest firmware /// - /// Drive speed if possible, -1 on error - public async Task GetDiscSpeed() + /// + public async Task DriveHasLatestFimrware() { // Validate that the required program exists if (!File.Exists(DICPath)) - return -1; + return false; - // Validate that the drive is set up - if (Drive == null) - return -1; - - // Validate we're not trying to get the speed for a floppy disk - if (IsFloppy) - return -1; - - // Make sure that the current drive is active - if (!Drive.MarkedActive) - return -1; - - // Get the drive speed directly - //int speed = Validators.GetDriveSpeed(Drive); - //int speed = Validators.GetDriveSpeedEx(Drive, _currentMediaType); - - // Get the drive speed from DIC, if possible + // Use the drive speed command as a quick test Process childProcess; string output = await Task.Run(() => { @@ -178,31 +162,15 @@ namespace DICUI.Utilities return stdout; }); - // If a drive or argument was invalid, just exit - if (output.Contains("Invalid argument")) - { - return -1; - } - // If we get that the firmware is out of date, tell the user - else if (output.Contains("[ERROR] This drive isn't latest firmware. Please update.")) + // If we get the firmware message + if (output.Contains("[ERROR] This drive isn't latest firmware. Please update.")) { MessageBox.Show($"DiscImageCreator has reported that drive {Drive.Letter} is not updated to the most recent firmware. Please update the firmware for your drive and try again.", "Outdated Firmware", MessageBoxButton.OK, MessageBoxImage.Error); - return -1; - } - // Otherwise, if we find the maximum read speed as reported - else if (output.Contains("ReadSpeedMaximum:")) - { - int index = output.IndexOf("ReadSpeedMaximum:"); - string readspeed = Regex.Match(output.Substring(index), @"ReadSpeedMaximum: [0-9]+KB/sec \(([0-9]*)x\)").Groups[1].Value; - if (!Int32.TryParse(readspeed, out int speed) || speed <= 0) - { - return -1; - } - - return speed; + return false; } - return -1; + // Otherwise, we know the firmware's good + return true; } /// diff --git a/DICUI/Utilities/Validators.cs b/DICUI/Utilities/Validators.cs index 02e6dd56..7d6f3899 100644 --- a/DICUI/Utilities/Validators.cs +++ b/DICUI/Utilities/Validators.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Management; -using System.Runtime.InteropServices; using System.Threading.Tasks; using BurnOutSharp; using IMAPI2; @@ -513,169 +512,6 @@ namespace DICUI.Utilities return null; } - /// - /// Get the drive speed of the currently selected drive - /// - /// Speed of the drive converted from kbps - /// - /// DIC uses the SCSI_MODE_SENSE command to check this, so does QPXTool (a different one, but still) - /// See if SCSI_MODE_SENSE can be used here - /// Currently, the calculations get something that is technically accurate, but is different than the advertisised - /// capabilities of the drives (according to QPXTool) - /// TransferRate appears to be the CURRENT transfer rate, not the maximum... basically making that flag useless - /// - public static int GetDriveSpeed(Drive drive) - { - // If the current drive is not active or optical - if (drive.IsFloppy || !drive.MarkedActive) - return -1; - - ManagementObjectSearcher searcher = - new ManagementObjectSearcher("root\\CIMV2", - "SELECT * FROM Win32_CDROMDrive WHERE Id = '" + drive.Letter + ":\'"); - - var collection = searcher.Get(); - double? transferRate = -1; - foreach (ManagementObject queryObj in collection) - { - var obj = queryObj["TransferRate"]; - transferRate = (double?)queryObj["TransferRate"]; - } - - // Transfer Rates (kBps) - double cdTransfer = 153.6; - double dvdTransfer = 1385; - - double cdTransferTest = ((transferRate ?? -1)) / cdTransfer; - double dvdTransferTest = ((transferRate ?? -1)) / dvdTransfer; - - return 0; - } - - public unsafe static int GetDriveSpeedEx(Drive drive, MediaType? mediaType) - { - // If the current drive is not active or optical - if (drive.IsFloppy || !drive.MarkedActive) - return -1; - - // Get the DeviceID from the current drive letter - string deviceId = null; - try - { - ManagementObjectSearcher searcher = - new ManagementObjectSearcher("root\\CIMV2", - "SELECT * FROM Win32_CDROMDrive WHERE Id = '" + drive.Letter + ":\'"); - - var collection = searcher.Get(); - foreach (ManagementObject queryObj in collection) - { - deviceId = (string)queryObj["DeviceID"]; - } - } - catch - { - // We don't care what the error was - return -1; - } - - // If we got no valid device, we don't care and just return - if (deviceId == null) - { - return -1; - } - - // Get all relevant disc information - MsftDiscMaster2 discMaster = new MsftDiscMaster2(); - deviceId = deviceId.ToLower().Replace('\\', '#'); - string id = null; - foreach (var disc in discMaster) - { - if (disc.ToString().Contains(deviceId)) - { - id = disc.ToString(); - } - } - - // If we couldn't find the drive, we don't care and return - if (id == null) - { - return -1; - } - - // Now we initialize the recorder to get disc info - MsftDiscRecorder2 recorder = new MsftDiscRecorder2(); - recorder.InitializeDiscRecorder(id); - IDiscRecorder2Ex recorderEx = recorder as IDiscRecorder2Ex; - IMAPI_FEATURE_PAGE_TYPE ifpt = IMAPI_FEATURE_PAGE_TYPE.IMAPI_FEATURE_PAGE_TYPE_PROFILE_LIST; - switch(mediaType) - { - case MediaType.CD: - ifpt = IMAPI_FEATURE_PAGE_TYPE.IMAPI_FEATURE_PAGE_TYPE_CD_READ; - break; - case MediaType.DVD: - ifpt = IMAPI_FEATURE_PAGE_TYPE.IMAPI_FEATURE_PAGE_TYPE_DVD_READ; - break; - case MediaType.HDDVD: - ifpt = IMAPI_FEATURE_PAGE_TYPE.IMAPI_FEATURE_PAGE_TYPE_HD_DVD_READ; - break; - case MediaType.BluRay: - ifpt = IMAPI_FEATURE_PAGE_TYPE.IMAPI_FEATURE_PAGE_TYPE_BD_READ; - break; - } - - // If we couldn't determine the media type properly, we don't care and return - if (ifpt == IMAPI_FEATURE_PAGE_TYPE.IMAPI_FEATURE_PAGE_TYPE_PROFILE_LIST) - { - return -1; - } - - // Ones that haven't worked: - // recorderEx.GetAdapterDescriptor - // recorderEx.GetDeviceDescriptor - // recorderEx.GetDiscInformation - // recorderEx.GetTrackInformation - - // Now we get the requested feature page - // TODO: Figure out structure of returned data - IntPtr featureData = Marshal.AllocHGlobal(32 * sizeof(byte)); - recorderEx.GetFeaturePage( - ifpt, - (sbyte)0, - featureData, - out uint byteSize); - byte[] outFeatureArray = new byte[byteSize]; - Marshal.Copy(featureData, outFeatureArray, 0, (int)byteSize); - - // Now we get the requested mode data - // TODO: Figure out structure of returned data - IntPtr modeData = Marshal.AllocHGlobal(256 * sizeof(byte)); - recorderEx.GetModePage( - (IMAPI_MODE_PAGE_TYPE)0x2A, - IMAPI_MODE_PAGE_REQUEST_TYPE.IMAPI_MODE_PAGE_REQUEST_TYPE_CURRENT_VALUES, - modeData, - out uint modeDataSize); - byte[] outModeArray = new byte[modeDataSize]; - Marshal.Copy(modeData, outModeArray, 0, (int)modeDataSize); - - // Now we send the command to get sense data from the device - // TODO: This seems like the best option, but how is this data structured properly? - byte[] cdbArray = new byte[] { 0x5a, 0x0, 0x2a, 0x00, 0xff, 0x0 }; - byte[] senseBuffer = new byte[256]; - byte[] buffer = new byte[256]; - uint bufferSize = 256; - - recorderEx.SendCommandGetDataFromDevice( - ref cdbArray[0], - (uint)6, - senseBuffer, - (uint)60, - out buffer[0], - bufferSize, - out uint BufferFetched); - - return -1; - } - /// /// Verify that, given a system and a media type, they are correct ///