diff --git a/src/process.c b/src/process.c index a20dc191..33c3a851 100644 --- a/src/process.c +++ b/src/process.c @@ -503,7 +503,8 @@ static DWORD WINAPI SearchProcessThread(LPVOID param) // Still nothing? Try GetProcessImageFileName. Note that GetProcessImageFileName uses // '\Device\Harddisk#\Partition#\' instead drive letters if (!bGotExePath) { - if (bGotExePath = (GetProcessImageFileNameW(processHandle, wexe_path, MAX_PATH) != 0)) + bGotExePath = (GetProcessImageFileNameW(processHandle, wexe_path, MAX_PATH) != 0); + if (bGotExePath) wchar_to_utf8_no_alloc(wexe_path, exe_path, sizeof(exe_path)); } @@ -524,7 +525,7 @@ out: PhFree(buffer); PhFree(handles); PhDestroyHeap(); - ExitThread((DWORD)access_mask); + ExitThread(0); } /** @@ -542,7 +543,7 @@ out: BYTE SearchProcess(char* HandleName, DWORD dwTimeOut, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL bQuiet) { HANDLE handle; - DWORD dw = 0; + DWORD res = 0; _HandleName = HandleName; _bPartialMatch = bPartialMatch; @@ -552,16 +553,17 @@ BYTE SearchProcess(char* HandleName, DWORD dwTimeOut, BOOL bPartialMatch, BOOL b handle = CreateThread(NULL, 0, SearchProcessThread, NULL, 0, NULL); if (handle == NULL) { - uprintf("Unable to create process search thread"); + uprintf("Warning: Unable to create conflicting process search thread"); return 0x00; } - dw = WaitForSingleObject(handle, dwTimeOut); - if (dw == WAIT_TIMEOUT) { + res = WaitForSingleObjectWithMessages(handle, dwTimeOut); + if (res == WAIT_TIMEOUT) { // Timeout - kill the thread TerminateThread(handle, 0); - uprintf("Warning: Killed process search thread"); - } else if (dw != WAIT_OBJECT_0) { - uprintf("Failed to wait for process search thread: %s", WindowsErrorString()); + uprintf("Warning: Conflicting process search failed to complete due to timeout"); + } else if (res != WAIT_OBJECT_0) { + TerminateThread(handle, 0); + uprintf("Warning: Failed to wait for conflicting process search thread: %s", WindowsErrorString()); } return access_mask; } diff --git a/src/rufus.c b/src/rufus.c index 421e6d31..f9760d74 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -1159,7 +1159,7 @@ static void ToggleAdvanced(BOOL enable) point.y = (rect.bottom - rect.top) + (int)(fScale*dialog_shift); SetWindowPos(hLog, NULL, 0, 0, point.x, point.y, SWP_NOZORDER); // Don't forget to scroll the edit to the bottom after resize - SendMessage(hLog, EM_LINESCROLL, 0, SendMessage(hLog, EM_GETLINECOUNT, 0, 0)); + Edit_Scroll(hLog, 0, Edit_GetLineCount(hLog)); // Hide or show the various advanced options toggle = enable?SW_SHOW:SW_HIDE; @@ -1249,7 +1249,7 @@ static void ToggleToGo(void) point.y = (rect.bottom - rect.top) + (int)(fScale*dialog_shift); SetWindowPos(hLog, NULL, 0, 0, point.x, point.y, SWP_NOZORDER); // Don't forget to scroll the edit to the bottom after resize - SendMessage(hLog, EM_LINESCROLL, 0, SendMessage(hLog, EM_GETLINECOUNT, 0, 0)); + Edit_Scroll(hLog, 0, Edit_GetLineCount(hLog)); // Hide or show the various advanced options toggle = togo_mode?SW_SHOW:SW_HIDE; @@ -2155,7 +2155,8 @@ static void SaveISO(void) // Check for conflicting processes accessing the drive, and if any, // ask the user whether they want to proceed. -static BOOL CheckDriveAccess(void) +// Parameter is the maximum amount of time we allow for this call to execute (in ms) +static BOOL CheckDriveAccess(DWORD dwTimeOut) { uint32_t i, j; BOOL bProceed = TRUE; @@ -2163,16 +2164,22 @@ static BOOL CheckDriveAccess(void) char *PhysicalPath, DevPath[MAX_PATH]; char drive_letter[27], drive_name[] = "?:"; char *message, title[128]; + DWORD cur_time, end_time = GetTickCount() + dwTimeOut; // Get the current selected device DWORD DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, ComboBox_GetCurSel(hDeviceList)); if ((DeviceNum < 0x80) || (DeviceNum == (DWORD)-1)) return FALSE; + // TODO: "Checking for conflicting processes..." would be better but + // but "Requesting disk access..." will have to do for now. + PrintInfo(0, MSG_225); + // Search for any blocking processes against the physical drive PhysicalPath = GetPhysicalName(DeviceNum); QueryDosDeviceA(&PhysicalPath[4], DevPath, sizeof(DevPath)); - access_mask = SearchProcess(DevPath, 2000, TRUE, TRUE, TRUE); + access_mask = SearchProcess(DevPath, dwTimeOut, TRUE, TRUE, TRUE); + CHECK_FOR_USER_CANCEL; if (access_mask != 0) { bProceed = FALSE; uprintf("Found potentially blocking process(es) against %s:", &PhysicalPath[4]); @@ -2187,7 +2194,11 @@ static BOOL CheckDriveAccess(void) drive_name[0] = drive_letter[i]; if (QueryDosDeviceA(drive_name, DevPath, sizeof(DevPath)) != 0) { StrArrayClear(&BlockingProcess); - access_mask = SearchProcess(DevPath, 2000, TRUE, TRUE, TRUE); + cur_time = GetTickCount(); + if (cur_time >= end_time) + break; + access_mask = SearchProcess(DevPath, end_time - cur_time, TRUE, TRUE, TRUE); + CHECK_FOR_USER_CANCEL; // Ignore if all we have is read-only if ((access_mask & 0x06) || (access_mask == 0x80)) { bProceed = FALSE; @@ -2209,7 +2220,11 @@ static BOOL CheckDriveAccess(void) } } + PrintInfo(0, MSG_210); return bProceed; +out: + PrintInfo(0, MSG_210); + return FALSE; } #ifdef RUFUS_TEST @@ -2219,7 +2234,6 @@ static BOOL CheckDriveAccess(void) /* * Main dialog callback */ -#define PROCESS_QUEUED_EVENTS if (queued_hotplug_event) SendMessage(hDlg, UM_MEDIA_CHANGE, 0, 0) static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { static DWORD DeviceNum = 0; @@ -2248,7 +2262,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA case WM_COMMAND: #ifdef RUFUS_TEST if (LOWORD(wParam) == IDC_TEST) { - uprintf("Proceed = %s", CheckDriveAccess()?"True":"False"); + uprintf("Proceed = %s", CheckDriveAccess(2000)?"True":"False"); // char* choices[] = { "Choice 1", "Choice 2", "Choice 3" }; // SelectionDyn("Test Choice", "Unused", choices, ARRAYSIZE(choices)); break; @@ -2294,6 +2308,11 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA } no_confirmation_on_cancel = FALSE; return (INT_PTR)TRUE; + } else if (format_op_in_progress) { + // User might be trying to cancel during preliminary checks + FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED; + PrintInfo(0, MSG_201); + return (INT_PTR)TRUE; } if ((pfSHChangeNotifyDeregister != NULL) && (ulRegister != 0)) pfSHChangeNotifyDeregister(ulRegister); @@ -2565,7 +2584,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA } } - if (!CheckDriveAccess()) + if (!CheckDriveAccess(2000)) goto aborted_start; GetWindowTextU(hDeviceList, tmp, ARRAYSIZE(tmp)); @@ -2602,7 +2621,9 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA format_op_in_progress = FALSE; EnableControls(TRUE); zero_drive = FALSE; - PROCESS_QUEUED_EVENTS; + if (queued_hotplug_event) + SendMessage(hDlg, UM_MEDIA_CHANGE, 0, 0); + EnableWindow(GetDlgItem(hDlg, IDCANCEL), TRUE); break; case IDC_HASH: if ((format_thid == NULL) && (image_path != NULL)) { @@ -3305,7 +3326,7 @@ relaunch: if ( (IsWindowVisible(hLogDlg)) && (GetKeyState(VK_CONTROL) & 0x8000) && (msg.message == WM_KEYDOWN) && (msg.wParam == 'A') ) { // Might also need ES_NOHIDESEL property if you want to select when not active - SendMessage(hLog, EM_SETSEL, 0, -1); + Edit_SetSel(hLog, 0, -1); } // Alt-. => Enable USB enumeration debug if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == VK_OEM_PERIOD)) { diff --git a/src/rufus.h b/src/rufus.h index 64873f1d..bbbae95c 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -500,6 +500,7 @@ extern void ClrFormatPromptHook(void); extern BYTE SearchProcess(char* HandleName, DWORD dwTimeout, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL bQuiet); extern BOOL EnablePrivileges(void); extern void FlashTaskbar(HANDLE handle); +extern DWORD WaitForSingleObjectWithMessages(HANDLE hHandle, DWORD dwMilliseconds); DWORD WINAPI FormatThread(void* param); DWORD WINAPI SaveImageThread(void* param); diff --git a/src/rufus.rc b/src/rufus.rc index b6df942d..17674040 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.16.1150" +CAPTION "Rufus 2.16.1151" 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,16,1150,0 - PRODUCTVERSION 2,16,1150,0 + FILEVERSION 2,16,1151,0 + PRODUCTVERSION 2,16,1151,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.16.1150" + VALUE "FileVersion", "2.16.1151" 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.16.1150" + VALUE "ProductVersion", "2.16.1151" END END BLOCK "VarFileInfo" diff --git a/src/stdio.c b/src/stdio.c index 629f26f4..c3975f36 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -42,7 +42,6 @@ size_t ubuffer_pos = 0; char ubuffer[UBUFFER_SIZE]; // Buffer for ubpushf() messages we don't log right away #ifdef RUFUS_LOGGING -#define Edit_ReplaceSelW(hCtrl, wstr) ((void)SendMessageW(hCtrl, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)wstr)) void _uprintf(const char *format, ...) { static char buf[4096]; @@ -71,10 +70,10 @@ void _uprintf(const char *format, ...) if ((hLog != NULL) && (hLog != INVALID_HANDLE_VALUE)) { // Send output to our log Window Edit_SetSel(hLog, MAX_LOG_SIZE, MAX_LOG_SIZE); - Edit_ReplaceSelW(hLog, wbuf); + Edit_ReplaceSel(hLog, wbuf); // Make sure the message scrolls into view // (Or see code commented in LogProc:WM_SHOWWINDOW for a less forceful scroll) - SendMessage(hLog, EM_LINESCROLL, 0, SendMessage(hLog, EM_GETLINECOUNT, 0, 0)); + Edit_Scroll(hLog, 0, Edit_GetLineCount(hLog)); } free(wbuf); } @@ -360,3 +359,38 @@ BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWr SetLastError(ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT); return FALSE; } + +// A WaitForSingleObject() equivalent that doesn't block Windows messages +// This is needed, for instance, if you are waiting for a thread that may issue uprintf's +DWORD WaitForSingleObjectWithMessages(HANDLE hHandle, DWORD dwMilliseconds) +{ + DWORD res, dwCurTime, dwEndTime = GetTickCount() + dwMilliseconds; + MSG msg; + + do { + // Read all of the messages in this next loop, removing each message as we read it. + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + if ((msg.message == WM_QUIT) || (msg.message == WM_CLOSE)) { + SetLastError(ERROR_CANCELLED); + return WAIT_FAILED; + } else { + DispatchMessage(&msg); + } + } + + // Wait for any message sent or posted to this queue or for the handle to signaled. + res = MsgWaitForMultipleObjects(1, &hHandle, FALSE, dwMilliseconds, QS_ALLINPUT); + + if (dwMilliseconds != INFINITE) { + dwCurTime = GetTickCount(); + // Account for the case where we may reach the timeout condition while + // processing timestamps + if (dwCurTime < dwEndTime) + dwMilliseconds = dwEndTime - dwCurTime; + else + res = WAIT_TIMEOUT; + } + } while (res == (WAIT_OBJECT_0 + 1)); + + return res; +}