From ae08fe3ac25841dfa074d128e5de74cff5d2d664 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 27 May 2014 02:02:50 +0100 Subject: [PATCH] [misc] fix an issue with Far Manager * Closes #161 * Also fix a couple warnings from MinGW and VS --- ChangeLog.txt | 3 +- res/hogger/hogger.asm | 85 ++++++++++++++++++++++++++++++++++++++++++ res/hogger/hogger.c | 40 ++++++++++++++++++++ res/hogger/hogger.exe | Bin 0 -> 2048 bytes res/hogger/readme.txt | 69 ++++++++++++++++++++++++++++++++++ src/resource.h | 3 +- src/rufus.c | 82 +++++++++++++++++++++++++--------------- src/rufus.h | 2 +- src/rufus.rc | 14 ++++--- src/stdlg.c | 2 +- src/vhd.c | 8 ++-- 11 files changed, 263 insertions(+), 45 deletions(-) create mode 100644 res/hogger/hogger.asm create mode 100644 res/hogger/hogger.c create mode 100644 res/hogger/hogger.exe create mode 100644 res/hogger/readme.txt diff --git a/ChangeLog.txt b/ChangeLog.txt index 209e5601..5fb36da8 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -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 diff --git a/res/hogger/hogger.asm b/res/hogger/hogger.asm new file mode 100644 index 00000000..dbab990c --- /dev/null +++ b/res/hogger/hogger.asm @@ -0,0 +1,85 @@ + ; Rufus: The Reliable USB Formatting Utility + ; Commandline hogger, assembly version (NASM) + ; Copyright © 2014 Pete Batard + ; + ; 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 . + + 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: \ No newline at end of file diff --git a/res/hogger/hogger.c b/res/hogger/hogger.c new file mode 100644 index 00000000..a03b76ee --- /dev/null +++ b/res/hogger/hogger.c @@ -0,0 +1,40 @@ +/* + * Rufus: The Reliable USB Formatting Utility + * Commandline hogger, C version + * Copyright © 2014 Pete Batard + * + * 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 . + */ + +#include + +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); +} diff --git a/res/hogger/hogger.exe b/res/hogger/hogger.exe new file mode 100644 index 0000000000000000000000000000000000000000..6ca64e8a6e6516f80e7273130455580adc5293a1 GIT binary patch literal 2048 zcmeHHL2DCH5S}zqY_&C@hu(YziykD3{(-H!O>NUAW-S#J>Sp)Zee33J*nO+Df(TWx z5YeM&4;}=;Ly_W1=|#l;0WW$H0`;gjACDpunxN+c7Koh@6e z9=g2H-`{sQZM}c>;HQbF3(XE5yg1Sv)BJXGD%Hm^p8mMrq*xV>N439CRxtrenI3@m zi&iK18M2wZnO*>tH7Jo!!H5_e9P_(~qIDviKtfAF!~NXTg>;u1==dv;2!jmZs6PE= zhkXZkXjxEvUSa+@)zDn@)^u)?$QZ!YLgd=Y23Sr7UALRarWtx6o4kAa|2MGoW$|my z|K7TbPhDE|#`6aF;L)elib;BV|BdSN+vi)?k*y!_;i37X;ve&7vCwK=LD7fSWenen zL0Gec z=a~WRVbDIO{T}W2q3_zi*nr0XZXlY7Cy0v(GK1-$-7`89wy^E)zswZ5vXnb!OE=&E zNl&@K 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 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 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/ diff --git a/src/resource.h b/src/resource.h index 68f681e3..babac41d 100644 --- a/src/resource.h +++ b/src/resource.h @@ -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 diff --git a/src/rufus.c b/src/rufus.c index 3c7c9db8..467c3f26 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -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"); diff --git a/src/rufus.h b/src/rufus.h index 5ea63d89..4dac1bb8 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -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); diff --git a/src/rufus.rc b/src/rufus.rc index ea6dd780..e9971487 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -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! diff --git a/src/stdlg.c b/src/stdlg.c index fa4af701..3d5fdc03 100644 --- a/src/stdlg.c +++ b/src/stdlg.c @@ -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); diff --git a/src/vhd.c b/src/vhd.c index 3af32f44..9b0c88e3 100644 --- a/src/vhd.c +++ b/src/vhd.c @@ -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));