diff --git a/src/dev.c b/src/dev.c index 04fe943f..7ecd327e 100644 --- a/src/dev.c +++ b/src/dev.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Device detection and enumeration - * Copyright © 2014-2017 Pete Batard + * Copyright © 2014-2017 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -42,7 +42,8 @@ #include "drive.h" #include "dev.h" -extern StrArray DriveID, DriveLabel; +extern StrArray DriveID, DriveLabel, DriveHub; +extern uint32_t DrivePort[MAX_DRIVES]; extern BOOL enable_HDDs, use_fake_units, enable_vmdk, usb_debug, list_non_usb_removable_drives; /* @@ -123,6 +124,51 @@ out: return r; } +/* + * Cycle port (reset) the selected device + */ +BOOL ResetDevice(int index) +{ + static uint64_t LastReset = 0; + BOOL r = FALSE; + HANDLE handle = INVALID_HANDLE_VALUE; + DWORD size; + USB_CYCLE_PORT_PARAMS cycle_port; + + // Wait at least 10 secs between resets + if (_GetTickCount64() < LastReset + 10000ULL) { + uprintf("You must wait at least 10 seconds before trying to reset a device"); + return FALSE; + } + + if (DriveHub.String[index] == NULL) + return FALSE; + + LastReset = _GetTickCount64(); + + handle = CreateFileA(DriveHub.String[index], GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + if (handle == INVALID_HANDLE_VALUE) { + uprintf("Could not open %s: %s", DriveHub.String[index], WindowsErrorString()); + goto out; + } + + memset(&cycle_port, 0, sizeof(cycle_port)); + size = sizeof(cycle_port); + cycle_port.ConnectionIndex = DrivePort[index]; + uprintf("Cycling port %d (reset) on %s", DrivePort[index], DriveHub.String[index]); + // As per https://msdn.microsoft.com/en-us/library/windows/hardware/ff537340.aspx + // IOCTL_USB_HUB_CYCLE_PORT is not supported on Windows 7, Windows Vista, and Windows Server 2008 + if (!DeviceIoControl(handle, IOCTL_USB_HUB_CYCLE_PORT, &cycle_port, size, &cycle_port, size, &size, NULL)) { + uprintf(" Failed to cycle port: %s", WindowsErrorString()); + goto out; + } + r = TRUE; + +out: + safe_closehandle(handle); + return r; +} + static __inline BOOL IsVHD(const char* buffer) { int i; @@ -319,12 +365,13 @@ BOOL GetDevices(DWORD devnum) LONG maxwidth = 0; int s, score, drive_number, remove_drive; char drive_letters[27], *device_id, *devid_list = NULL, entry_msg[128]; - char *p, *label, *entry, buffer[MAX_PATH], str[MAX_PATH], *method_str; + char *p, *label, *entry, buffer[MAX_PATH], str[MAX_PATH], *method_str, *hub_path; usb_device_props props; IGNORE_RETVAL(ComboBox_ResetContent(hDeviceList)); StrArrayClear(&DriveID); StrArrayClear(&DriveLabel); + StrArrayClear(&DriveHub); StrArrayCreate(&dev_if_path, 128); // Add a dummy for string index zero, as this is what non matching hashes will point to StrArrayAdd(&dev_if_path, "", TRUE); @@ -452,6 +499,7 @@ BOOL GetDevices(DWORD devnum) memset(buffer, 0, sizeof(buffer)); memset(&props, 0, sizeof(props)); method_str = ""; + hub_path = NULL; if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_ENUMERATOR_NAME, &datatype, (LPBYTE)buffer, sizeof(buffer), &size)) { uprintf("SetupDiGetDeviceRegistryProperty (Enumerator Name) failed: %s\n", WindowsErrorString()); @@ -584,8 +632,10 @@ BOOL GetDevices(DWORD devnum) if ((uintptr_t)htab_devid.table[j].data > 0) { uuprintf(" Matched with Hub[%d]: '%s'", (uintptr_t)htab_devid.table[j].data, dev_if_path.String[(uintptr_t)htab_devid.table[j].data]); - if (GetUSBProperties(dev_if_path.String[(uintptr_t)htab_devid.table[j].data], device_id, &props)) + if (GetUSBProperties(dev_if_path.String[(uintptr_t)htab_devid.table[j].data], device_id, &props)) { method_str = ""; + hub_path = dev_if_path.String[(uintptr_t)htab_devid.table[j].data]; + } #ifdef FORCED_DEVICE props.vid = FORCED_VID; props.pid = FORCED_PID; @@ -769,6 +819,8 @@ BOOL GetDevices(DWORD devnum) // Must ensure that the combo box is UNSORTED for indexes to be the same StrArrayAdd(&DriveID, buffer, TRUE); StrArrayAdd(&DriveLabel, label, TRUE); + if ((hub_path != NULL) && (StrArrayAdd(&DriveHub, hub_path, TRUE) >= 0)) + DrivePort[DriveHub.Index - 1] = props.port; IGNORE_RETVAL(ComboBox_SetItemData(hDeviceList, ComboBox_AddStringU(hDeviceList, entry), drive_index)); maxwidth = max(maxwidth, GetEntryWidth(hDeviceList, entry)); diff --git a/src/dev.h b/src/dev.h index 2b1841a1..f1cf429d 100644 --- a/src/dev.h +++ b/src/dev.h @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Device listing - * Copyright © 2014-2016 Pete Batard + * Copyright © 2014-2016 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -106,9 +106,12 @@ DECLSPEC_IMPORT CONFIGRET WINAPI CM_Get_Sibling(PDEVINST pdnDevInst, DEVINST dnD // This last one is unknown from MinGW32 and needs to be fetched from the DLL PF_TYPE_DECL(WINAPI, CONFIGRET, CM_Get_DevNode_Registry_PropertyA, (DEVINST, ULONG, PULONG, PVOID, PULONG, ULONG)); +#define USB_HUB_CYCLE_PORT 273 #define USB_GET_NODE_CONNECTION_INFORMATION_EX 274 #define USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 279 +#define IOCTL_USB_HUB_CYCLE_PORT \ + CTL_CODE(FILE_DEVICE_USB, USB_HUB_CYCLE_PORT, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \ CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 \ @@ -172,6 +175,11 @@ typedef struct _USB_NODE_CONNECTION_INFORMATION_EX_V2 { USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS Flags; } USB_NODE_CONNECTION_INFORMATION_EX_V2, *PUSB_NODE_CONNECTION_INFORMATION_EX_V2; +typedef struct { + ULONG ConnectionIndex; + ULONG StatusReturned; +} USB_CYCLE_PORT_PARAMS; + #pragma pack(pop) const GUID _GUID_DEVINTERFACE_DISK = diff --git a/src/rufus.c b/src/rufus.c index 903daae9..ed58ee8c 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -114,7 +114,8 @@ uint16_t rufus_version[3], embedded_sl_version[2]; char embedded_sl_version_str[2][12] = { "?.??", "?.??" }; char embedded_sl_version_ext[2][32]; RUFUS_UPDATE update = { {0,0,0}, {0,0}, NULL, NULL}; -StrArray DriveID, DriveLabel, BlockingProcess; +StrArray DriveID, DriveLabel, DriveHub, BlockingProcess; +uint32_t DrivePort[MAX_DRIVES]; extern char* szStatusMessage; static HANDLE format_thid = NULL, dialog_handle = NULL; @@ -1828,9 +1829,10 @@ static void InitDialog(HWND hDlg) } IGNORE_RETVAL(ComboBox_SetCurSel(hDiskID, 0)); - // Create the string array + // Create the string arrays StrArrayCreate(&DriveID, MAX_DRIVES); StrArrayCreate(&DriveLabel, MAX_DRIVES); + StrArrayCreate(&DriveHub, MAX_DRIVES); StrArrayCreate(&BlockingProcess, 16); // Set various checkboxes CheckDlgButton(hDlg, IDC_QUICKFORMAT, BST_CHECKED); @@ -2351,6 +2353,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA PostQuitMessage(0); StrArrayDestroy(&DriveID); StrArrayDestroy(&DriveLabel); + StrArrayDestroy(&DriveHub); StrArrayDestroy(&BlockingProcess); DestroyAllTooltips(); DestroyWindow(hLogDlg); @@ -3351,7 +3354,7 @@ relaunch: // Do our own event processing and process "magic" commands while(GetMessage(&msg, NULL, 0, 0)) { - // ** ***** **** ** ******** * + // ** ***** **** ** ********** // .,ABCDEFGHIJKLMNOPQRSTUVWXYZ // Ctrl-A => Select the log data @@ -3359,6 +3362,7 @@ relaunch: (msg.message == WM_KEYDOWN) && (msg.wParam == 'A') ) { // Might also need ES_NOHIDESEL property if you want to select when not active Edit_SetSel(hLog, 0, -1); + continue; } // Alt-. => Enable USB enumeration debug if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == VK_OEM_PERIOD)) { @@ -3385,12 +3389,12 @@ relaunch: PrintStatusTimeout(lmprintf(MSG_256), detect_fakes); continue; } - // Alt C => Force the update check to be successful - // This will set the reported current version of Rufus to 0.0.0.0 when performing an update - // check, so that it always succeeds. This is useful for translators. + // Alt-C => Cycle USB port for currently selected device if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'C')) { - force_update = !force_update; - PrintStatusTimeout(lmprintf(MSG_259), force_update); + int index = ComboBox_GetCurSel(hDeviceList); + if (index < 0) + break; + ResetDevice(index); continue; } // Alt-D => Delete the NoDriveTypeAutorun key on exit (useful if the app crashed) @@ -3473,7 +3477,6 @@ relaunch: PrintStatusTimeout(lmprintf(MSG_290), !disable_file_indexing); continue; } - // Alt-R => Remove all the registry keys that may have been created by Rufus if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'R')) { PrintStatus(2000, DeleteRegistryKey(REGKEY_HKCU, COMPANY_NAME "\\" APPLICATION_NAME)?MSG_248:MSG_249); @@ -3525,11 +3528,20 @@ relaunch: SHDeleteDirectoryExU(NULL, tmp_path, FOF_SILENT | FOF_NOERRORUI | FOF_NOCONFIRMATION); continue; } + // Alt Y => Force the update check to be successful + // This will set the reported current version of Rufus to 0.0.0.0 when performing an update + // check, so that it always succeeds. This is useful for translators. + if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'Y')) { + force_update = !force_update; + PrintStatusTimeout(lmprintf(MSG_259), force_update); + continue; + } // Alt-Z => Zero the drive if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'Z')) { zero_drive = TRUE; // Simulate a button click for Start PostMessage(hDlg, WM_COMMAND, (WPARAM)IDC_START, 0); + continue; } // Hazardous cheat modes require Ctrl + Alt diff --git a/src/rufus.h b/src/rufus.h index e2a6195d..ab1f7223 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -369,11 +369,11 @@ enum WindowsVersion { WINDOWS_UNDEFINED = -1, WINDOWS_UNSUPPORTED = 0, WINDOWS_XP = 0x51, - WINDOWS_2003 = 0x52, // Also XP x64 - WINDOWS_VISTA = 0x60, - WINDOWS_7 = 0x61, - WINDOWS_8 = 0x62, - WINDOWS_8_1 = 0x63, + WINDOWS_2003 = 0x52, // Also XP_64 + WINDOWS_VISTA = 0x60, // Also 2008 + WINDOWS_7 = 0x61, // Also 2008_R2 + WINDOWS_8 = 0x62, // Also 2012 + WINDOWS_8_1 = 0x63, // Also 2012_R2 WINDOWS_10_PREVIEW1 = 0x64, WINDOWS_10 = 0xA0, WINDOWS_MAX @@ -460,6 +460,7 @@ extern DWORD GetResourceSize(HMODULE module, char* name, char* type, const char* extern DWORD RunCommand(const char* cmdline, const char* dir, BOOL log); extern BOOL CompareGUID(const GUID *guid1, const GUID *guid2); extern BOOL GetDevices(DWORD devnum); +extern BOOL ResetDevice(int index); extern BOOL GetOpticalMedia(IMG_SAVE* img_save); extern BOOL SetLGP(BOOL bRestore, BOOL* bExistingKey, const char* szPath, const char* szPolicy, DWORD dwValue); extern LONG GetEntryWidth(HWND hDropDown, const char* entry); diff --git a/src/rufus.rc b/src/rufus.rc index c97f06d1..132dcb37 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.18.1200" +CAPTION "Rufus 2.18.1201" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -366,8 +366,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,18,1200,0 - PRODUCTVERSION 2,18,1200,0 + FILEVERSION 2,18,1201,0 + PRODUCTVERSION 2,18,1201,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -384,13 +384,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.18.1200" + VALUE "FileVersion", "2.18.1201" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2017 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.18.1200" + VALUE "ProductVersion", "2.18.1201" END END BLOCK "VarFileInfo" diff --git a/src/stdfn.c b/src/stdfn.c index 90ef4b8c..73329c5c 100644 --- a/src/stdfn.c +++ b/src/stdfn.c @@ -284,20 +284,20 @@ void GetWindowsVersion(void) switch (nWindowsVersion) { case 0x51: w = "XP"; break; - case 0x52: w = (!GetSystemMetrics(89)?"2003":"2003_R2"); + case 0x52: w = (!GetSystemMetrics(89)?"Server 2003":"Server 2003_R2"); break; - case 0x60: w = (ws?"Vista":"2008"); + case 0x60: w = (ws?"Vista":"Server 2008"); break; - case 0x61: w = (ws?"7":"2008_R2"); + case 0x61: w = (ws?"7":"Server 2008_R2"); break; - case 0x62: w = (ws?"8":"2012"); + case 0x62: w = (ws?"8":"Server 2012"); break; - case 0x63: w = (ws?"8.1":"2012_R2"); + case 0x63: w = (ws?"8.1":"Server 2012_R2"); break; case 0x64: w = (ws?"10 (Preview 1)":"Server 10 (Preview 1)"); break; // Starting with Windows 10 Preview 2, the major is the same as the public-facing version - case 0xA0: w = (ws?"10":"Server 10"); + case 0xA0: w = (ws?"10":"Server 2016"); break; default: if (nWindowsVersion < 0x51)