[misc] fix an issue with Far Manager

* Closes #161
* Also fix a couple warnings from MinGW and VS
This commit is contained in:
Pete Batard 2014-05-27 02:02:50 +01:00
parent 70d2784165
commit ae08fe3ac2
11 changed files with 263 additions and 45 deletions

View File

@ -1,11 +1,12 @@
o Version 1.4.8 (2014.06.??)
Add KolibriOS ISO support
Add VHD support (as *uncompressed* image source)
Add Arabic translation, courtesy of عمر الصمد
Add Croatian translation, courtesy of Dario Komar
Add Danish translation, courtesy of Jens Hansen
Add Latvian translation, courtesy of Aldis Tutins
Allow the use of VHDs as DD image source (fixed disk/uncompressed only)
Report the detected USB speed in the log
Fix a long standing issue when launching Rufus from Far Manager
Fix support for pure UEFI bootable disk images
Various other fixes and improvements

85
res/hogger/hogger.asm Normal file
View File

@ -0,0 +1,85 @@
; Rufus: The Reliable USB Formatting Utility
; Commandline hogger, assembly version (NASM)
; Copyright © 2014 Pete Batard <pete@akeo.ie>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
global _main
extern _GetStdHandle@4
extern _OpenMutexA@12
extern _WaitForSingleObject@8
extern _WriteFile@20
extern _ExitProcess@4
section .text
_main:
; DWORD size;
mov ebp, esp
sub esp, 4
; register HANDLE mutex [-> ecx], stdout [-> ebx];
; stdout = GetStdHandle(STD_OUTPUT_HANDLE);
push -11
call _GetStdHandle@4
mov ebx, eax
; mutex = OpenMutexA(SYNCHRONIZE, FALSE, "Global/Rufus_CmdLine");
push mutex_name
push 0
push 1048576 ; 0x00100000
call _OpenMutexA@12
mov ecx, eax
; if (mutex == NULL)
test eax, eax
; goto error
je error
; WaitForSingleObject(mutex, INFINITE);
push -1
push ecx
call _WaitForSingleObject@8
; goto out;
jmp out;
; error:
error:
; WriteFile(stdout, error_msg, sizeof(error_msg), &size, 0);
push 0
lea eax, [ebp-4]
push eax
push (error_msg_end - error_msg)
push error_msg
push ebx
call _WriteFile@20
; out:
out:
; ExitProcess(0)
push 0
call _ExitProcess@4
; Just in case...
hlt
mutex_name:
db "Global/Rufus_CmdLine",0
error_msg:
db "Unable to synchronize with GUI application.",0
error_msg_end:

40
res/hogger/hogger.c Normal file
View File

@ -0,0 +1,40 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Commandline hogger, C version
* Copyright © 2014 Pete Batard <pete@akeo.ie>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <windows.h>
const char error_msg[] = "Unable to synchronize with UI application.";
int __cdecl main(int argc_ansi, char** argv_ansi)
{
DWORD size;
register HANDLE mutex, stdout;
stdout = GetStdHandle(STD_OUTPUT_HANDLE);
mutex = OpenMutexA(SYNCHRONIZE, FALSE, "Global/Rufus_CmdLine");
if (mutex == NULL)
goto error;
WaitForSingleObject(mutex, INFINITE);
goto out;
error:
WriteFile(stdout, error_msg, sizeof(error_msg), &size, 0);
out:
ExitProcess(0);
}

BIN
res/hogger/hogger.exe Normal file

Binary file not shown.

69
res/hogger/readme.txt Normal file
View File

@ -0,0 +1,69 @@
Rufus: The Reliable USB Formatting Utility - Commandline hogger
# Description
This little utility is intended to solve the issue of Windows applications not
being able to be BOTH console and GUI [1], leading to all kind of annoyances [2].
The basic problem is as follows:
1. You have an awesome Windows UI application that you want your users to be
able to start from the commandline (to provide parameters, etc.)
2. If an application is set to operate in UI mode, then when you launch it from
the command line, you will NOT get a command prompt freeze until it exits, as
you'd expect from any console app, but instead the prompt will return to the
user right away.
3. This means that any message that you try to output from your app to the
console will appear as ugly as:
C:\Some\Directory> Some Application Message
4. Another unfortunate effect is that, when users exit your app, they might
continue to wait for the prompt to come back, when it is already available
whilst polluted by output that looks out of place => Your user experience is
now subpar...
5. To compensate for this, you might try to be (somewhat) clever, through the
simulating an <Enter> keypress when your app exit, but lo and behold, soon
enough you start receiving complaints left and right from Far Manager [3]
users, due to the fact that this application uses the <Enter> keypress as an
"I want to launch the currently selected app" event.
6. HEY, MICROSOFT, THIS SUPER-SUCKS!!!!
# Primer
So, how far do we need to go to address this?
1. We'll create a console hogger application, that does just what you'd expect
a regular commandline app to do (hog the console prompt until the app exits)
and wait for a signal (Mutex) from the UI app to indicate that it is closed.
2. We'll embed this console hogger as a resource in our app, to be extracted
and run in the current directory whenever we detect that our UI app has
been launched from the commandline
3. Because we want this annoyance to have the least impact possible, we'll
make sure that it is AS SMALL AS POSSIBLE, by writing it in pure assembly
so that we can compile it with NASM and linking it with WDK, leaving us
with a 2 KB executable (that will further be compressed to about 1/4th of
this size through UPX/LZMA).
# Drawbacks
The one annoyance with this workaround is that our 'hogger' will appear in the
command history (doskey). This means that when when a user wants to navigate
back to the command they launched, they need to skip through an extra entry,
which they probably have no idea about. And of course, doskey does not provide
the ability to suppress this last entry.
Oh, and you also need to release the mutex so that you can delete the file
before you exit, though that's not a big deal...
# Compilation
; From a WDK command prompt
nasm -fwin32 hogger.asm
link /subsystem:console /nodefaultlib /entry:main hogger.obj %SDK_LIB_DEST%\i386\kernel32.lib
# Links
[1] http://blogs.msdn.com/b/oldnewthing/archive/2009/01/01/9259142.aspx
[2] https://github.com/pbatard/rufus/issues/161
[3] http://www.farmanager.com/

View File

@ -54,6 +54,7 @@
#define IDR_SL_LDLINUX_V5_SYS 403
#define IDR_SL_MBOOT_C32 404
#define IDR_LC_RUFUS_LOC 500
#define IDR_XT_HOGGER 501
#define IDC_DEVICE 1001
#define IDC_FILESYSTEM 1002
#define IDC_START 1003
@ -388,7 +389,7 @@
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 404
#define _APS_NEXT_RESOURCE_VALUE 502
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1071
#define _APS_NEXT_SYMED_VALUE 4000

View File

@ -1571,6 +1571,10 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
SHCNE_MEDIAINSERTED|SHCNE_MEDIAREMOVED, UM_MEDIA_CHANGE, 1, &NotifyEntry);
}
PostMessage(hMainDialog, UM_PROGRESS_CREATE, 0, 0);
// 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);
return (INT_PTR)TRUE;
// The things one must do to get an ellipsis on the status bar...
@ -2031,28 +2035,6 @@ static void PrintUsage(char* appname)
printf(" This usage guide.\n");
}
/* There's a massive annoyance when taking over the console in a win32 app
* in that it doesn't return the prompt on app exit. So we must handle that
* manually, but the *ONLY* frigging way to achieve it is by simulating a
* keypress... which means we first need to bring our console back on top.
* And people wonder why developing elegant Win32 apps takes forever...
*/
static void DetachConsole(void)
{
INPUT input;
HWND hWnd;
hWnd = GetConsoleWindow();
SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
FreeConsole();
memset(&input, 0, sizeof(input));
input.type = INPUT_KEYBOARD;
input.ki.wVk = VK_RETURN;
SendInput(1, &input, sizeof(input));
input.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &input, sizeof(input));
}
/*
* Application Entrypoint
*/
@ -2064,15 +2046,16 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
{
const char* old_wait_option = "/W";
const char* rufus_loc = "rufus.loc";
const char* cmdline_hogger = "rufus.com";
int i, opt, option_index = 0, argc = 0, si = 0, lcid = GetUserDefaultUILanguage();
BOOL attached_console = FALSE, external_loc_file = FALSE, lgp_set = FALSE;
BYTE* loc_data;
DWORD loc_size, Size;
BYTE *loc_data, *hog_data;
DWORD loc_size, hog_size, Size;
char tmp_path[MAX_PATH] = "", loc_file[MAX_PATH] = "", *tmp, *locale_name = NULL;
char** argv = NULL;
wchar_t **wenv, **wargv;
PF_TYPE_DECL(CDECL, int, __wgetmainargs, (int*, wchar_t***, wchar_t***, int, int*));
HANDLE mutex = NULL, hFile = NULL;
HANDLE mutex = NULL, hogmutex = NULL, hFile = NULL;
HWND hDlg = NULL;
MSG msg;
int wait_for_mutex = 0;
@ -2087,12 +2070,41 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
// Reattach the console, if we were started from commandline
if (AttachConsole(ATTACH_PARENT_PROCESS) != 0) {
INPUT* input;
attached_console = TRUE;
IGNORE_RETVAL(freopen("CONIN$", "r", stdin));
IGNORE_RETVAL(freopen("CONOUT$", "w", stdout));
IGNORE_RETVAL(freopen("CONOUT$", "w", stderr));
_flushall();
printf("\n");
hog_data = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_XT_HOGGER),
_RT_RCDATA, cmdline_hogger, &hog_size, FALSE);
if (hog_data != NULL) {
// Create our synchronisation mutex
hogmutex = CreateMutexA(NULL, TRUE, "Global/Rufus_CmdLine");
// Extract the hogger resource
hFile = CreateFileA(cmdline_hogger, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
WriteFile(hFile, hog_data, hog_size, &Size, NULL);
}
safe_closehandle(hFile);
// Now launch the file from the commandline, by simulating keypresses
input = (INPUT*)calloc(strlen(cmdline_hogger)+1, sizeof(INPUT));
for (i=0; i<(int)strlen(cmdline_hogger); i++) {
input[i].type = INPUT_KEYBOARD;
input[i].ki.dwFlags = KEYEVENTF_UNICODE;
input[i].ki.wScan = (wchar_t)cmdline_hogger[i];
}
input[i].type = INPUT_KEYBOARD;
input[i].ki.wVk = VK_RETURN;
// SetWindowPos(GetConsoleWindow(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
SendInput(i+1, input, sizeof(INPUT));
safe_free(input);
}
}
// Use the Locale specified in the registry, if any
@ -2183,7 +2195,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
if ( (!get_supported_locales(loc_file))
|| ((selected_locale = ((locale_name == NULL)?get_locale_from_lcid(lcid, TRUE):get_locale_from_name(locale_name, TRUE))) == NULL) ) {
uprintf("FATAL: Could not access locale!\n");
MessageBoxU(NULL, "The locale data is missing or invalid. This application will now exit.", "Fatal error", MB_ICONSTOP|MB_IS_RTL);
MessageBoxU(NULL, "The locale data is missing or invalid. This application will now exit.",
"Fatal error", MB_ICONSTOP|MB_IS_RTL|MB_SYSTEMMODAL);
goto out;
}
@ -2200,7 +2213,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
if ((mutex == NULL) || (GetLastError() == ERROR_ALREADY_EXISTS)) {
// Load the translation before we print the error
get_loc_data_file(loc_file, selected_locale);
MessageBoxU(NULL, lmprintf(MSG_002), lmprintf(MSG_001), MB_ICONSTOP|MB_IS_RTL);
// Set MB_SYSTEMMODAL to prevent Far Manager from stealing focus...
MessageBoxU(NULL, lmprintf(MSG_002), lmprintf(MSG_001), MB_ICONSTOP|MB_IS_RTL|MB_SYSTEMMODAL);
goto out;
}
@ -2254,7 +2268,7 @@ relaunch:
*/
hDlg = CreateDialogW(hInstance, MAKEINTRESOURCEW(IDD_DIALOG + IDD_IS_RTL), NULL, MainCallback);
if (hDlg == NULL) {
MessageBoxU(NULL, "Could not create Window", "DialogBox failure", MB_ICONSTOP|MB_IS_RTL);
MessageBoxU(NULL, "Could not create Window", "DialogBox failure", MB_ICONSTOP|MB_IS_RTL|MB_SYSTEMMODAL);
goto out;
}
if ((relaunch_rc.left > -65536) && (relaunch_rc.top > -65536))
@ -2376,6 +2390,9 @@ relaunch:
}
out:
// Destroy our commandline hogger first, so that we can delete the app
ReleaseMutex(hogmutex);
safe_closehandle(hogmutex);
if ((!external_loc_file) && (loc_file[0] != 0))
DeleteFileU(loc_file);
DestroyAllTooltips();
@ -2390,8 +2407,11 @@ out:
}
if (lgp_set)
SetLGP(TRUE, &existing_key, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", "NoDriveTypeAutorun", 0);
if (attached_console)
DetachConsole();
if (attached_console) {
SetWindowPos(GetConsoleWindow(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
FreeConsole();
}
DeleteFileA(cmdline_hogger);
CloseHandle(mutex);
CLOSE_OPENED_LIBRARIES;
uprintf("*** " APPLICATION_NAME " exit ***\n");

View File

@ -387,7 +387,7 @@ extern void parse_update(char* buf, size_t len);
extern BOOL WimExtractCheck(void);
extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst);
extern BOOL IsHDImage(const char* path);
extern BOOL AppendVHDFooter(const char* image_path);
extern BOOL AppendVHDFooter(const char* vhd_path);
extern int IsHDD(DWORD DriveIndex, uint16_t vid, uint16_t pid, const char* strid);
DWORD WINAPI FormatThread(void* param);

View File

@ -32,7 +32,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 206, 329
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Rufus 1.4.8.489"
CAPTION "Rufus 1.4.8.490"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
@ -165,7 +165,7 @@ END
RTL_IDD_DIALOG DIALOGEX 12, 12, 206, 329
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL
CAPTION "Rufus 1.4.8.489"
CAPTION "Rufus 1.4.8.490"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
@ -366,6 +366,7 @@ BEGIN
"IDR_FD_EGA16_CPX RCDATA ""../res/freedos/ega16.cpx""\r\n"
"IDR_FD_EGA17_CPX RCDATA ""../res/freedos/ega17.cpx""\r\n"
"IDR_FD_EGA18_CPX RCDATA ""../res/freedos/ega18.cpx""\r\n"
"IDR_XT_HOGGER RCDATA ""../res/hogger/hogger.exe""\r\n"
"\r\n"
"// Must reference a manifest for visual styles and elevation\r\n"
"// Oh, and it must happen at the end, or MinGW will ignore it!\r\n"
@ -427,8 +428,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,4,8,489
PRODUCTVERSION 1,4,8,489
FILEVERSION 1,4,8,490
PRODUCTVERSION 1,4,8,490
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -445,13 +446,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "1.4.8.489"
VALUE "FileVersion", "1.4.8.490"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2014 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "1.4.8.489"
VALUE "ProductVersion", "1.4.8.490"
END
END
BLOCK "VarFileInfo"
@ -519,6 +520,7 @@ IDR_FD_EGA15_CPX RCDATA "../res/freedos/ega15.cpx"
IDR_FD_EGA16_CPX RCDATA "../res/freedos/ega16.cpx"
IDR_FD_EGA17_CPX RCDATA "../res/freedos/ega17.cpx"
IDR_FD_EGA18_CPX RCDATA "../res/freedos/ega18.cpx"
IDR_XT_HOGGER RCDATA "../res/hogger/hogger.exe"
// Must reference a manifest for visual styles and elevation
// Oh, and it must happen at the end, or MinGW will ignore it!

View File

@ -283,7 +283,7 @@ char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options)
}
// Set the file extension filters
pfd->lpVtbl->SetFileTypes(pfd, ext->count+1, filter_spec);
pfd->lpVtbl->SetFileTypes(pfd, (UINT)ext->count+1, filter_spec);
// Set the default directory
wpath = utf8_to_wchar(path);

View File

@ -115,7 +115,7 @@ static BOOL Get7ZipPath(void)
return FALSE;
}
BOOL AppendVHDFooter(const char* image_path)
BOOL AppendVHDFooter(const char* vhd_path)
{
const char creator_os[4] = VHD_FOOTER_CREATOR_HOST_OS_WINDOWS;
const char creator_app[4] = { 'r', 'u', 'f', 'u' };
@ -123,7 +123,7 @@ BOOL AppendVHDFooter(const char* image_path)
DWORD size;
LARGE_INTEGER li;
HANDLE handle = INVALID_HANDLE_VALUE;
vhd_footer* footer;
vhd_footer* footer = NULL;
uint64_t totalSectors;
uint16_t cylinders = 0;
uint8_t heads, sectorsPerTrack;
@ -132,10 +132,10 @@ BOOL AppendVHDFooter(const char* image_path)
size_t i;
PF_INIT(UuidCreate, Rpcrt4);
handle = CreateFileU(image_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
handle = CreateFileU(vhd_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
li.QuadPart = 0;
if ((handle == INVALID_HANDLE_VALUE) || (!SetFilePointerEx(handle, li, &li, FILE_END))) {
uprintf("Could not open image '%s': %s", image_path, WindowsErrorString());
uprintf("Could not open image '%s': %s", vhd_path, WindowsErrorString());
goto out;
}
footer = (vhd_footer*)calloc(1, sizeof(vhd_footer));