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;