[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:
Pete Batard 2016-07-09 16:20:58 +01:00
parent cebfa4cc7a
commit 9dd06e93bc
8 changed files with 299 additions and 207 deletions

View File

@ -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
---------
<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 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.

View File

@ -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
// 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.
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);
for (i=0; i<num_sectors_to_clear; i++) {
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;
}
/*
* 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)
{
if (_GetTickCount64() > LastRefresh + MAX_REFRESH) {
@ -1687,7 +1643,6 @@ DWORD WINAPI FormatThread(void* param)
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE;
goto out;
}
CreateThread(NULL, 0, CloseFormatPromptThread, NULL, 0, NULL);
if (IsChecked(IDC_BADBLOCKS)) {
do {

View File

@ -226,6 +226,21 @@ static __inline int MessageBoxExU(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UI
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)
{
int ret;
@ -917,6 +932,14 @@ static __inline BOOL GetVolumeInformationU(LPCSTR lpRootPathName, LPSTR lpVolume
return ret;
}
static __inline HMODULE LoadLibraryU(LPCSTR lpFileName)
{
HMODULE h;
wconvert(lpFileName);
h = LoadLibraryW(wlpFileName);
wfree(lpFileName);
return h;
}
#ifdef __cplusplus
}

View File

@ -2076,115 +2076,13 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
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:
#ifdef RUFUS_TEST
if (LOWORD(wParam) == IDC_TEST) {
break;
}
#endif
if ((LOWORD(wParam) >= UM_LANGUAGE_MENU) && (LOWORD(wParam) < UM_LANGUAGE_MENU_MAX)) {
selected_language = LOWORD(wParam) - UM_LANGUAGE_MENU;
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
ShowWindow(hLogDlg, log_displayed?SW_SHOW:SW_HIDE);
break;
#ifdef RUFUS_TEST
case IDC_TEST:
{
break;
}
#endif
case IDC_ADVANCED:
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;
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:
switch (((LPNMHDR)lParam)->code) {
case TBN_DROPDOWN:
@ -2784,46 +2785,6 @@ static HANDLE SetHogger(BOOL attached_console, BOOL disable_hogger)
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
@ -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);
UpdateWindow(hDlg);
@ -3348,6 +3313,7 @@ out:
if ((!external_loc_file) && (loc_file[0] != 0))
DeleteFileU(loc_file);
DestroyAllTooltips();
ClrFormatPromptHook();
exit_localization();
safe_free(image_path);
safe_free(locale_name);

View File

@ -465,6 +465,10 @@ extern BOOL IsBufferInDB(const unsigned char* buf, const size_t len);
#define printbits(x) _printbits(sizeof(x), &x, 0)
#define printbitslz(x) _printbits(sizeof(x), &x, 1)
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 SaveImageThread(void* param);

View File

@ -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.10.968"
CAPTION "Rufus 2.10.969"
FONT 8, "Segoe UI Symbol", 400, 0, 0x0
BEGIN
LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8
@ -320,8 +320,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,10,968,0
PRODUCTVERSION 2,10,968,0
FILEVERSION 2,10,969,0
PRODUCTVERSION 2,10,969,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -338,13 +338,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "2.10.968"
VALUE "FileVersion", "2.10.969"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2016 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "2.10.968"
VALUE "ProductVersion", "2.10.969"
END
END
BLOCK "VarFileInfo"

View File

@ -36,6 +36,8 @@ extern BOOL usb_debug; // For uuprintf
int nWindowsVersion = WINDOWS_UNDEFINED;
char WindowsVersionStr[128] = "Windows ";
PF_TYPE_DECL(WINAPI, int, LCIDToLocaleName, (LCID, LPWSTR, int, DWORD));
/*
* Hash table functions - modified From glibc 2.3.2:
* [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]));
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;
}

View File

@ -63,6 +63,8 @@ static BOOL notification_is_question;
static const notification_info* notification_more_info;
static BOOL settings_commcheck = FALSE;
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;
@ -1725,3 +1727,85 @@ INT_PTR MyDialogBox(HINSTANCE hInstance, int Dialog_ID, HWND hWndParent, DLGPROC
safe_free(rcTemplate);
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;
}