mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[process] improve the search for conflicting processes check
* Add a WaitForSingleObjectWithMessages() call so that we can process Windows messages while waiting on events (prevents lockup while issuing log messages) * Limit the total duration of CheckDriveAccess() to 2 seconds * Allow for user cancellation * Also update code to use the Edit_####() predefined macros for Edit controls instead of EM_### messages
This commit is contained in:
parent
5e609f022f
commit
369a392af0
5 changed files with 85 additions and 27 deletions
|
@ -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;
|
||||
}
|
||||
|
|
41
src/rufus.c
41
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)) {
|
||||
|
|
|
@ -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);
|
||||
|
|
10
src/rufus.rc
10
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"
|
||||
|
|
40
src/stdio.c
40
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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue