mirror of
https://github.com/pbatard/rufus.git
synced 2025-05-19 09:25:12 -04:00
[ui] improve Windows format prompt autoclose
* Closes #794 * Also reorder some messages (so that RUFUS_TEST comes first) * Also update issue template
This commit is contained in:
parent
cebfa4cc7a
commit
9dd06e93bc
8 changed files with 299 additions and 207 deletions
4
.github/ISSUE_TEMPLATE.md
vendored
4
.github/ISSUE_TEMPLATE.md
vendored
|
@ -1,7 +1,7 @@
|
||||||
|
<PLEASE READ THIS CAREFULLY: You *MUST* read and complete the checklist below, by placing an x into each [ ], BEFORE clicking on 'Submit new issue'. Failure to perform these steps, WHICH ARE ONLY THERE TO HELP *YOU*, will result in the issue being dismissed without warning.>
|
||||||
|
|
||||||
Checklist
|
Checklist
|
||||||
---------
|
---------
|
||||||
<Please complete the following and place an x into each [ ] to confirm that you have read and performed these preliminary steps>
|
|
||||||
|
|
||||||
- [ ] I looked at https://github.com/pbatard/rufus/wiki/FAQ to see if my question has already been answered.
|
- [ ] I looked at https://github.com/pbatard/rufus/wiki/FAQ to see if my question has already been answered.
|
||||||
- [ ] I performed a search in the issue tracker for similar issues, using keywords relevant to my problem.
|
- [ ] I performed a search in the issue tracker for similar issues, using keywords relevant to my problem.
|
||||||
- [ ] I clicked the `Log` button in Rufus and copy/pasted the log into the line that says `<FULL LOG>` below.
|
- [ ] I clicked the `Log` button in Rufus and copy/pasted the log into the line that says `<FULL LOG>` below.
|
||||||
|
|
47
src/format.c
47
src/format.c
|
@ -825,7 +825,7 @@ static BOOL ClearMBRGPT(HANDLE hPhysicalDrive, LONGLONG DiskSize, DWORD SectorSi
|
||||||
// Also, for various reasons (one of which being that Windows seems to have issues
|
// Also, for various reasons (one of which being that Windows seems to have issues
|
||||||
// with GPT drives that contain a lot of small partitions) we try not not to clear
|
// with GPT drives that contain a lot of small partitions) we try not not to clear
|
||||||
// sectors further than the lowest partition already residing on the disk.
|
// sectors further than the lowest partition already residing on the disk.
|
||||||
num_sectors_to_clear = min(SelectedDrive.FirstDataSector, (add1MB ? 2048 : 0) + MAX_SECTORS_TO_CLEAR);
|
num_sectors_to_clear = min(SelectedDrive.FirstDataSector, (DWORD)((add1MB ? 2048 : 0) + MAX_SECTORS_TO_CLEAR));
|
||||||
uprintf("Erasing %d sectors", num_sectors_to_clear);
|
uprintf("Erasing %d sectors", num_sectors_to_clear);
|
||||||
for (i=0; i<num_sectors_to_clear; i++) {
|
for (i=0; i<num_sectors_to_clear; i++) {
|
||||||
if ((IS_ERROR(FormatStatus)) || (write_sectors(hPhysicalDrive, SectorSize, i, 1, pBuf) != SectorSize)) {
|
if ((IS_ERROR(FormatStatus)) || (write_sectors(hPhysicalDrive, SectorSize, i, 1, pBuf) != SectorSize)) {
|
||||||
|
@ -1406,50 +1406,6 @@ static BOOL SetupWinToGo(const char* drive_name, BOOL use_ms_efi)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Detect if a Windows Format prompt is active, by enumerating the
|
|
||||||
* whole Windows tree and looking for the relevant popup
|
|
||||||
*/
|
|
||||||
static BOOL CALLBACK FormatPromptCallback(HWND hWnd, LPARAM lParam)
|
|
||||||
{
|
|
||||||
char str_buf[MAX_PATH];
|
|
||||||
HWND *hFound = (HWND*)lParam;
|
|
||||||
static const char* security_string = "Microsoft Windows";
|
|
||||||
|
|
||||||
// The format prompt has the popup window style
|
|
||||||
if (GetWindowLong(hWnd, GWL_STYLE) & WS_POPUPWINDOW) {
|
|
||||||
str_buf[0] = 0;
|
|
||||||
GetWindowTextA(hWnd, str_buf, MAX_PATH);
|
|
||||||
str_buf[MAX_PATH-1] = 0;
|
|
||||||
if (safe_strcmp(str_buf, security_string) == 0) {
|
|
||||||
*hFound = hWnd;
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When we format a drive that doesn't have any existing partitions, we can't lock it
|
|
||||||
* prior to partitioning, which means that Windows will display a "You need to format the
|
|
||||||
* disk in drive X: before you can use it'. You will also get that popup if you start a
|
|
||||||
* bad blocks check and cancel it before it completes. We have to close that popup manually.
|
|
||||||
*/
|
|
||||||
static DWORD WINAPI CloseFormatPromptThread(LPVOID param) {
|
|
||||||
HWND hFormatPrompt;
|
|
||||||
|
|
||||||
while(format_op_in_progress) {
|
|
||||||
hFormatPrompt = NULL;
|
|
||||||
EnumChildWindows(GetDesktopWindow(), FormatPromptCallback, (LPARAM)&hFormatPrompt);
|
|
||||||
if (hFormatPrompt != NULL) {
|
|
||||||
SendMessage(hFormatPrompt, WM_COMMAND, (WPARAM)IDCANCEL, (LPARAM)0);
|
|
||||||
uprintf("Closed Windows format prompt\n");
|
|
||||||
}
|
|
||||||
Sleep(100);
|
|
||||||
}
|
|
||||||
ExitThread(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_progress(const uint64_t processed_bytes)
|
static void update_progress(const uint64_t processed_bytes)
|
||||||
{
|
{
|
||||||
if (_GetTickCount64() > LastRefresh + MAX_REFRESH) {
|
if (_GetTickCount64() > LastRefresh + MAX_REFRESH) {
|
||||||
|
@ -1687,7 +1643,6 @@ DWORD WINAPI FormatThread(void* param)
|
||||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE;
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
CreateThread(NULL, 0, CloseFormatPromptThread, NULL, 0, NULL);
|
|
||||||
|
|
||||||
if (IsChecked(IDC_BADBLOCKS)) {
|
if (IsChecked(IDC_BADBLOCKS)) {
|
||||||
do {
|
do {
|
||||||
|
|
|
@ -226,6 +226,21 @@ static __inline int MessageBoxExU(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UI
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static __inline int LoadStringU(HINSTANCE hInstance, UINT uID, LPSTR lpBuffer, int nBufferMax)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
DWORD err = ERROR_INVALID_DATA;
|
||||||
|
walloc(lpBuffer, nBufferMax);
|
||||||
|
ret = LoadStringW(hInstance, uID, wlpBuffer, nBufferMax);
|
||||||
|
err = GetLastError();
|
||||||
|
if ((ret > 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, nBufferMax)) == 0)) {
|
||||||
|
err = GetLastError();
|
||||||
|
}
|
||||||
|
wfree(lpBuffer);
|
||||||
|
SetLastError(err);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static __inline int DrawTextU(HDC hDC, LPCSTR lpText, int nCount, LPRECT lpRect, UINT uFormat)
|
static __inline int DrawTextU(HDC hDC, LPCSTR lpText, int nCount, LPRECT lpRect, UINT uFormat)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -917,6 +932,14 @@ static __inline BOOL GetVolumeInformationU(LPCSTR lpRootPathName, LPSTR lpVolume
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static __inline HMODULE LoadLibraryU(LPCSTR lpFileName)
|
||||||
|
{
|
||||||
|
HMODULE h;
|
||||||
|
wconvert(lpFileName);
|
||||||
|
h = LoadLibraryW(wlpFileName);
|
||||||
|
wfree(lpFileName);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
274
src/rufus.c
274
src/rufus.c
|
@ -2076,115 +2076,13 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
|
||||||
|
|
||||||
switch (message) {
|
switch (message) {
|
||||||
|
|
||||||
case UM_MEDIA_CHANGE:
|
|
||||||
wParam = DBT_CUSTOMEVENT;
|
|
||||||
// Fall through
|
|
||||||
case WM_DEVICECHANGE:
|
|
||||||
// The Windows hotplug subsystem sucks. Among other things, if you insert a GPT partitioned
|
|
||||||
// USB drive with zero partitions, the only device messages you will get are a stream of
|
|
||||||
// DBT_DEVNODES_CHANGED and that's it. But those messages are also issued when you get a
|
|
||||||
// DBT_DEVICEARRIVAL and DBT_DEVICEREMOVECOMPLETE, and there's a whole slew of them so we
|
|
||||||
// can't really issue a refresh for each one we receive
|
|
||||||
// What we do then is arm a timer on DBT_DEVNODES_CHANGED, if it's been more than 1 second
|
|
||||||
// since last refresh/arm timer, and have that timer send DBT_CUSTOMEVENT when it expires.
|
|
||||||
// DO *NOT* USE WM_DEVICECHANGE AS THE MESSAGE FROM THE TIMER PROC, as it may be filtered!
|
|
||||||
// For instance filtering will occur when (un)plugging in a FreeBSD UFD on Windows 8.
|
|
||||||
// Instead, use a custom user message, such as UM_MEDIA_CHANGE, to set DBT_CUSTOMEVENT.
|
|
||||||
if (format_thid == NULL) {
|
|
||||||
switch (wParam) {
|
|
||||||
case DBT_DEVICEARRIVAL:
|
|
||||||
case DBT_DEVICEREMOVECOMPLETE:
|
|
||||||
case DBT_CUSTOMEVENT: // Sent by our timer refresh function or for card reader media change
|
|
||||||
LastRefresh = _GetTickCount64();
|
|
||||||
KillTimer(hMainDialog, TID_REFRESH_TIMER);
|
|
||||||
if (!format_op_in_progress) {
|
|
||||||
queued_hotplug_event = FALSE;
|
|
||||||
GetDevices((DWORD)ComboBox_GetItemData(hDeviceList, ComboBox_GetCurSel(hDeviceList)));
|
|
||||||
user_changed_label = FALSE;
|
|
||||||
} else {
|
|
||||||
queued_hotplug_event = TRUE;
|
|
||||||
}
|
|
||||||
return (INT_PTR)TRUE;
|
|
||||||
case DBT_DEVNODES_CHANGED:
|
|
||||||
// If it's been more than a second since last device refresh, arm a refresh timer
|
|
||||||
if (_GetTickCount64() > LastRefresh + 1000) {
|
|
||||||
LastRefresh = _GetTickCount64();
|
|
||||||
SetTimer(hMainDialog, TID_REFRESH_TIMER, 1000, RefreshTimer);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_INITDIALOG:
|
|
||||||
PF_INIT(SHChangeNotifyRegister, shell32);
|
|
||||||
// Make sure fScale is set before the first call to apply localization, so that move/resize scale appropriately
|
|
||||||
hDC = GetDC(hDlg);
|
|
||||||
fScale = GetDeviceCaps(hDC, LOGPIXELSX) / 96.0f;
|
|
||||||
if (hDC != NULL)
|
|
||||||
ReleaseDC(hDlg, hDC);
|
|
||||||
apply_localization(IDD_DIALOG, hDlg);
|
|
||||||
SetUpdateCheck();
|
|
||||||
togo_mode = TRUE; // We display the ToGo controls by default and need to hide them
|
|
||||||
// Create the log window (hidden)
|
|
||||||
first_log_display = TRUE;
|
|
||||||
log_displayed = FALSE;
|
|
||||||
hLogDlg = MyCreateDialog(hMainInstance, IDD_LOG, hDlg, (DLGPROC)LogProc);
|
|
||||||
InitDialog(hDlg);
|
|
||||||
GetDevices(0);
|
|
||||||
CheckForUpdates(FALSE);
|
|
||||||
// Register MEDIA_INSERTED/MEDIA_REMOVED notifications for card readers
|
|
||||||
if ((pfSHChangeNotifyRegister != NULL) && (SUCCEEDED(SHGetSpecialFolderLocation(0, CSIDL_DESKTOP, &pidlDesktop)))) {
|
|
||||||
NotifyEntry.pidl = pidlDesktop;
|
|
||||||
NotifyEntry.fRecursive = TRUE;
|
|
||||||
// NB: The following only works if the media is already formatted.
|
|
||||||
// If you insert a blank card, notifications will not be sent... :(
|
|
||||||
ulRegister = pfSHChangeNotifyRegister(hDlg, 0x0001|0x0002|0x8000,
|
|
||||||
SHCNE_MEDIAINSERTED|SHCNE_MEDIAREMOVED, UM_MEDIA_CHANGE, 1, &NotifyEntry);
|
|
||||||
}
|
|
||||||
// Bring our Window on top. We have to go through all *THREE* of these, or Far Manager hides our window :(
|
|
||||||
SetWindowPos(hMainDialog, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
|
|
||||||
SetWindowPos(hMainDialog, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
|
|
||||||
SetWindowPos(hMainDialog, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
|
|
||||||
|
|
||||||
// Set 'Start' as the selected button if it's enabled, otherwise use 'Select ISO', instead
|
|
||||||
SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)(IsWindowEnabled(hStart) ? hStart : hSelectISO), TRUE);
|
|
||||||
|
|
||||||
#if defined(ALPHA)
|
|
||||||
// Add a VERY ANNOYING popup for Alpha releases, so that people don't start redistributing them
|
|
||||||
MessageBoxA(NULL, "This is an Alpha version of " APPLICATION_NAME " - It is meant to be used for "
|
|
||||||
"testing ONLY and should NOT be distributed as a release.", "ALPHA VERSION", MSG_INFO);
|
|
||||||
#elif defined(TEST)
|
|
||||||
// Same thing for Test releases
|
|
||||||
MessageBoxA(NULL, "This is a Test version of " APPLICATION_NAME " - It is meant to be used for "
|
|
||||||
"testing ONLY and should NOT be distributed as a release.", "TEST VERSION", MSG_INFO);
|
|
||||||
#endif
|
|
||||||
return (INT_PTR)FALSE;
|
|
||||||
|
|
||||||
// The things one must do to get an ellipsis and text alignment on the status bar...
|
|
||||||
case WM_DRAWITEM:
|
|
||||||
if (wParam == IDC_STATUS) {
|
|
||||||
pDI = (DRAWITEMSTRUCT*)lParam;
|
|
||||||
pDI->rcItem.top -= (int)((4.0f * fScale) - 6.0f);
|
|
||||||
pDI->rcItem.left += (int)(((pDI->itemID == SB_SECTION_MIDDLE)?-2.0f:4.0f) * fScale);
|
|
||||||
SetBkMode(pDI->hDC, TRANSPARENT);
|
|
||||||
switch(pDI->itemID) {
|
|
||||||
case SB_SECTION_LEFT:
|
|
||||||
SetTextColor(pDI->hDC, GetSysColor(COLOR_BTNTEXT));
|
|
||||||
DrawTextExU(pDI->hDC, szStatusMessage, -1, &pDI->rcItem,
|
|
||||||
DT_LEFT|DT_END_ELLIPSIS|DT_PATH_ELLIPSIS, NULL);
|
|
||||||
return (INT_PTR)TRUE;
|
|
||||||
case SB_SECTION_RIGHT:
|
|
||||||
SetTextColor(pDI->hDC, GetSysColor(COLOR_3DSHADOW));
|
|
||||||
DrawTextExA(pDI->hDC, szTimer, -1, &pDI->rcItem, DT_LEFT, NULL);
|
|
||||||
return (INT_PTR)TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_COMMAND:
|
case WM_COMMAND:
|
||||||
|
#ifdef RUFUS_TEST
|
||||||
|
if (LOWORD(wParam) == IDC_TEST) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((LOWORD(wParam) >= UM_LANGUAGE_MENU) && (LOWORD(wParam) < UM_LANGUAGE_MENU_MAX)) {
|
if ((LOWORD(wParam) >= UM_LANGUAGE_MENU) && (LOWORD(wParam) < UM_LANGUAGE_MENU_MAX)) {
|
||||||
selected_language = LOWORD(wParam) - UM_LANGUAGE_MENU;
|
selected_language = LOWORD(wParam) - UM_LANGUAGE_MENU;
|
||||||
i = 0;
|
i = 0;
|
||||||
|
@ -2277,12 +2175,6 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
|
||||||
// Must come last for the log window to get focus
|
// Must come last for the log window to get focus
|
||||||
ShowWindow(hLogDlg, log_displayed?SW_SHOW:SW_HIDE);
|
ShowWindow(hLogDlg, log_displayed?SW_SHOW:SW_HIDE);
|
||||||
break;
|
break;
|
||||||
#ifdef RUFUS_TEST
|
|
||||||
case IDC_TEST:
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
case IDC_ADVANCED:
|
case IDC_ADVANCED:
|
||||||
advanced_mode = !advanced_mode;
|
advanced_mode = !advanced_mode;
|
||||||
WriteSettingBool(SETTING_ADVANCED_MODE, advanced_mode);
|
WriteSettingBool(SETTING_ADVANCED_MODE, advanced_mode);
|
||||||
|
@ -2578,6 +2470,115 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
|
||||||
}
|
}
|
||||||
return (INT_PTR)TRUE;
|
return (INT_PTR)TRUE;
|
||||||
|
|
||||||
|
case UM_MEDIA_CHANGE:
|
||||||
|
wParam = DBT_CUSTOMEVENT;
|
||||||
|
// Fall through
|
||||||
|
case WM_DEVICECHANGE:
|
||||||
|
// The Windows hotplug subsystem sucks. Among other things, if you insert a GPT partitioned
|
||||||
|
// USB drive with zero partitions, the only device messages you will get are a stream of
|
||||||
|
// DBT_DEVNODES_CHANGED and that's it. But those messages are also issued when you get a
|
||||||
|
// DBT_DEVICEARRIVAL and DBT_DEVICEREMOVECOMPLETE, and there's a whole slew of them so we
|
||||||
|
// can't really issue a refresh for each one we receive
|
||||||
|
// What we do then is arm a timer on DBT_DEVNODES_CHANGED, if it's been more than 1 second
|
||||||
|
// since last refresh/arm timer, and have that timer send DBT_CUSTOMEVENT when it expires.
|
||||||
|
// DO *NOT* USE WM_DEVICECHANGE AS THE MESSAGE FROM THE TIMER PROC, as it may be filtered!
|
||||||
|
// For instance filtering will occur when (un)plugging in a FreeBSD UFD on Windows 8.
|
||||||
|
// Instead, use a custom user message, such as UM_MEDIA_CHANGE, to set DBT_CUSTOMEVENT.
|
||||||
|
if (format_thid == NULL) {
|
||||||
|
switch (wParam) {
|
||||||
|
case DBT_DEVICEARRIVAL:
|
||||||
|
case DBT_DEVICEREMOVECOMPLETE:
|
||||||
|
case DBT_CUSTOMEVENT: // Sent by our timer refresh function or for card reader media change
|
||||||
|
LastRefresh = _GetTickCount64();
|
||||||
|
KillTimer(hMainDialog, TID_REFRESH_TIMER);
|
||||||
|
if (!format_op_in_progress) {
|
||||||
|
queued_hotplug_event = FALSE;
|
||||||
|
GetDevices((DWORD)ComboBox_GetItemData(hDeviceList, ComboBox_GetCurSel(hDeviceList)));
|
||||||
|
user_changed_label = FALSE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
queued_hotplug_event = TRUE;
|
||||||
|
}
|
||||||
|
return (INT_PTR)TRUE;
|
||||||
|
case DBT_DEVNODES_CHANGED:
|
||||||
|
// If it's been more than a second since last device refresh, arm a refresh timer
|
||||||
|
if (_GetTickCount64() > LastRefresh + 1000) {
|
||||||
|
LastRefresh = _GetTickCount64();
|
||||||
|
SetTimer(hMainDialog, TID_REFRESH_TIMER, 1000, RefreshTimer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_INITDIALOG:
|
||||||
|
PF_INIT(SHChangeNotifyRegister, shell32);
|
||||||
|
// Make sure fScale is set before the first call to apply localization, so that move/resize scale appropriately
|
||||||
|
hDC = GetDC(hDlg);
|
||||||
|
fScale = GetDeviceCaps(hDC, LOGPIXELSX) / 96.0f;
|
||||||
|
if (hDC != NULL)
|
||||||
|
ReleaseDC(hDlg, hDC);
|
||||||
|
apply_localization(IDD_DIALOG, hDlg);
|
||||||
|
SetUpdateCheck();
|
||||||
|
togo_mode = TRUE; // We display the ToGo controls by default and need to hide them
|
||||||
|
// Create the log window (hidden)
|
||||||
|
first_log_display = TRUE;
|
||||||
|
log_displayed = FALSE;
|
||||||
|
hLogDlg = MyCreateDialog(hMainInstance, IDD_LOG, hDlg, (DLGPROC)LogProc);
|
||||||
|
InitDialog(hDlg);
|
||||||
|
GetDevices(0);
|
||||||
|
CheckForUpdates(FALSE);
|
||||||
|
// Register MEDIA_INSERTED/MEDIA_REMOVED notifications for card readers
|
||||||
|
if ((pfSHChangeNotifyRegister != NULL) && (SUCCEEDED(SHGetSpecialFolderLocation(0, CSIDL_DESKTOP, &pidlDesktop)))) {
|
||||||
|
NotifyEntry.pidl = pidlDesktop;
|
||||||
|
NotifyEntry.fRecursive = TRUE;
|
||||||
|
// NB: The following only works if the media is already formatted.
|
||||||
|
// If you insert a blank card, notifications will not be sent... :(
|
||||||
|
ulRegister = pfSHChangeNotifyRegister(hDlg, 0x0001 | 0x0002 | 0x8000,
|
||||||
|
SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED, UM_MEDIA_CHANGE, 1, &NotifyEntry);
|
||||||
|
}
|
||||||
|
// Bring our Window on top. We have to go through all *THREE* of these, or Far Manager hides our window :(
|
||||||
|
SetWindowPos(hMainDialog, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
|
||||||
|
SetWindowPos(hMainDialog, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
|
||||||
|
SetWindowPos(hMainDialog, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
|
||||||
|
|
||||||
|
// Set 'Start' as the selected button if it's enabled, otherwise use 'Select ISO', instead
|
||||||
|
SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)(IsWindowEnabled(hStart) ? hStart : hSelectISO), TRUE);
|
||||||
|
|
||||||
|
#if defined(ALPHA)
|
||||||
|
// Add a VERY ANNOYING popup for Alpha releases, so that people don't start redistributing them
|
||||||
|
MessageBoxA(NULL, "This is an Alpha version of " APPLICATION_NAME " - It is meant to be used for "
|
||||||
|
"testing ONLY and should NOT be distributed as a release.", "ALPHA VERSION", MSG_INFO);
|
||||||
|
#elif defined(TEST)
|
||||||
|
// Same thing for Test releases
|
||||||
|
MessageBoxA(NULL, "This is a Test version of " APPLICATION_NAME " - It is meant to be used for "
|
||||||
|
"testing ONLY and should NOT be distributed as a release.", "TEST VERSION", MSG_INFO);
|
||||||
|
#endif
|
||||||
|
return (INT_PTR)FALSE;
|
||||||
|
|
||||||
|
// The things one must do to get an ellipsis and text alignment on the status bar...
|
||||||
|
case WM_DRAWITEM:
|
||||||
|
if (wParam == IDC_STATUS) {
|
||||||
|
pDI = (DRAWITEMSTRUCT*)lParam;
|
||||||
|
pDI->rcItem.top -= (int)((4.0f * fScale) - 6.0f);
|
||||||
|
pDI->rcItem.left += (int)(((pDI->itemID == SB_SECTION_MIDDLE) ? -2.0f : 4.0f) * fScale);
|
||||||
|
SetBkMode(pDI->hDC, TRANSPARENT);
|
||||||
|
switch (pDI->itemID) {
|
||||||
|
case SB_SECTION_LEFT:
|
||||||
|
SetTextColor(pDI->hDC, GetSysColor(COLOR_BTNTEXT));
|
||||||
|
DrawTextExU(pDI->hDC, szStatusMessage, -1, &pDI->rcItem,
|
||||||
|
DT_LEFT | DT_END_ELLIPSIS | DT_PATH_ELLIPSIS, NULL);
|
||||||
|
return (INT_PTR)TRUE;
|
||||||
|
case SB_SECTION_RIGHT:
|
||||||
|
SetTextColor(pDI->hDC, GetSysColor(COLOR_3DSHADOW));
|
||||||
|
DrawTextExA(pDI->hDC, szTimer, -1, &pDI->rcItem, DT_LEFT, NULL);
|
||||||
|
return (INT_PTR)TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case WM_NOTIFY:
|
case WM_NOTIFY:
|
||||||
switch (((LPNMHDR)lParam)->code) {
|
switch (((LPNMHDR)lParam)->code) {
|
||||||
case TBN_DROPDOWN:
|
case TBN_DROPDOWN:
|
||||||
|
@ -2784,46 +2785,6 @@ static HANDLE SetHogger(BOOL attached_console, BOOL disable_hogger)
|
||||||
return hogmutex;
|
return hogmutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns true if:
|
|
||||||
* 1. The OS supports UAC, UAC is on, and the current process runs elevated, or
|
|
||||||
* 2. The OS doesn't support UAC or UAC is off, and the process is being run by a member of the admin group
|
|
||||||
*/
|
|
||||||
static BOOL IsCurrentProcessElevated(void)
|
|
||||||
{
|
|
||||||
BOOL r = FALSE;
|
|
||||||
DWORD size;
|
|
||||||
HANDLE token = INVALID_HANDLE_VALUE;
|
|
||||||
TOKEN_ELEVATION te;
|
|
||||||
SID_IDENTIFIER_AUTHORITY auth = { SECURITY_NT_AUTHORITY };
|
|
||||||
PSID psid;
|
|
||||||
|
|
||||||
if (ReadRegistryKey32(REGKEY_HKLM, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\EnableLUA") == 1) {
|
|
||||||
uprintf("NOTE: UAC is on");
|
|
||||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
|
|
||||||
uprintf("Could not get current process token: %s", WindowsErrorString());
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (!GetTokenInformation(token, TokenElevation, &te, sizeof(te), &size)) {
|
|
||||||
uprintf("Could not get token information: %s", WindowsErrorString());
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
r = (te.TokenIsElevated != 0);
|
|
||||||
} else {
|
|
||||||
uprintf("NOTE: UAC is either disabled or not available");
|
|
||||||
if (!AllocateAndInitializeSid(&auth, 2, SECURITY_BUILTIN_DOMAIN_RID,
|
|
||||||
DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psid))
|
|
||||||
goto out;
|
|
||||||
if (!CheckTokenMembership(NULL, psid, &r))
|
|
||||||
r = FALSE;
|
|
||||||
FreeSid(psid);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
safe_closehandle(token);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Application Entrypoint
|
* Application Entrypoint
|
||||||
|
@ -3135,6 +3096,10 @@ relaunch:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the hook to automatically close Windows' "You need to format the disk in drive..." prompt
|
||||||
|
if (!SetFormatPromptHook())
|
||||||
|
uprintf("Warning:Could not set 'Format Disk' prompt auto-close");
|
||||||
|
|
||||||
ShowWindow(hDlg, SW_SHOWNORMAL);
|
ShowWindow(hDlg, SW_SHOWNORMAL);
|
||||||
UpdateWindow(hDlg);
|
UpdateWindow(hDlg);
|
||||||
|
|
||||||
|
@ -3348,6 +3313,7 @@ out:
|
||||||
if ((!external_loc_file) && (loc_file[0] != 0))
|
if ((!external_loc_file) && (loc_file[0] != 0))
|
||||||
DeleteFileU(loc_file);
|
DeleteFileU(loc_file);
|
||||||
DestroyAllTooltips();
|
DestroyAllTooltips();
|
||||||
|
ClrFormatPromptHook();
|
||||||
exit_localization();
|
exit_localization();
|
||||||
safe_free(image_path);
|
safe_free(image_path);
|
||||||
safe_free(locale_name);
|
safe_free(locale_name);
|
||||||
|
|
|
@ -465,6 +465,10 @@ extern BOOL IsBufferInDB(const unsigned char* buf, const size_t len);
|
||||||
#define printbits(x) _printbits(sizeof(x), &x, 0)
|
#define printbits(x) _printbits(sizeof(x), &x, 0)
|
||||||
#define printbitslz(x) _printbits(sizeof(x), &x, 1)
|
#define printbitslz(x) _printbits(sizeof(x), &x, 1)
|
||||||
extern char* _printbits(size_t const size, void const * const ptr, int leading_zeroes);
|
extern char* _printbits(size_t const size, void const * const ptr, int leading_zeroes);
|
||||||
|
extern BOOL IsCurrentProcessElevated(void);
|
||||||
|
extern char* GetCurrentMUI(void);
|
||||||
|
extern BOOL SetFormatPromptHook(void);
|
||||||
|
extern void ClrFormatPromptHook(void);
|
||||||
|
|
||||||
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.10.968"
|
CAPTION "Rufus 2.10.969"
|
||||||
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
|
||||||
|
@ -320,8 +320,8 @@ END
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 2,10,968,0
|
FILEVERSION 2,10,969,0
|
||||||
PRODUCTVERSION 2,10,968,0
|
PRODUCTVERSION 2,10,969,0
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -338,13 +338,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.10.968"
|
VALUE "FileVersion", "2.10.969"
|
||||||
VALUE "InternalName", "Rufus"
|
VALUE "InternalName", "Rufus"
|
||||||
VALUE "LegalCopyright", "© 2011-2016 Pete Batard (GPL v3)"
|
VALUE "LegalCopyright", "© 2011-2016 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.10.968"
|
VALUE "ProductVersion", "2.10.969"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
60
src/stdfn.c
60
src/stdfn.c
|
@ -36,6 +36,8 @@ extern BOOL usb_debug; // For uuprintf
|
||||||
int nWindowsVersion = WINDOWS_UNDEFINED;
|
int nWindowsVersion = WINDOWS_UNDEFINED;
|
||||||
char WindowsVersionStr[128] = "Windows ";
|
char WindowsVersionStr[128] = "Windows ";
|
||||||
|
|
||||||
|
PF_TYPE_DECL(WINAPI, int, LCIDToLocaleName, (LCID, LPWSTR, int, DWORD));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hash table functions - modified From glibc 2.3.2:
|
* Hash table functions - modified From glibc 2.3.2:
|
||||||
* [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
|
* [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
|
||||||
|
@ -847,3 +849,61 @@ BOOL SetThreadAffinity(DWORD_PTR* thread_affinity, size_t num_threads)
|
||||||
uuprintf(" thr_%d:\t%s", i, printbitslz(thread_affinity[i]));
|
uuprintf(" thr_%d:\t%s", i, printbitslz(thread_affinity[i]));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns true if:
|
||||||
|
* 1. The OS supports UAC, UAC is on, and the current process runs elevated, or
|
||||||
|
* 2. The OS doesn't support UAC or UAC is off, and the process is being run by a member of the admin group
|
||||||
|
*/
|
||||||
|
BOOL IsCurrentProcessElevated(void)
|
||||||
|
{
|
||||||
|
BOOL r = FALSE;
|
||||||
|
DWORD size;
|
||||||
|
HANDLE token = INVALID_HANDLE_VALUE;
|
||||||
|
TOKEN_ELEVATION te;
|
||||||
|
SID_IDENTIFIER_AUTHORITY auth = { SECURITY_NT_AUTHORITY };
|
||||||
|
PSID psid;
|
||||||
|
|
||||||
|
if (ReadRegistryKey32(REGKEY_HKLM, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\EnableLUA") == 1) {
|
||||||
|
uprintf("Note: UAC is active");
|
||||||
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
|
||||||
|
uprintf("Could not get current process token: %s", WindowsErrorString());
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (!GetTokenInformation(token, TokenElevation, &te, sizeof(te), &size)) {
|
||||||
|
uprintf("Could not get token information: %s", WindowsErrorString());
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
r = (te.TokenIsElevated != 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uprintf("Note: UAC is either disabled or not available");
|
||||||
|
if (!AllocateAndInitializeSid(&auth, 2, SECURITY_BUILTIN_DOMAIN_RID,
|
||||||
|
DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psid))
|
||||||
|
goto out;
|
||||||
|
if (!CheckTokenMembership(NULL, psid, &r))
|
||||||
|
r = FALSE;
|
||||||
|
FreeSid(psid);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
safe_closehandle(token);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* GetCurrentMUI(void)
|
||||||
|
{
|
||||||
|
static char mui_str[LOCALE_NAME_MAX_LENGTH];
|
||||||
|
wchar_t wmui_str[LOCALE_NAME_MAX_LENGTH];
|
||||||
|
|
||||||
|
// Of course LCIDToLocaleName() is not available on XP... grrrr!
|
||||||
|
PF_INIT(LCIDToLocaleName, kernel32);
|
||||||
|
|
||||||
|
if ( (pfLCIDToLocaleName != NULL) &&
|
||||||
|
(pfLCIDToLocaleName(GetUserDefaultUILanguage(), wmui_str, LOCALE_NAME_MAX_LENGTH, 0) > 0) ) {
|
||||||
|
wchar_to_utf8_no_alloc(wmui_str, mui_str, LOCALE_NAME_MAX_LENGTH);
|
||||||
|
} else {
|
||||||
|
safe_strcpy(mui_str, LOCALE_NAME_MAX_LENGTH, "en-US");
|
||||||
|
}
|
||||||
|
return mui_str;
|
||||||
|
}
|
||||||
|
|
84
src/stdlg.c
84
src/stdlg.c
|
@ -63,6 +63,8 @@ static BOOL notification_is_question;
|
||||||
static const notification_info* notification_more_info;
|
static const notification_info* notification_more_info;
|
||||||
static BOOL settings_commcheck = FALSE;
|
static BOOL settings_commcheck = FALSE;
|
||||||
static WNDPROC update_original_proc = NULL;
|
static WNDPROC update_original_proc = NULL;
|
||||||
|
static HWINEVENTHOOK fp_weh = NULL;
|
||||||
|
static char *fp_title_str = "Microsoft Windows", *fp_button_str = "Format disk";
|
||||||
|
|
||||||
extern loc_cmd* selected_locale;
|
extern loc_cmd* selected_locale;
|
||||||
|
|
||||||
|
@ -1725,3 +1727,85 @@ INT_PTR MyDialogBox(HINSTANCE hInstance, int Dialog_ID, HWND hWndParent, DLGPROC
|
||||||
safe_free(rcTemplate);
|
safe_free(rcTemplate);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following function calls are used to automatically detect and close the native
|
||||||
|
* Windows format prompt "You must format the disk in drive X:". To do that, we use an
|
||||||
|
* event hook that gets triggered whenever a window is placed in the foreground.
|
||||||
|
* In that hook, we look for a dialog that has style WS_POPUPWINDOW and has the relevant
|
||||||
|
* title. However, because the title in itself is too generic (the expectation is that
|
||||||
|
* it will be "Microsoft Windows") we also enumerate all the child controls from that
|
||||||
|
* prompt, using another callback, until we find one that contains the text we expect
|
||||||
|
* for the "Format disk" button.
|
||||||
|
* Oh, and since all of these strings are localized, we must first pick them up from
|
||||||
|
* the relevant mui (something like "C:\Windows\System32\en-GB\shell32.dll.mui")
|
||||||
|
*/
|
||||||
|
static BOOL CALLBACK FormatPromptCallback(HWND hWnd, LPARAM lParam)
|
||||||
|
{
|
||||||
|
char str[128];
|
||||||
|
BOOL *found = (BOOL*)lParam;
|
||||||
|
|
||||||
|
if (GetWindowTextU(hWnd, str, sizeof(str)) == 0)
|
||||||
|
return TRUE;
|
||||||
|
if (safe_strcmp(str, fp_button_str) == 0)
|
||||||
|
*found = TRUE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CALLBACK FormatPromptHook(HWINEVENTHOOK hWinEventHook, DWORD Event, HWND hWnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
|
||||||
|
{
|
||||||
|
char str[128];
|
||||||
|
BOOL found;
|
||||||
|
|
||||||
|
if (Event == EVENT_SYSTEM_FOREGROUND) {
|
||||||
|
if (GetWindowLong(hWnd, GWL_STYLE) & WS_POPUPWINDOW) {
|
||||||
|
str[0] = 0;
|
||||||
|
GetWindowTextU(hWnd, str, sizeof(str));
|
||||||
|
if (safe_strcmp(str, fp_title_str) == 0) {
|
||||||
|
found = FALSE;
|
||||||
|
EnumChildWindows(hWnd, FormatPromptCallback, (LPARAM)&found);
|
||||||
|
if (found) {
|
||||||
|
SendMessage(hWnd, WM_COMMAND, (WPARAM)IDCANCEL, (LPARAM)0);
|
||||||
|
uprintf("Closed Windows format prompt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL SetFormatPromptHook(void)
|
||||||
|
{
|
||||||
|
HMODULE mui_lib;
|
||||||
|
char mui_path[MAX_PATH];
|
||||||
|
static char title_str[128], button_str[128];
|
||||||
|
|
||||||
|
if (fp_weh != NULL)
|
||||||
|
return TRUE; // No need to set again if active
|
||||||
|
|
||||||
|
// Fetch the localized strings in the relevant
|
||||||
|
static_sprintf(mui_path, "%s\\%s\\shell32.dll.mui", system_dir, GetCurrentMUI());
|
||||||
|
mui_lib = LoadLibraryU(mui_path);
|
||||||
|
if (mui_lib != NULL) {
|
||||||
|
// 4097 = "You need to format the disk in drive %c: before you can use it." (dialog text)
|
||||||
|
// 4125 = "Microsoft Windows" (dialog title)
|
||||||
|
// 4126 = "Format disk" (button)
|
||||||
|
if (LoadStringU(mui_lib, 4125, title_str, sizeof(title_str)) > 0)
|
||||||
|
fp_title_str = title_str;
|
||||||
|
else
|
||||||
|
uprintf("Warning: Could not locate localized format prompt title string in '%s': %s", mui_path, WindowsErrorString());
|
||||||
|
if (LoadStringU(mui_lib, 4126, button_str, sizeof(button_str)) > 0)
|
||||||
|
fp_button_str = button_str;
|
||||||
|
else
|
||||||
|
uprintf("Warning: Could not locate localized format prompt button string in '%s': %s", mui_path, WindowsErrorString());
|
||||||
|
FreeLibrary(mui_lib);
|
||||||
|
}
|
||||||
|
|
||||||
|
fp_weh = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, NULL,
|
||||||
|
FormatPromptHook, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
|
||||||
|
return (fp_weh != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClrFormatPromptHook(void) {
|
||||||
|
UnhookWinEvent(fp_weh);
|
||||||
|
fp_weh = NULL;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue