mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00: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
|
@ -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
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<Identity
|
||||
Name="19453.net.Rufus"
|
||||
Publisher="CN=7AC86D13-3E5A-491A-ADD5-80095C212740"
|
||||
Version="3.16.1832.0" />
|
||||
Version="3.16.1833.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>Rufus</DisplayName>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 <Ctrl>-<Alt>-<Z> 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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
10
src/rufus.rc
10
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"
|
||||
|
|
19
src/stdio.c
19
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);
|
||||
|
||||
|
|
10
src/ui.c
10
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;
|
||||
}
|
||||
|
|
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…
Reference in a new issue