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
 | 		// Still nothing? Try GetProcessImageFileName. Note that GetProcessImageFileName uses
 | ||||||
| 		// '\Device\Harddisk#\Partition#\' instead drive letters
 | 		// '\Device\Harddisk#\Partition#\' instead drive letters
 | ||||||
| 		if (!bGotExePath) { | 		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)); | 				wchar_to_utf8_no_alloc(wexe_path, exe_path, sizeof(exe_path)); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -524,7 +525,7 @@ out: | ||||||
| 	PhFree(buffer); | 	PhFree(buffer); | ||||||
| 	PhFree(handles); | 	PhFree(handles); | ||||||
| 	PhDestroyHeap(); | 	PhDestroyHeap(); | ||||||
| 	ExitThread((DWORD)access_mask); | 	ExitThread(0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -542,7 +543,7 @@ out: | ||||||
| BYTE SearchProcess(char* HandleName, DWORD dwTimeOut, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL bQuiet) | BYTE SearchProcess(char* HandleName, DWORD dwTimeOut, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL bQuiet) | ||||||
| { | { | ||||||
| 	HANDLE handle; | 	HANDLE handle; | ||||||
| 	DWORD dw = 0; | 	DWORD res = 0; | ||||||
| 
 | 
 | ||||||
| 	_HandleName = HandleName; | 	_HandleName = HandleName; | ||||||
| 	_bPartialMatch = bPartialMatch; | 	_bPartialMatch = bPartialMatch; | ||||||
|  | @ -552,16 +553,17 @@ BYTE SearchProcess(char* HandleName, DWORD dwTimeOut, BOOL bPartialMatch, BOOL b | ||||||
| 
 | 
 | ||||||
| 	handle = CreateThread(NULL, 0, SearchProcessThread, NULL, 0, NULL); | 	handle = CreateThread(NULL, 0, SearchProcessThread, NULL, 0, NULL); | ||||||
| 	if (handle == NULL) { | 	if (handle == NULL) { | ||||||
| 		uprintf("Unable to create process search thread"); | 		uprintf("Warning: Unable to create conflicting process search thread"); | ||||||
| 		return 0x00; | 		return 0x00; | ||||||
| 	} | 	} | ||||||
| 	dw = WaitForSingleObject(handle, dwTimeOut); | 	res = WaitForSingleObjectWithMessages(handle, dwTimeOut); | ||||||
| 	if (dw == WAIT_TIMEOUT) { | 	if (res == WAIT_TIMEOUT) { | ||||||
| 		// Timeout - kill the thread
 | 		// Timeout - kill the thread
 | ||||||
| 		TerminateThread(handle, 0); | 		TerminateThread(handle, 0); | ||||||
| 		uprintf("Warning: Killed process search thread"); | 		uprintf("Warning: Conflicting process search failed to complete due to timeout"); | ||||||
| 	} else if (dw != WAIT_OBJECT_0) { | 	} else if (res != WAIT_OBJECT_0) { | ||||||
| 		uprintf("Failed to wait for process search thread: %s", WindowsErrorString()); | 		TerminateThread(handle, 0); | ||||||
|  | 		uprintf("Warning: Failed to wait for conflicting process search thread: %s", WindowsErrorString()); | ||||||
| 	} | 	} | ||||||
| 	return access_mask; | 	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); | 	point.y = (rect.bottom - rect.top) + (int)(fScale*dialog_shift); | ||||||
| 	SetWindowPos(hLog, NULL, 0, 0, point.x, point.y, SWP_NOZORDER); | 	SetWindowPos(hLog, NULL, 0, 0, point.x, point.y, SWP_NOZORDER); | ||||||
| 	// Don't forget to scroll the edit to the bottom after resize
 | 	// 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
 | 	// Hide or show the various advanced options
 | ||||||
| 	toggle = enable?SW_SHOW:SW_HIDE; | 	toggle = enable?SW_SHOW:SW_HIDE; | ||||||
|  | @ -1249,7 +1249,7 @@ static void ToggleToGo(void) | ||||||
| 	point.y = (rect.bottom - rect.top) + (int)(fScale*dialog_shift); | 	point.y = (rect.bottom - rect.top) + (int)(fScale*dialog_shift); | ||||||
| 	SetWindowPos(hLog, NULL, 0, 0, point.x, point.y, SWP_NOZORDER); | 	SetWindowPos(hLog, NULL, 0, 0, point.x, point.y, SWP_NOZORDER); | ||||||
| 	// Don't forget to scroll the edit to the bottom after resize
 | 	// 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
 | 	// Hide or show the various advanced options
 | ||||||
| 	toggle = togo_mode?SW_SHOW:SW_HIDE; | 	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,
 | // Check for conflicting processes accessing the drive, and if any,
 | ||||||
| // ask the user whether they want to proceed.
 | // 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; | 	uint32_t i, j; | ||||||
| 	BOOL bProceed = TRUE; | 	BOOL bProceed = TRUE; | ||||||
|  | @ -2163,16 +2164,22 @@ static BOOL CheckDriveAccess(void) | ||||||
| 	char *PhysicalPath, DevPath[MAX_PATH]; | 	char *PhysicalPath, DevPath[MAX_PATH]; | ||||||
| 	char drive_letter[27], drive_name[] = "?:"; | 	char drive_letter[27], drive_name[] = "?:"; | ||||||
| 	char *message, title[128]; | 	char *message, title[128]; | ||||||
|  | 	DWORD cur_time, end_time = GetTickCount() + dwTimeOut; | ||||||
| 
 | 
 | ||||||
| 	// Get the current selected device
 | 	// Get the current selected device
 | ||||||
| 	DWORD DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, ComboBox_GetCurSel(hDeviceList)); | 	DWORD DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, ComboBox_GetCurSel(hDeviceList)); | ||||||
| 	if ((DeviceNum < 0x80) || (DeviceNum == (DWORD)-1)) | 	if ((DeviceNum < 0x80) || (DeviceNum == (DWORD)-1)) | ||||||
| 		return FALSE; | 		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
 | 	// Search for any blocking processes against the physical drive
 | ||||||
| 	PhysicalPath = GetPhysicalName(DeviceNum); | 	PhysicalPath = GetPhysicalName(DeviceNum); | ||||||
| 	QueryDosDeviceA(&PhysicalPath[4], DevPath, sizeof(DevPath)); | 	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) { | 	if (access_mask != 0) { | ||||||
| 		bProceed = FALSE; | 		bProceed = FALSE; | ||||||
| 		uprintf("Found potentially blocking process(es) against %s:", &PhysicalPath[4]); | 		uprintf("Found potentially blocking process(es) against %s:", &PhysicalPath[4]); | ||||||
|  | @ -2187,7 +2194,11 @@ static BOOL CheckDriveAccess(void) | ||||||
| 		drive_name[0] = drive_letter[i]; | 		drive_name[0] = drive_letter[i]; | ||||||
| 		if (QueryDosDeviceA(drive_name, DevPath, sizeof(DevPath)) != 0) { | 		if (QueryDosDeviceA(drive_name, DevPath, sizeof(DevPath)) != 0) { | ||||||
| 			StrArrayClear(&BlockingProcess); | 			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
 | 			// Ignore if all we have is read-only
 | ||||||
| 			if ((access_mask & 0x06) || (access_mask == 0x80)) { | 			if ((access_mask & 0x06) || (access_mask == 0x80)) { | ||||||
| 				bProceed = FALSE; | 				bProceed = FALSE; | ||||||
|  | @ -2209,7 +2220,11 @@ static BOOL CheckDriveAccess(void) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	PrintInfo(0, MSG_210); | ||||||
| 	return bProceed; | 	return bProceed; | ||||||
|  | out: | ||||||
|  | 	PrintInfo(0, MSG_210); | ||||||
|  | 	return FALSE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifdef RUFUS_TEST | #ifdef RUFUS_TEST | ||||||
|  | @ -2219,7 +2234,6 @@ static BOOL CheckDriveAccess(void) | ||||||
| /*
 | /*
 | ||||||
|  * Main dialog callback |  * 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 INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) | ||||||
| { | { | ||||||
| 	static DWORD DeviceNum = 0; | 	static DWORD DeviceNum = 0; | ||||||
|  | @ -2248,7 +2262,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA | ||||||
| 	case WM_COMMAND: | 	case WM_COMMAND: | ||||||
| #ifdef RUFUS_TEST | #ifdef RUFUS_TEST | ||||||
| 		if (LOWORD(wParam) == IDC_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" };
 | //			char* choices[] = { "Choice 1", "Choice 2", "Choice 3" };
 | ||||||
| //			SelectionDyn("Test Choice", "Unused", choices, ARRAYSIZE(choices));
 | //			SelectionDyn("Test Choice", "Unused", choices, ARRAYSIZE(choices));
 | ||||||
| 			break; | 			break; | ||||||
|  | @ -2294,6 +2308,11 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA | ||||||
| 				} | 				} | ||||||
| 				no_confirmation_on_cancel = FALSE; | 				no_confirmation_on_cancel = FALSE; | ||||||
| 				return (INT_PTR)TRUE; | 				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)) | 			if ((pfSHChangeNotifyDeregister != NULL) && (ulRegister != 0)) | ||||||
| 				pfSHChangeNotifyDeregister(ulRegister); | 				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; | 					goto aborted_start; | ||||||
| 
 | 
 | ||||||
| 				GetWindowTextU(hDeviceList, tmp, ARRAYSIZE(tmp)); | 				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; | 			format_op_in_progress = FALSE; | ||||||
| 			EnableControls(TRUE); | 			EnableControls(TRUE); | ||||||
| 			zero_drive = FALSE; | 			zero_drive = FALSE; | ||||||
| 			PROCESS_QUEUED_EVENTS; | 			if (queued_hotplug_event) | ||||||
|  | 				SendMessage(hDlg, UM_MEDIA_CHANGE, 0, 0); | ||||||
|  | 			EnableWindow(GetDlgItem(hDlg, IDCANCEL), TRUE); | ||||||
| 			break; | 			break; | ||||||
| 		case IDC_HASH: | 		case IDC_HASH: | ||||||
| 			if ((format_thid == NULL) && (image_path != NULL)) { | 			if ((format_thid == NULL) && (image_path != NULL)) { | ||||||
|  | @ -3305,7 +3326,7 @@ relaunch: | ||||||
| 		if ( (IsWindowVisible(hLogDlg)) && (GetKeyState(VK_CONTROL) & 0x8000) && | 		if ( (IsWindowVisible(hLogDlg)) && (GetKeyState(VK_CONTROL) & 0x8000) && | ||||||
| 			(msg.message == WM_KEYDOWN) && (msg.wParam == 'A') ) { | 			(msg.message == WM_KEYDOWN) && (msg.wParam == 'A') ) { | ||||||
| 			// Might also need ES_NOHIDESEL property if you want to select when not active
 | 			// 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
 | 		// Alt-. => Enable USB enumeration debug
 | ||||||
| 		if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == VK_OEM_PERIOD)) { | 		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 BYTE SearchProcess(char* HandleName, DWORD dwTimeout, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL bQuiet); | ||||||
| extern BOOL EnablePrivileges(void); | extern BOOL EnablePrivileges(void); | ||||||
| extern void FlashTaskbar(HANDLE handle); | extern void FlashTaskbar(HANDLE handle); | ||||||
|  | extern DWORD WaitForSingleObjectWithMessages(HANDLE hHandle, DWORD dwMilliseconds); | ||||||
| 
 | 
 | ||||||
| DWORD WINAPI FormatThread(void* param); | DWORD WINAPI FormatThread(void* param); | ||||||
| DWORD WINAPI SaveImageThread(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 | IDD_DIALOG DIALOGEX 12, 12, 242, 376 | ||||||
| STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | ||||||
| EXSTYLE WS_EX_ACCEPTFILES | EXSTYLE WS_EX_ACCEPTFILES | ||||||
| CAPTION "Rufus 2.16.1150" | CAPTION "Rufus 2.16.1151" | ||||||
| FONT 8, "Segoe UI Symbol", 400, 0, 0x0 | FONT 8, "Segoe UI Symbol", 400, 0, 0x0 | ||||||
| BEGIN | BEGIN | ||||||
|     LTEXT           "Device",IDS_DEVICE_TXT,9,6,200,8 |     LTEXT           "Device",IDS_DEVICE_TXT,9,6,200,8 | ||||||
|  | @ -366,8 +366,8 @@ END | ||||||
| // | // | ||||||
| 
 | 
 | ||||||
| VS_VERSION_INFO VERSIONINFO | VS_VERSION_INFO VERSIONINFO | ||||||
|  FILEVERSION 2,16,1150,0 |  FILEVERSION 2,16,1151,0 | ||||||
|  PRODUCTVERSION 2,16,1150,0 |  PRODUCTVERSION 2,16,1151,0 | ||||||
|  FILEFLAGSMASK 0x3fL |  FILEFLAGSMASK 0x3fL | ||||||
| #ifdef _DEBUG | #ifdef _DEBUG | ||||||
|  FILEFLAGS 0x1L |  FILEFLAGS 0x1L | ||||||
|  | @ -384,13 +384,13 @@ BEGIN | ||||||
|         BEGIN |         BEGIN | ||||||
|             VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" |             VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" | ||||||
|             VALUE "FileDescription", "Rufus" |             VALUE "FileDescription", "Rufus" | ||||||
|             VALUE "FileVersion", "2.16.1150" |             VALUE "FileVersion", "2.16.1151" | ||||||
|             VALUE "InternalName", "Rufus" |             VALUE "InternalName", "Rufus" | ||||||
|             VALUE "LegalCopyright", "© 2011-2017 Pete Batard (GPL v3)" |             VALUE "LegalCopyright", "© 2011-2017 Pete Batard (GPL v3)" | ||||||
|             VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" |             VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" | ||||||
|             VALUE "OriginalFilename", "rufus.exe" |             VALUE "OriginalFilename", "rufus.exe" | ||||||
|             VALUE "ProductName", "Rufus" |             VALUE "ProductName", "Rufus" | ||||||
|             VALUE "ProductVersion", "2.16.1150" |             VALUE "ProductVersion", "2.16.1151" | ||||||
|         END |         END | ||||||
|     END |     END | ||||||
|     BLOCK "VarFileInfo" |     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
 | char ubuffer[UBUFFER_SIZE];	// Buffer for ubpushf() messages we don't log right away
 | ||||||
| 
 | 
 | ||||||
| #ifdef RUFUS_LOGGING | #ifdef RUFUS_LOGGING | ||||||
| #define Edit_ReplaceSelW(hCtrl, wstr) ((void)SendMessageW(hCtrl, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)wstr)) |  | ||||||
| void _uprintf(const char *format, ...) | void _uprintf(const char *format, ...) | ||||||
| { | { | ||||||
| 	static char buf[4096]; | 	static char buf[4096]; | ||||||
|  | @ -71,10 +70,10 @@ void _uprintf(const char *format, ...) | ||||||
| 	if ((hLog != NULL) && (hLog != INVALID_HANDLE_VALUE)) { | 	if ((hLog != NULL) && (hLog != INVALID_HANDLE_VALUE)) { | ||||||
| 		// Send output to our log Window
 | 		// Send output to our log Window
 | ||||||
| 		Edit_SetSel(hLog, MAX_LOG_SIZE, MAX_LOG_SIZE); | 		Edit_SetSel(hLog, MAX_LOG_SIZE, MAX_LOG_SIZE); | ||||||
| 		Edit_ReplaceSelW(hLog, wbuf); | 		Edit_ReplaceSel(hLog, wbuf); | ||||||
| 		// Make sure the message scrolls into view
 | 		// Make sure the message scrolls into view
 | ||||||
| 		// (Or see code commented in LogProc:WM_SHOWWINDOW for a less forceful scroll)
 | 		// (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); | 	free(wbuf); | ||||||
| } | } | ||||||
|  | @ -360,3 +359,38 @@ BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWr | ||||||
| 		SetLastError(ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT); | 		SetLastError(ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT); | ||||||
| 	return FALSE; | 	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…
	
	Add table
		Add a link
		
	
		Reference in a new issue