mirror of
https://github.com/pbatard/rufus.git
synced 2025-05-29 05:55:30 -04:00
[ui] improve progress report when disabling Windows 11 installation restrictions
* Also fix Image Options content being lost when switching language.
This commit is contained in:
parent
b043db33e6
commit
957ec183c9
11 changed files with 221 additions and 133 deletions
276
src/vhd.c
276
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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue