From 957ec183c9bb82876d6de7085706f8e02906c96b Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Sat, 9 Oct 2021 16:15:21 +0100 Subject: [PATCH] [ui] improve progress report when disabling Windows 11 installation restrictions * Also fix Image Options content being lost when switching language. --- ChangeLog.txt | 2 +- res/appstore/Package.appxmanifest | 2 +- res/loc/ChangeLog.txt | 6 + res/loc/rufus.loc | 13 +- src/format.c | 9 +- src/rufus.c | 1 + src/rufus.h | 6 +- src/rufus.rc | 10 +- src/stdio.c | 19 +- src/ui.c | 10 +- src/vhd.c | 276 ++++++++++++++++++------------ 11 files changed, 221 insertions(+), 133 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 3174c65c..add58d94 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -3,9 +3,9 @@ o Version 3.16 (2021.10.??) Fix BIOS boot support for Arch derivatives Fix removal of some boot entries for Ubuntu derivatives Fix log not being saved on exit + Add Windows 11 "Extended" installation support (Disables TPM/Secure Boot/RAM requirements) Add UEFI Shell ISO downloads Add support for Intel NUC card readers - Add Windows 11 extended installation support (disables TPM or Secure Boot requirement) Improve Windows 11 support Improve Windows version reporting Speed up clearing of MBR/GPT diff --git a/res/appstore/Package.appxmanifest b/res/appstore/Package.appxmanifest index b59970bf..0cf7b7b2 100644 --- a/res/appstore/Package.appxmanifest +++ b/res/appstore/Package.appxmanifest @@ -11,7 +11,7 @@ + Version="3.16.1833.0" /> Rufus diff --git a/res/loc/ChangeLog.txt b/res/loc/ChangeLog.txt index 5a1c9dc3..e54e26b3 100644 --- a/res/loc/ChangeLog.txt +++ b/res/loc/ChangeLog.txt @@ -5,6 +5,12 @@ To edit a translation, please make sure to follow: https://github.com/pbatard/rufus/wiki/Localization#Editing_an_existing_translation Or simply download https://rufus-web.akeo.ie/locale/pollock.exe and follow its directions. +o v3.?? (????.??.??) + - *UPDATED* MSG_305 Reworked the message to mention the new Windows 11 Extended option + - *NEW* MSG_322 "Standard Windows 11 Installation (TPM 2.0, Secure Boot, 8GB+ RAM)" + - *NEW* MSG_323 "Extended Windows 11 Installation (no TPM/no Secure Boot/8GB- RAM)" + - *NEW* MSG_324 "Removing Windows 11 installation restrictions: %s" + o v3.14 (2021.03.31) - *UPDATED* MSG_068 "Error while partitioning drive." -> "Could not partition drive." - *UPDATED* MSG_274 "IsoHybrid image detected" -> "%s image detected" diff --git a/res/loc/rufus.loc b/res/loc/rufus.loc index 9a72478a..778d7b8f 100644 --- a/res/loc/rufus.loc +++ b/res/loc/rufus.loc @@ -559,9 +559,10 @@ t MSG_301 "Show application settings" t MSG_302 "Show information about this application" t MSG_303 "Show the log" t MSG_304 "Create a disk image of the selected device" -t MSG_305 "Use this option to indicate if you want to run Windows directly from this drive (Windows To Go) or if you " - "want to install Windows to a different disk.\r\nIn 'Extended Windows 11 Installation' mode, Rufus patches the " - "media so that Windows 11 can be installed on platforms that don't meet the TPM 2.0 or Secure Boot requirements." +t MSG_305 "Use this option to indicate if you plan to install Windows to a different disk, or if you want to run Windows " + "directly from this drive (Windows To Go).\r\nIn 'Extended Windows 11 Installation' mode, Rufus will patch the " + "media so that Windows 11 can be installed on platforms that don't meet the TPM 2.0, Secure Boot or minimum RAM " + "requirements." # You can see this status message by pressing -- and then selecting START. # It's the same as MSG_286 but with a process that *may* be faster, hence the name. t MSG_306 "Fast-zeroing drive: %s" @@ -583,9 +584,9 @@ t MSG_319 "Ignore Boot Marker" t MSG_320 "Refreshing partition layout (%s)..." t MSG_321 "The image you have selected is an ISOHybrid, but its creators have not made it compatible with ISO/File " "copy mode.\nAs a result, DD image writing mode will be enforced." -t MSG_322 "Standard Windows 11 Installation (TPM 2.0 / Secure Boot / 8GB+ RAM)" -t MSG_323 "Extended Windows 11 Installation (no TPM / no Secure Boot / 8GB- RAM)" -t MSG_324 "Removing Windows 11 installation restrictions (%s)" +t MSG_322 "Standard Windows 11 Installation (TPM 2.0, Secure Boot, 8GB+ RAM)" +t MSG_323 "Extended Windows 11 Installation (no TPM/no Secure Boot/8GB- RAM)" +t MSG_324 "Removing Windows 11 installation restrictions: %s" ######################################################################### l "ar-SA" "Arabic (العربية)" 0x0401, 0x0801, 0x0c01, 0x1001, 0x1401, 0x1801, 0x1c01, 0x2001, 0x2401, 0x2801, 0x2c01, 0x3001, 0x3401, 0x3801, 0x3c01, 0x4001 diff --git a/src/format.c b/src/format.c index 4057835c..86d7d785 100644 --- a/src/format.c +++ b/src/format.c @@ -1452,7 +1452,7 @@ BOOL RemoveWindows11Restrictions(char drive_letter) boot_wim_path[0] = drive_letter; - PrintInfo(0, MSG_324, lmprintf(MSG_307)); + UpdateProgressWithInfoForce(OP_PATCH, MSG_324, 0, PATCH_PROGRESS_TOTAL); uprintf("Mounting '%s'...", boot_wim_path); mount_path = WimMountImage(boot_wim_path, wim_index); @@ -1462,6 +1462,7 @@ BOOL RemoveWindows11Restrictions(char drive_letter) static_sprintf(path, "%s\\Windows\\System32\\config\\SYSTEM", mount_path); if (!MountRegistryHive(HKEY_LOCAL_MACHINE, offline_hive_name, path)) goto out; + UpdateProgressWithInfoForce(OP_PATCH, MSG_324, 102, PATCH_PROGRESS_TOTAL); is_hive_mounted = TRUE; static_sprintf(key_path, "%s\\Setup", offline_hive_name); @@ -1490,6 +1491,7 @@ BOOL RemoveWindows11Restrictions(char drive_letter) } uprintf("Created 'HKLM\\SYSTEM\\Setup\\LabConfig\\%s' registry key", key_name[i]); } + UpdateProgressWithInfoForce(OP_PATCH, MSG_324, 103, PATCH_PROGRESS_TOTAL); r = TRUE; out: @@ -1497,12 +1499,15 @@ out: RegCloseKey(hSubKey); if (hKey != NULL) RegCloseKey(hKey); - if (is_hive_mounted) + if (is_hive_mounted) { UnmountRegistryHive(HKEY_LOCAL_MACHINE, offline_hive_name); + UpdateProgressWithInfoForce(OP_PATCH, MSG_324, 104, PATCH_PROGRESS_TOTAL); + } if (mount_path) { uprintf("Unmounting '%s'...", boot_wim_path, wim_index); WimUnmountImage(boot_wim_path, wim_index); } + UpdateProgressWithInfo(OP_PATCH, MSG_324, PATCH_PROGRESS_TOTAL, PATCH_PROGRESS_TOTAL); free(mount_path); return r; } diff --git a/src/rufus.c b/src/rufus.c index 8a0376d9..4335967c 100755 --- a/src/rufus.c +++ b/src/rufus.c @@ -2707,6 +2707,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA InitDialog(hDlg); GetDevices(0); EnableControls(TRUE, FALSE); + UpdateImage(FALSE); // The AppStore version does not need the internal check for updates if (!appstore_version) CheckForUpdates(FALSE); diff --git a/src/rufus.h b/src/rufus.h index 499766c2..a967f99f 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -69,6 +69,7 @@ #define MAX_SIZE_SUFFIXES 6 // bytes, KB, MB, GB, TB, PB #define MAX_CLUSTER_SIZES 18 #define MAX_PROGRESS 0xFFFF +#define PATCH_PROGRESS_TOTAL 207 #define MAX_LOG_SIZE 0x7FFFFFFE #define MAX_REFRESH 25 // How long we should wait to refresh UI elements (in ms) #define MAX_GUID_STRING_LENGTH 40 @@ -251,6 +252,7 @@ enum action_type { OP_CREATE_FS, OP_FIX_MBR, OP_FILE_COPY, + OP_PATCH, OP_FINALIZE, OP_MAX }; @@ -516,7 +518,9 @@ extern void PrintStatusInfo(BOOL info, BOOL debug, unsigned int duration, int ms #define PrintInfo(...) PrintStatusInfo(TRUE, FALSE, __VA_ARGS__) #define PrintInfoDebug(...) PrintStatusInfo(TRUE, TRUE, __VA_ARGS__) extern void UpdateProgress(int op, float percent); -extern void UpdateProgressWithInfo(int op, int msg, uint64_t processed, uint64_t total); +extern void _UpdateProgressWithInfo(int op, int msg, uint64_t processed, uint64_t total, BOOL force); +#define UpdateProgressWithInfo(op, msg, processed, total) _UpdateProgressWithInfo(op, msg, processed, total, FALSE) +#define UpdateProgressWithInfoForce(op, msg, processed, total) _UpdateProgressWithInfo(op, msg, processed, total, TRUE) #define UpdateProgressWithInfoInit(hProgressDialog, bNoAltMode) UpdateProgressWithInfo(OP_INIT, (int)bNoAltMode, (uint64_t)(uintptr_t)hProgressDialog, 0); extern const char* StrError(DWORD error_code, BOOL use_default_locale); extern char* GuidToString(const GUID* guid); diff --git a/src/rufus.rc b/src/rufus.rc index 6706ee77..16593fad 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 3.16.1832" +CAPTION "Rufus 3.16.1833" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -395,8 +395,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,16,1832,0 - PRODUCTVERSION 3,16,1832,0 + FILEVERSION 3,16,1833,0 + PRODUCTVERSION 3,16,1833,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -414,13 +414,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "3.16.1832" + VALUE "FileVersion", "3.16.1833" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2021 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-3.16.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "3.16.1832" + VALUE "ProductVersion", "3.16.1833" END END BLOCK "VarFileInfo" diff --git a/src/stdio.c b/src/stdio.c index f14c3631..50b80c18 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -37,6 +37,8 @@ #include "msapi_utf8.h" #include "localization.h" +#define FACILITY_WIM 322 + /* * Globals */ @@ -627,6 +629,16 @@ static const char *GetVdsError(DWORD error_code) } } +static const char* GetVimError(DWORD error_code) +{ + switch (error_code) { + case 0xC1420127: + return "The specified image in the specified wim is already mounted for read and write access."; + default: + return NULL; + } +} + // Convert a windows error to human readable string const char *WindowsErrorString(void) { @@ -637,11 +649,14 @@ const char *WindowsErrorString(void) error_code = GetLastError(); // Check for VDS error codes - if ((SCODE_FACILITY(error_code) == FACILITY_ITF) && (GetVdsError(error_code) != NULL)) { + if ((HRESULT_FACILITY(error_code) == FACILITY_ITF) && (GetVdsError(error_code) != NULL)) { static_sprintf(err_string, "[0x%08lX] %s", error_code, GetVdsError(error_code)); return err_string; } - + if ((HRESULT_FACILITY(error_code) == FACILITY_WIM) && (GetVimError(error_code) != NULL)) { + static_sprintf(err_string, "[0x%08lX] %s", error_code, GetVimError(error_code)); + return err_string; + } static_sprintf(err_string, "[0x%08lX] ", error_code); presize = (DWORD)strlen(err_string); diff --git a/src/ui.c b/src/ui.c index 9425df99..18d57d60 100644 --- a/src/ui.c +++ b/src/ui.c @@ -1181,6 +1181,8 @@ void InitProgress(BOOL bOnlyFormat) break; case BT_IMAGE: nb_slots[OP_FILE_COPY] = (img_report.is_iso || img_report.is_windows_img) ? -1 : 0; + if (HAS_WINDOWS(img_report) && ComboBox_GetCurItemData(hImageOption) == IMOP_WIN_EXTENDED) + nb_slots[OP_PATCH] = -1; break; default: nb_slots[OP_FILE_COPY] = 2 + 1; @@ -1387,7 +1389,7 @@ static void bar_update(struct bar_progress* bp, uint64_t howmuch, uint64_t dltim // display percentage completed, rate of transfer and estimated remaining duration. // During init (op = OP_INIT) an optional HWND can be passed on which to look for // a progress bar. Part of the code (eta, speed) comes from GNU wget. -void UpdateProgressWithInfo(int op, int msg, uint64_t processed, uint64_t total) +void _UpdateProgressWithInfo(int op, int msg, uint64_t processed, uint64_t total, BOOL force) { static int last_update_progress_type = UPT_PERCENT; static struct bar_progress bp = { 0 }; @@ -1486,7 +1488,7 @@ void UpdateProgressWithInfo(int op, int msg, uint64_t processed, uint64_t total) static_sprintf(msg_data, "%0.1f%%", percent); break; } - if ((bp.count == bp.total_length) || (current_time > last_refresh + MAX_REFRESH)) { + if ((force) || (bp.count == bp.total_length) || (current_time > last_refresh + MAX_REFRESH)) { if (op < 0) { SendMessage(hProgressBar, PBM_SETPOS, (WPARAM)(MAX_PROGRESS * percent / 100.0f), 0); if (op == OP_NOOP_WITH_TASKBAR) @@ -1494,8 +1496,8 @@ void UpdateProgressWithInfo(int op, int msg, uint64_t processed, uint64_t total) } else { UpdateProgress(op, (float)percent); } - if ((msg >= 0) && ((current_time > bp.last_screen_update + SCREEN_REFRESH_INTERVAL) || - (last_update_progress_type != update_progress_type) || (bp.count == bp.total_length))) { + if ((force) || ((msg >= 0) && ((current_time > bp.last_screen_update + SCREEN_REFRESH_INTERVAL) || + (last_update_progress_type != update_progress_type) || (bp.count == bp.total_length)))) { PrintInfo(0, msg, msg_data); bp.last_screen_update = current_time; } diff --git a/src/vhd.c b/src/vhd.c index fd33159d..23432f53 100644 --- a/src/vhd.c +++ b/src/vhd.c @@ -57,6 +57,47 @@ #define SECONDS_SINCE_JAN_1ST_2000 946684800 +#define INVALID_CALLBACK_VALUE 0xFFFFFFFF + +#define WIM_FLAG_RESERVED 0x00000001 +#define WIM_FLAG_VERIFY 0x00000002 +#define WIM_FLAG_INDEX 0x00000004 +#define WIM_FLAG_NO_APPLY 0x00000008 +#define WIM_FLAG_NO_DIRACL 0x00000010 +#define WIM_FLAG_NO_FILEACL 0x00000020 +#define WIM_FLAG_SHARE_WRITE 0x00000040 +#define WIM_FLAG_FILEINFO 0x00000080 +#define WIM_FLAG_NO_RP_FIX 0x00000100 + +// Bitmask for the kind of progress we want to report in the WIM progress callback +#define WIM_REPORT_PROGRESS 0x00000001 +#define WIM_REPORT_PROCESS 0x00000002 +#define WIM_REPORT_FILEINFO 0x00000004 + +// From https://docs.microsoft.com/en-us/previous-versions/msdn10/dd834960(v=msdn.10) +// as well as https://msfn.org/board/topic/150700-wimgapi-wimmountimage-progressbar/ +enum WIMMessage { + WIM_MSG = WM_APP + 0x1476, + WIM_MSG_TEXT, + WIM_MSG_PROGRESS, // Indicates an update in the progress of an image application. + WIM_MSG_PROCESS, // Enables the caller to prevent a file or a directory from being captured or applied. + WIM_MSG_SCANNING, // Indicates that volume information is being gathered during an image capture. + WIM_MSG_SETRANGE, // Indicates the number of files that will be captured or applied. + WIM_MSG_SETPOS, // Indicates the number of files that have been captured or applied. + WIM_MSG_STEPIT, // Indicates that a file has been either captured or applied. + WIM_MSG_COMPRESS, // Enables the caller to prevent a file resource from being compressed during a capture. + WIM_MSG_ERROR, // Alerts the caller that an error has occurred while capturing or applying an image. + WIM_MSG_ALIGNMENT, // Enables the caller to align a file resource on a particular alignment boundary. + WIM_MSG_RETRY, // Sent when the file is being reapplied because of a network timeout. + WIM_MSG_SPLIT, // Enables the caller to align a file resource on a particular alignment boundary. + WIM_MSG_FILEINFO, // Used in conjunction with WimApplyImages()'s WIM_FLAG_FILEINFO flag to provide detailed file info. + WIM_MSG_INFO, // Sent when an info message is available. + WIM_MSG_WARNING, // Sent when a warning message is available. + WIM_MSG_CHK_PROCESS, + WIM_MSG_SUCCESS = 0, + WIM_MSG_ABORT_IMAGE = -1 +}; + /* * VHD Fixed HD footer (Big Endian) * http://download.microsoft.com/download/f/f/e/ffef50a5-07dd-4cf8-aaa3-442c0673a029/Virtual%20Hard%20Disk%20Format%20Spec_10_18_06.doc @@ -114,13 +155,15 @@ extern int default_thread_priority; extern BOOL ignore_boot_marker; static uint8_t wim_flags = 0; +static uint32_t progress_report_mask; +static uint64_t progress_offset = 0, progress_total = 100; static wchar_t wmount_path[MAX_PATH] = { 0 }, wmount_track[MAX_PATH] = { 0 }; static char sevenzip_path[MAX_PATH]; static const char conectix_str[] = VHD_FOOTER_COOKIE; -static BOOL count_files; +static BOOL count_files, use_msg_progress = FALSE; // Apply/Mount image functionality static const char *_image, *_dst; -static int _index; +static int _index, progress_op = OP_FILE_COPY, progress_msg = MSG_267; static BOOL Get7ZipPath(void) { @@ -355,6 +398,79 @@ out: return is_bootable_img; } +// WIM operations progress callback +DWORD WINAPI WimProgressCallback(DWORD dwMsgId, WPARAM wParam, LPARAM lParam, PVOID pvIgnored) +{ + PBOOL pbCancel = NULL; + PWIN32_FIND_DATA pFileData; + const char* level = NULL; + uint64_t size; + + switch (dwMsgId) { + case WIM_MSG_PROGRESS: + // The default WIM progress is useless for apply (freezes at 95%, which is usually when + // only half the files have been processed), so we only use it for mounting/unmounting. + if (!(progress_report_mask & WIM_REPORT_PROGRESS)) + break; + UpdateProgressWithInfo(progress_op, progress_msg, progress_offset + wParam, progress_total); + break; + case WIM_MSG_PROCESS: + if (!(progress_report_mask & WIM_REPORT_PROCESS)) + break; + // The amount of files processed is overwhelming (16k+ for a typical image), + // and trying to display it *WILL* slow us down, so we don't. +#if 0 + uprintf("%S", (PWSTR)wParam); + PrintStatus(0, MSG_000, str); // MSG_000 is "%s" +#endif + if (count_files) { + wim_nb_files++; + } else { + // At the end of an actual apply, the WIM API re-lists a bunch of directories it already processed, + // so, even as we try to compensate, we might end up with more entries than counted - ignore those. + if (wim_proc_files < wim_nb_files) + wim_proc_files++; + else + wim_extra_files++; + UpdateProgressWithInfo(progress_op, progress_msg, wim_proc_files, wim_nb_files); + } + // Halt on error + if (IS_ERROR(FormatStatus)) { + pbCancel = (PBOOL)lParam; + *pbCancel = TRUE; + break; + } + break; + case WIM_MSG_FILEINFO: + if (!(progress_report_mask & WIM_REPORT_FILEINFO)) + break; + pFileData = (PWIN32_FIND_DATA)lParam; + if (pFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + uprintf("Creating: %S", (PWSTR)wParam); + } else { + size = (((uint64_t)pFileData->nFileSizeHigh) << 32) + pFileData->nFileSizeLow; + uprintf("Extracting: %S (%s)", (PWSTR)wParam, SizeToHumanReadable(size, FALSE, FALSE)); + } + break; + case WIM_MSG_RETRY: + level = "retry"; + // fall through + case WIM_MSG_INFO: + if (level == NULL) level = "info"; + // fall through + case WIM_MSG_WARNING: + if (level == NULL) level = "warning"; + // fall through + case WIM_MSG_ERROR: + if (level == NULL) level = "error"; + SetLastError((DWORD)lParam); + uprintf("WIM processing %s: %S [err = %d]\n", level, (PWSTR)wParam, WindowsErrorString()); + break; + } + + return IS_ERROR(FormatStatus) ? WIM_MSG_ABORT_IMAGE : WIM_MSG_SUCCESS; +} + // Find out if we have any way to extract/apply WIM files on this platform // Returns a bitfield of the methods we can use (1 = Extract using wimgapi, 2 = Extract using 7-Zip, 4 = Apply using wimgapi) uint8_t WimExtractCheck(BOOL bSilent) @@ -384,15 +500,26 @@ uint8_t WimExtractCheck(BOOL bSilent) return wim_flags; } +// // Looks like Microsoft's idea of "mount" for WIM images involves the creation // of a as many virtual junctions as there exist directories on the image... // So, yeah, this is both very slow and wasteful of space. +// +// NB: You can see mounted WIMs, along with their mountpoint, by checking: +// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WIMMount\Mounted Images\ +// You can also mount/unmount images from an elevated prompt with something like: +// dism /mount-image [/readonly] /imagefile:F:\sources\boot.wim /index:2 /mountdir:C:\test\offline +// dism /unmount-image /discard /mountdir:C:\test\offline +// static DWORD WINAPI WimMountImageThread(LPVOID param) { BOOL r = FALSE; wconvert(temp_dir); wchar_t* wimage = utf8_to_wchar(_image); + + PF_INIT_OR_OUT(WIMRegisterMessageCallback, Wimgapi); PF_INIT_OR_OUT(WIMMountImage, Wimgapi); + PF_INIT_OR_OUT(WIMUnregisterMessageCallback, Wimgapi); if (wmount_path[0] != 0) { uprintf("WimMountImage: An image is already mounted"); @@ -417,7 +544,18 @@ static DWORD WINAPI WimMountImageThread(LPVOID param) goto out; } + progress_report_mask = WIM_REPORT_PROGRESS; + progress_op = OP_PATCH; + progress_msg = MSG_324; + progress_offset = 1; + progress_total = PATCH_PROGRESS_TOTAL; + if (pfWIMRegisterMessageCallback(NULL, (FARPROC)WimProgressCallback, NULL) == INVALID_CALLBACK_VALUE) { + uprintf("WimMountImage: Could not set progress callback: %s", WindowsErrorString()); + goto out; + } + r = pfWIMMountImage(wmount_path, wimage, _index, wmount_track); + pfWIMUnregisterMessageCallback(NULL, (FARPROC)WimProgressCallback); if (!r) { uprintf("Could not mount '%S [%d]' on '%S': %s", wimage, _index, wmount_path, WindowsErrorString()); goto out; @@ -455,22 +593,39 @@ static DWORD WINAPI WimUnmountImageThread(LPVOID param) { BOOL r = FALSE; wchar_t* wimage = utf8_to_wchar(_image); + + PF_INIT_OR_OUT(WIMRegisterMessageCallback, Wimgapi); PF_INIT_OR_OUT(WIMUnmountImage, Wimgapi); + PF_INIT_OR_OUT(WIMUnregisterMessageCallback, Wimgapi); if (wmount_path[0] == 0) { uprintf("WimUnmountImage: No image is mounted"); goto out; } + + progress_report_mask = WIM_REPORT_PROGRESS; + progress_op = OP_PATCH; + progress_msg = MSG_324; + progress_offset = 105; + progress_total = PATCH_PROGRESS_TOTAL; + if (pfWIMRegisterMessageCallback(NULL, (FARPROC)WimProgressCallback, NULL) == INVALID_CALLBACK_VALUE) { + uprintf("WimUnmountImage: Could not set progress callback: %s", WindowsErrorString()); + goto out; + } + r = pfWIMUnmountImage(wmount_path, wimage, _index, TRUE); + pfWIMUnregisterMessageCallback(NULL, (FARPROC)WimProgressCallback); if (!r) { uprintf("Could not unmount '%S': %s", wmount_path, WindowsErrorString()); goto out; } uprintf("Unmounted '%S [%d]'", wmount_path, _index); - RemoveDirectoryW(wmount_path); - wmount_path[0] = 0; - RemoveDirectoryW(wmount_track); + if (!RemoveDirectoryW(wmount_track)) + uprintf("Could not delete '%S' : %s", wmount_track, WindowsErrorString()); wmount_track[0] = 0; + if (!RemoveDirectoryW(wmount_path)) + uprintf("Could not delete '%S' : %s", wmount_path, WindowsErrorString()); + wmount_path[0] = 0; out: safe_free(wimage); ExitThread((DWORD)r); @@ -652,112 +807,6 @@ BOOL WimExtractFile(const char* image, int index, const char* src, const char* d || ((wim_flags & WIM_HAS_API_EXTRACT) && WimExtractFile_API(image, index, src, dst, bSilent)) ); } -// From https://docs.microsoft.com/en-us/previous-versions/msdn10/dd834960(v=msdn.10) -// as well as https://msfn.org/board/topic/150700-wimgapi-wimmountimage-progressbar/ -enum WIMMessage { - WIM_MSG = WM_APP + 0x1476, - WIM_MSG_TEXT, - WIM_MSG_PROGRESS, // Indicates an update in the progress of an image application. - WIM_MSG_PROCESS, // Enables the caller to prevent a file or a directory from being captured or applied. - WIM_MSG_SCANNING, // Indicates that volume information is being gathered during an image capture. - WIM_MSG_SETRANGE, // Indicates the number of files that will be captured or applied. - WIM_MSG_SETPOS, // Indicates the number of files that have been captured or applied. - WIM_MSG_STEPIT, // Indicates that a file has been either captured or applied. - WIM_MSG_COMPRESS, // Enables the caller to prevent a file resource from being compressed during a capture. - WIM_MSG_ERROR, // Alerts the caller that an error has occurred while capturing or applying an image. - WIM_MSG_ALIGNMENT, // Enables the caller to align a file resource on a particular alignment boundary. - WIM_MSG_RETRY, // Sent when the file is being reapplied because of a network timeout. - WIM_MSG_SPLIT, // Enables the caller to align a file resource on a particular alignment boundary. - WIM_MSG_FILEINFO, // Used in conjunction with WimApplyImages()'s WIM_FLAG_FILEINFO flag to provide detailed file info. - WIM_MSG_INFO, // Sent when an info message is available. - WIM_MSG_WARNING, // Sent when a warning message is available. - WIM_MSG_CHK_PROCESS, - WIM_MSG_SUCCESS = 0x00000000, - WIM_MSG_ABORT_IMAGE = -1 -}; - -#define INVALID_CALLBACK_VALUE 0xFFFFFFFF - -#define WIM_FLAG_RESERVED 0x00000001 -#define WIM_FLAG_VERIFY 0x00000002 -#define WIM_FLAG_INDEX 0x00000004 -#define WIM_FLAG_NO_APPLY 0x00000008 -#define WIM_FLAG_NO_DIRACL 0x00000010 -#define WIM_FLAG_NO_FILEACL 0x00000020 -#define WIM_FLAG_SHARE_WRITE 0x00000040 -#define WIM_FLAG_FILEINFO 0x00000080 -#define WIM_FLAG_NO_RP_FIX 0x00000100 - -// Progress callback -DWORD WINAPI WimProgressCallback(DWORD dwMsgId, WPARAM wParam, LPARAM lParam, PVOID pvIgnored) -{ - PBOOL pbCancel = NULL; - PWIN32_FIND_DATA pFileData; - const char* level = NULL; - uint64_t size; - - switch (dwMsgId) { - case WIM_MSG_PROGRESS: - // The default WIM progress is useless (freezes at 95%, which is usually when only half - // the files have been processed), so we don't use it -#if 0 - PrintInfo(0, MSG_267, (DWORD)wParam); - UpdateProgress(OP_FILE_COPY, 0.98f*(DWORD)wParam); -#endif - break; - case WIM_MSG_PROCESS: - // The amount of files processed is overwhelming (16k+ for a typical image), - // and trying to display it *WILL* slow us down, so we don't. -#if 0 - uprintf("%S", (PWSTR)wParam); - PrintStatus(0, MSG_000, str); // MSG_000 is "%s" -#endif - if (count_files) { - wim_nb_files++; - } else { - // At the end of an actual apply, the WIM API re-lists a bunch of directories it already processed, - // so, even as we try to compensate, we might end up with more entries than counted - ignore those. - if (wim_proc_files < wim_nb_files) - wim_proc_files++; - else - wim_extra_files++; - UpdateProgressWithInfo(OP_FILE_COPY, MSG_267, wim_proc_files, wim_nb_files); - } - // Halt on error - if (IS_ERROR(FormatStatus)) { - pbCancel = (PBOOL)lParam; - *pbCancel = TRUE; - break; - } - break; - case WIM_MSG_FILEINFO: - pFileData = (PWIN32_FIND_DATA)lParam; - if (pFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - uprintf("Creating: %S", (PWSTR)wParam); - } else { - size = (((uint64_t)pFileData->nFileSizeHigh) << 32) + pFileData->nFileSizeLow; - uprintf("Extracting: %S (%s)", (PWSTR)wParam, SizeToHumanReadable(size, FALSE, FALSE)); - } - break; - case WIM_MSG_RETRY: - level = "retry"; - // fall through - case WIM_MSG_INFO: - if (level == NULL) level = "info"; - // fall through - case WIM_MSG_WARNING: - if (level == NULL) level = "warning"; - // fall through - case WIM_MSG_ERROR: - if (level == NULL) level = "error"; - SetLastError((DWORD)lParam); - uprintf("Apply %s: %S [err = %d]\n", level, (PWSTR)wParam, WindowsErrorString()); - break; - } - - return IS_ERROR(FormatStatus)?WIM_MSG_ABORT_IMAGE:WIM_MSG_SUCCESS; -} - // Apply a WIM image using wimgapi.dll (Windows 7 or later) // https://docs.microsoft.com/en-us/previous-versions/msdn10/dd851944(v=msdn.10) // To get progress, we must run this call within its own thread @@ -780,6 +829,11 @@ static DWORD WINAPI WimApplyImageThread(LPVOID param) uprintf("Opening: %s:[%d]", _image, _index); + progress_report_mask = WIM_REPORT_PROCESS | WIM_REPORT_FILEINFO; + progress_op = OP_FILE_COPY; + progress_msg = MSG_267; + progress_offset = 0; + progress_total = 100; if (pfWIMRegisterMessageCallback(NULL, (FARPROC)WimProgressCallback, NULL) == INVALID_CALLBACK_VALUE) { uprintf(" Could not set progress callback: %s", WindowsErrorString()); goto out;