mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[wue] add automatic local account creation and regional settings duplication
* Local account is created with the same name as the current user along with an *empty* password (which we force the user to change on next logon). This is done to assuage users who might be weary of entering a password in a third party application, and has the benefit of enabling autologon when the install is complete. * Note that the creation of a local account through an answer file prevents Windows 11 22H2 from bugging users about MSA *even with an active network connection*. * For convenience reasons, only duplication of the current username is enabled. We *may* add a dialog to enter any random username in a future version, but for 3.20, this is all you get. * Likewise, the locale duplication is only carried out during OOBE and *not* WinPE (which means that you still get the initial "Windows setup language and user preferences" prompt). This is intentional as otherwise the default screen and "Repair Windows" options are not presented. * It's not my fault that the Windows password change screen is super ill conceived, whereas it doesn't hide the current password field as it should when the current password is blank, and one needs to click on a very small arrow to get the changes applied, instead of a PROMINENT button that should intuitively have been positioned right next to "Cancel". * If you want to complain that we should just "present the user with XYZ and be done with it", please bear in mind that we can't add new dialogs to Rufus as willy-nilly as you believe we can. *ANY* new UI interface requires major planning, which is the reason why, for the time being, we are limited to reusing a simple dissociated list of checkboxes for all WUE options.
This commit is contained in:
parent
5117a3b4a8
commit
9073962faf
10 changed files with 204 additions and 127 deletions
|
@ -590,6 +590,8 @@ t MSG_329 "Remove requirement for 4GB+ RAM and 64GB+ disk"
|
||||||
t MSG_330 "Remove requirement for an online Microsoft account"
|
t MSG_330 "Remove requirement for an online Microsoft account"
|
||||||
t MSG_331 "Disable data collection (Skip privacy questions)"
|
t MSG_331 "Disable data collection (Skip privacy questions)"
|
||||||
t MSG_332 "Prevent Windows To Go from accessing internal disks"
|
t MSG_332 "Prevent Windows To Go from accessing internal disks"
|
||||||
|
t MSG_333 "Set a local account using the same name as this user's"
|
||||||
|
t MSG_334 "Set regional options to the same values as this user's"
|
||||||
|
|
||||||
#########################################################################
|
#########################################################################
|
||||||
l "ar-SA" "Arabic (العربية)" 0x0401, 0x0801, 0x0c01, 0x1001, 0x1401, 0x1801, 0x1c01, 0x2001, 0x2401, 0x2801, 0x2c01, 0x3001, 0x3401, 0x3801, 0x3c01, 0x4001
|
l "ar-SA" "Arabic (العربية)" 0x0401, 0x0801, 0x0c01, 0x1001, 0x1401, 0x1801, 0x1c01, 0x2001, 0x2401, 0x2801, 0x2c01, 0x3001, 0x3401, 0x3801, 0x3c01, 0x4001
|
||||||
|
|
28
src/format.c
28
src/format.c
|
@ -71,7 +71,7 @@ extern const int nb_steps[FS_MAX];
|
||||||
extern uint32_t dur_mins, dur_secs;
|
extern uint32_t dur_mins, dur_secs;
|
||||||
extern uint32_t wim_nb_files, wim_proc_files, wim_extra_files;
|
extern uint32_t wim_nb_files, wim_proc_files, wim_extra_files;
|
||||||
static int actual_fs_type, wintogo_index = -1, wininst_index = 0;
|
static int actual_fs_type, wintogo_index = -1, wininst_index = 0;
|
||||||
extern int unattend_xml_selection;
|
extern int unattend_xml_flags;
|
||||||
extern BOOL force_large_fat32, enable_ntfs_compression, lock_drive, zero_drive, fast_zeroing, enable_file_indexing;
|
extern BOOL force_large_fat32, enable_ntfs_compression, lock_drive, zero_drive, fast_zeroing, enable_file_indexing;
|
||||||
extern BOOL write_as_image, use_vds, write_as_esp, is_vds_available;
|
extern BOOL write_as_image, use_vds, write_as_esp, is_vds_available;
|
||||||
extern const grub_patch_t grub_patch[2];
|
extern const grub_patch_t grub_patch[2];
|
||||||
|
@ -1472,7 +1472,7 @@ static BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp)
|
||||||
// "upgrade" the ReFS version on all drives to v3.7, thereby preventing you from being able to mount
|
// "upgrade" the ReFS version on all drives to v3.7, thereby preventing you from being able to mount
|
||||||
// those volumes back on Windows 10 ever again. Yes, I have been stung by this Microsoft bullshit!
|
// those volumes back on Windows 10 ever again. Yes, I have been stung by this Microsoft bullshit!
|
||||||
// See: https://gist.github.com/0xbadfca11/da0598e47dd643d933dc#Mountability
|
// See: https://gist.github.com/0xbadfca11/da0598e47dd643d933dc#Mountability
|
||||||
if (unattend_xml_selection & UNATTEND_OFFLINE_INTERNAL_DRIVES) {
|
if (unattend_xml_flags & UNATTEND_OFFLINE_INTERNAL_DRIVES) {
|
||||||
uprintf("Setting the target's internal drives offline using command:");
|
uprintf("Setting the target's internal drives offline using command:");
|
||||||
// This applies the "offlineServicing" section of the unattend.xml (while ignoring the other sections)
|
// This applies the "offlineServicing" section of the unattend.xml (while ignoring the other sections)
|
||||||
static_sprintf(cmd, "dism /Image:%s\\ /Apply-Unattend:%s", drive_name, unattend_xml_path);
|
static_sprintf(cmd, "dism /Image:%s\\ /Apply-Unattend:%s", drive_name, unattend_xml_path);
|
||||||
|
@ -1498,9 +1498,9 @@ static BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add unattend.xml to 'sources\boot.wim' (install) or 'Windows\Panther\' (Windows To Go)
|
* Add unattend.xml to 'sources\boot.wim' (install) or 'Windows\Panther\' (Windows To Go)
|
||||||
* NB: Work with a copy of unattend_xml_selection as a paremeter since we will modify it.
|
* NB: Work with a copy of unattend_xml_flags as a paremeter since we will modify it.
|
||||||
*/
|
*/
|
||||||
BOOL ApplyWindowsCustomization(char drive_letter, int unattend_selection)
|
BOOL ApplyWindowsCustomization(char drive_letter, int flags)
|
||||||
{
|
{
|
||||||
BOOL r = FALSE, is_hive_mounted = FALSE;
|
BOOL r = FALSE, is_hive_mounted = FALSE;
|
||||||
int i;
|
int i;
|
||||||
|
@ -1516,7 +1516,7 @@ BOOL ApplyWindowsCustomization(char drive_letter, int unattend_selection)
|
||||||
|
|
||||||
assert(unattend_xml_path != NULL);
|
assert(unattend_xml_path != NULL);
|
||||||
uprintf("Applying Windows customization:");
|
uprintf("Applying Windows customization:");
|
||||||
if (unattend_selection & UNATTEND_WINDOWS_TO_GO) {
|
if (flags & UNATTEND_WINDOWS_TO_GO) {
|
||||||
static_sprintf(path, "%c:\\Windows\\Panther", drive_letter);
|
static_sprintf(path, "%c:\\Windows\\Panther", drive_letter);
|
||||||
if (!CreateDirectoryA(path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {
|
if (!CreateDirectoryA(path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {
|
||||||
uprintf("Could not create '%s' : %s", path, WindowsErrorString());
|
uprintf("Could not create '%s' : %s", path, WindowsErrorString());
|
||||||
|
@ -1530,7 +1530,7 @@ BOOL ApplyWindowsCustomization(char drive_letter, int unattend_selection)
|
||||||
uprintf("Added '%s'", path);
|
uprintf("Added '%s'", path);
|
||||||
} else {
|
} else {
|
||||||
boot_wim_path[0] = drive_letter;
|
boot_wim_path[0] = drive_letter;
|
||||||
if (unattend_selection & UNATTEND_WINPE_SETUP_MASK) {
|
if (flags & UNATTEND_WINPE_SETUP_MASK) {
|
||||||
// Create a backup of sources\appraiserres.dll and then create an empty file to
|
// Create a backup of sources\appraiserres.dll and then create an empty file to
|
||||||
// allow in-place upgrades without TPM/SB. Note that we need to create an empty,
|
// allow in-place upgrades without TPM/SB. Note that we need to create an empty,
|
||||||
// appraiserres.dll otherwise setup.exe extracts its own.
|
// appraiserres.dll otherwise setup.exe extracts its own.
|
||||||
|
@ -1547,14 +1547,14 @@ BOOL ApplyWindowsCustomization(char drive_letter, int unattend_selection)
|
||||||
UpdateProgressWithInfoForce(OP_PATCH, MSG_325, 0, PATCH_PROGRESS_TOTAL);
|
UpdateProgressWithInfoForce(OP_PATCH, MSG_325, 0, PATCH_PROGRESS_TOTAL);
|
||||||
// We only need to mount boot.wim if we have windowsPE data to deal with. If
|
// We only need to mount boot.wim if we have windowsPE data to deal with. If
|
||||||
// not, we can just copy our unattend.xml in \sources\$OEM$\$$\Panther\.
|
// not, we can just copy our unattend.xml in \sources\$OEM$\$$\Panther\.
|
||||||
if (unattend_selection & UNATTEND_WINPE_SETUP_MASK) {
|
if (flags & UNATTEND_WINPE_SETUP_MASK) {
|
||||||
uprintf("Mounting '%s'...", boot_wim_path);
|
uprintf("Mounting '%s'...", boot_wim_path);
|
||||||
mount_path = WimMountImage(boot_wim_path, wim_index);
|
mount_path = WimMountImage(boot_wim_path, wim_index);
|
||||||
if (mount_path == NULL)
|
if (mount_path == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unattend_selection & (UNATTEND_SECUREBOOT_TPM_MASK | UNATTEND_MINRAM_MINDISK_MASK)) {
|
if (flags & (UNATTEND_SECUREBOOT_TPM | UNATTEND_MINRAM_MINDISK)) {
|
||||||
// Try to create the registry keys directly, and fallback to using unattend
|
// Try to create the registry keys directly, and fallback to using unattend
|
||||||
// if that fails (which the Windows Store version is expected to do).
|
// if that fails (which the Windows Store version is expected to do).
|
||||||
static_sprintf(path, "%s\\Windows\\System32\\config\\SYSTEM", mount_path);
|
static_sprintf(path, "%s\\Windows\\System32\\config\\SYSTEM", mount_path);
|
||||||
|
@ -1582,7 +1582,7 @@ BOOL ApplyWindowsCustomization(char drive_letter, int unattend_selection)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ARRAYSIZE(bypass_name); i++) {
|
for (i = 0; i < ARRAYSIZE(bypass_name); i++) {
|
||||||
if (!(unattend_selection & (1 << (i / 2))))
|
if (!(flags & (1 << (i / 2))))
|
||||||
continue;
|
continue;
|
||||||
status = RegSetValueExA(hSubKey, bypass_name[i], 0, REG_DWORD, (LPBYTE)&dwVal, sizeof(DWORD));
|
status = RegSetValueExA(hSubKey, bypass_name[i], 0, REG_DWORD, (LPBYTE)&dwVal, sizeof(DWORD));
|
||||||
if (status != ERROR_SUCCESS) {
|
if (status != ERROR_SUCCESS) {
|
||||||
|
@ -1596,11 +1596,11 @@ BOOL ApplyWindowsCustomization(char drive_letter, int unattend_selection)
|
||||||
// We were successfull in creating the keys so disable the windowsPE section from unattend.xml
|
// We were successfull in creating the keys so disable the windowsPE section from unattend.xml
|
||||||
// We do this by replacing '<settings pass="windowsPE">' with '<settings pass="disabled">'
|
// We do this by replacing '<settings pass="windowsPE">' with '<settings pass="disabled">'
|
||||||
// (provided that the registry key creation was the only item for this pass)
|
// (provided that the registry key creation was the only item for this pass)
|
||||||
if ((unattend_selection & UNATTEND_WINPE_SETUP_MASK) == (UNATTEND_SECUREBOOT_TPM_MASK | UNATTEND_MINRAM_MINDISK_MASK)) {
|
if ((flags & UNATTEND_WINPE_SETUP_MASK) == (UNATTEND_SECUREBOOT_TPM | UNATTEND_MINRAM_MINDISK)) {
|
||||||
if (replace_in_token_data(unattend_xml_path, "<settings", "windowsPE", "disabled", FALSE) == NULL)
|
if (replace_in_token_data(unattend_xml_path, "<settings", "windowsPE", "disabled", FALSE) == NULL)
|
||||||
uprintf("Warning: Could not disable 'windowsPE' pass from unattend.xml");
|
uprintf("Warning: Could not disable 'windowsPE' pass from unattend.xml");
|
||||||
// Remove the flags, since we accomplished the registry creation outside of unattend.
|
// Remove the flags, since we accomplished the registry creation outside of unattend.
|
||||||
unattend_selection &= ~(UNATTEND_SECUREBOOT_TPM_MASK | UNATTEND_MINRAM_MINDISK_MASK);
|
flags &= ~(UNATTEND_SECUREBOOT_TPM | UNATTEND_MINRAM_MINDISK);
|
||||||
} else {
|
} else {
|
||||||
// TODO: If we add other tasks besides LabConfig reg keys, we'll need to figure out how
|
// TODO: If we add other tasks besides LabConfig reg keys, we'll need to figure out how
|
||||||
// to comment out the <RunSynchronous> entries from windowsPE (and only windowsPE).
|
// to comment out the <RunSynchronous> entries from windowsPE (and only windowsPE).
|
||||||
|
@ -1610,7 +1610,7 @@ BOOL ApplyWindowsCustomization(char drive_letter, int unattend_selection)
|
||||||
}
|
}
|
||||||
|
|
||||||
copy_unattend:
|
copy_unattend:
|
||||||
if (unattend_selection & UNATTEND_WINPE_SETUP_MASK) {
|
if (flags & UNATTEND_WINPE_SETUP_MASK) {
|
||||||
// If we have a windowsPE section, copy the answer files to the root of boot.wim as
|
// If we have a windowsPE section, copy the answer files to the root of boot.wim as
|
||||||
// Autounattend.xml. This also results in that file being automatically copied over
|
// Autounattend.xml. This also results in that file being automatically copied over
|
||||||
// to %WINDIR%\Panther\unattend.xml for later passes processing.
|
// to %WINDIR%\Panther\unattend.xml for later passes processing.
|
||||||
|
@ -2452,7 +2452,7 @@ DWORD WINAPI FormatThread(void* param)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (unattend_xml_path != NULL) {
|
if (unattend_xml_path != NULL) {
|
||||||
if (!ApplyWindowsCustomization(drive_name[0], unattend_xml_selection | UNATTEND_WINDOWS_TO_GO))
|
if (!ApplyWindowsCustomization(drive_name[0], unattend_xml_flags | UNATTEND_WINDOWS_TO_GO))
|
||||||
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_PATCH);
|
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_PATCH);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -2494,7 +2494,7 @@ DWORD WINAPI FormatThread(void* param)
|
||||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH);
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH);
|
||||||
}
|
}
|
||||||
if (unattend_xml_path != NULL) {
|
if (unattend_xml_path != NULL) {
|
||||||
if (!ApplyWindowsCustomization(drive_name[0], unattend_xml_selection))
|
if (!ApplyWindowsCustomization(drive_name[0], unattend_xml_flags))
|
||||||
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_PATCH);
|
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_PATCH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*
|
*
|
||||||
* See also: https://utf8everywhere.org
|
* See also: https://utf8everywhere.org
|
||||||
*
|
*
|
||||||
* Copyright © 2010-2021 Pete Batard <pete@akeo.ie>
|
* Copyright © 2010-2022 Pete Batard <pete@akeo.ie>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -1240,6 +1240,33 @@ static __inline BOOL SetupDiGetDeviceRegistryPropertyU(HDEVINFO DeviceInfoSet, P
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NB: This does not support the ERROR_INSUFFICIENT_BUFFER dance to retrieve the required buffer size
|
||||||
|
static __inline BOOL GetUserNameU(LPSTR lpBuffer, LPDWORD pcbBuffer)
|
||||||
|
{
|
||||||
|
BOOL ret;
|
||||||
|
DWORD err, size;
|
||||||
|
if (lpBuffer == NULL || pcbBuffer == NULL) {
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
size = *pcbBuffer;
|
||||||
|
// coverity[returned_null]
|
||||||
|
walloc(lpBuffer, size);
|
||||||
|
ret = GetUserNameW(wlpBuffer, &size);
|
||||||
|
err = GetLastError();
|
||||||
|
if (ret) {
|
||||||
|
*pcbBuffer = (DWORD)wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, size);
|
||||||
|
if (*pcbBuffer == 0)
|
||||||
|
err = GetLastError();
|
||||||
|
else
|
||||||
|
// Reported size includes the NUL terminator
|
||||||
|
(*pcbBuffer)++;
|
||||||
|
}
|
||||||
|
wfree(lpBuffer);
|
||||||
|
SetLastError(err);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static __inline BOOL GetVolumeInformationU(LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer,
|
static __inline BOOL GetVolumeInformationU(LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer,
|
||||||
DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength,
|
DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength,
|
||||||
LPDWORD lpFileSystemFlags, LPSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize)
|
LPDWORD lpFileSystemFlags, LPSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Rufus: The Reliable USB Formatting Utility
|
* Rufus: The Reliable USB Formatting Utility
|
||||||
* Registry access
|
* Registry access
|
||||||
* Copyright © 2012-2015 Pete Batard <pete@akeo.ie>
|
* Copyright © 2012-2022 Pete Batard <pete@akeo.ie>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
#include "rufus.h"
|
#include "rufus.h"
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
@ -36,9 +37,15 @@ static __inline BOOL DeleteRegistryKey(HKEY key_root, const char* key_name)
|
||||||
HKEY hSoftware = NULL;
|
HKEY hSoftware = NULL;
|
||||||
LONG s;
|
LONG s;
|
||||||
|
|
||||||
if (RegOpenKeyExA(key_root, "SOFTWARE", 0, KEY_READ|KEY_CREATE_SUB_KEY, &hSoftware) != ERROR_SUCCESS) {
|
assert(key_root == REGKEY_HKCU);
|
||||||
|
if (key_root != REGKEY_HKCU)
|
||||||
|
return FALSE;
|
||||||
|
assert(key_name != NULL);
|
||||||
|
if (key_name == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (RegOpenKeyExA(key_root, "SOFTWARE", 0, KEY_READ|KEY_CREATE_SUB_KEY, &hSoftware) != ERROR_SUCCESS)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
|
||||||
|
|
||||||
s = RegDeleteKeyA(hSoftware, key_name);
|
s = RegDeleteKeyA(hSoftware, key_name);
|
||||||
if ((s != ERROR_SUCCESS) && (s != ERROR_FILE_NOT_FOUND)) {
|
if ((s != ERROR_SUCCESS) && (s != ERROR_FILE_NOT_FOUND)) {
|
||||||
|
@ -68,7 +75,6 @@ static __inline BOOL IsRegistryNode(HKEY key_root, const char* key_name)
|
||||||
static __inline BOOL _GetRegistryKey(HKEY key_root, const char* key_name, DWORD reg_type,
|
static __inline BOOL _GetRegistryKey(HKEY key_root, const char* key_name, DWORD reg_type,
|
||||||
LPBYTE dest, DWORD dest_size)
|
LPBYTE dest, DWORD dest_size)
|
||||||
{
|
{
|
||||||
const char software_prefix[] = "SOFTWARE\\";
|
|
||||||
char long_key_name[MAX_PATH] = { 0 };
|
char long_key_name[MAX_PATH] = { 0 };
|
||||||
BOOL r = FALSE;
|
BOOL r = FALSE;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
@ -87,19 +93,11 @@ static __inline BOOL _GetRegistryKey(HKEY key_root, const char* key_name, DWORD
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
// Prefix with "SOFTWARE" if needed
|
// For a read operation, allow access to any long key
|
||||||
if (_strnicmp(key_name, software_prefix, sizeof(software_prefix) - 1) != 0) {
|
|
||||||
if (i + sizeof(software_prefix) >= sizeof(long_key_name))
|
|
||||||
return FALSE;
|
|
||||||
strcpy(long_key_name, software_prefix);
|
|
||||||
static_strcat(long_key_name, key_name);
|
|
||||||
long_key_name[sizeof(software_prefix) + i - 1] = 0;
|
|
||||||
} else {
|
|
||||||
if (i >= sizeof(long_key_name))
|
if (i >= sizeof(long_key_name))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
static_strcpy(long_key_name, key_name);
|
static_strcpy(long_key_name, key_name);
|
||||||
long_key_name[i] = 0;
|
long_key_name[i] = 0;
|
||||||
}
|
|
||||||
i++;
|
i++;
|
||||||
if (RegOpenKeyExA(key_root, long_key_name, 0, KEY_READ, &hApp) != ERROR_SUCCESS) {
|
if (RegOpenKeyExA(key_root, long_key_name, 0, KEY_READ, &hApp) != ERROR_SUCCESS) {
|
||||||
hApp = NULL;
|
hApp = NULL;
|
||||||
|
@ -133,57 +131,34 @@ out:
|
||||||
/* Write a generic registry key value (create the key if it doesn't exist) */
|
/* Write a generic registry key value (create the key if it doesn't exist) */
|
||||||
static __inline BOOL _SetRegistryKey(HKEY key_root, const char* key_name, DWORD reg_type, LPBYTE src, DWORD src_size)
|
static __inline BOOL _SetRegistryKey(HKEY key_root, const char* key_name, DWORD reg_type, LPBYTE src, DWORD src_size)
|
||||||
{
|
{
|
||||||
const char software_prefix[] = "SOFTWARE\\";
|
|
||||||
char long_key_name[MAX_PATH] = { 0 };
|
|
||||||
BOOL r = FALSE;
|
BOOL r = FALSE;
|
||||||
size_t i;
|
|
||||||
HKEY hRoot = NULL, hApp = NULL;
|
HKEY hRoot = NULL, hApp = NULL;
|
||||||
DWORD dwDisp, dwType = reg_type;
|
DWORD dwDisp, dwType = reg_type;
|
||||||
|
|
||||||
|
assert(key_name != NULL);
|
||||||
if (key_name == NULL)
|
if (key_name == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
assert(key_root == REGKEY_HKCU);
|
||||||
|
if (key_root != REGKEY_HKCU)
|
||||||
|
return FALSE;
|
||||||
|
// Validate that we are always dealing with a short key
|
||||||
|
assert(strchr(key_name, '\\') == NULL);
|
||||||
|
if (strchr(key_name, '\\') != NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
if (RegOpenKeyExA(key_root, NULL, 0, KEY_READ|KEY_CREATE_SUB_KEY, &hRoot) != ERROR_SUCCESS) {
|
if (RegOpenKeyExA(key_root, NULL, 0, KEY_READ|KEY_CREATE_SUB_KEY, &hRoot) != ERROR_SUCCESS) {
|
||||||
hRoot = NULL;
|
hRoot = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find if we're dealing with a short key
|
|
||||||
for (i = safe_strlen(key_name); i > 0; i--) {
|
|
||||||
if (key_name[i] == '\\')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i > 0) {
|
|
||||||
// Prefix with "SOFTWARE" if needed
|
|
||||||
if (_strnicmp(key_name, software_prefix, sizeof(software_prefix) - 1) != 0) {
|
|
||||||
if (i + sizeof(software_prefix) >= sizeof(long_key_name))
|
|
||||||
goto out;
|
|
||||||
strcpy(long_key_name, software_prefix);
|
|
||||||
static_strcat(long_key_name, key_name);
|
|
||||||
long_key_name[sizeof(software_prefix) + i - 1] = 0;
|
|
||||||
} else {
|
|
||||||
if (i >= sizeof(long_key_name))
|
|
||||||
goto out;
|
|
||||||
static_strcpy(long_key_name, key_name);
|
|
||||||
long_key_name[i] = 0;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
if (RegCreateKeyExA(hRoot, long_key_name, 0, NULL, 0,
|
|
||||||
KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_CREATE_SUB_KEY, NULL, &hApp, &dwDisp) != ERROR_SUCCESS) {
|
|
||||||
hApp = NULL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// This is a short key name, store the value under our app sub-hive
|
// This is a short key name, store the value under our app sub-hive
|
||||||
if (RegCreateKeyExA(hRoot, "SOFTWARE\\" COMPANY_NAME "\\" APPLICATION_NAME, 0, NULL, 0,
|
if (RegCreateKeyExA(hRoot, "SOFTWARE\\" COMPANY_NAME "\\" APPLICATION_NAME, 0, NULL, 0,
|
||||||
KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_CREATE_SUB_KEY, NULL, &hApp, &dwDisp) != ERROR_SUCCESS) {
|
KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_CREATE_SUB_KEY, NULL, &hApp, &dwDisp) != ERROR_SUCCESS) {
|
||||||
hApp = NULL;
|
hApp = NULL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
r = (RegSetValueExA(hApp, &key_name[i], 0, dwType, src, src_size) == ERROR_SUCCESS);
|
r = (RegSetValueExA(hApp, key_name, 0, dwType, src, src_size) == ERROR_SUCCESS);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (hRoot != NULL)
|
if (hRoot != NULL)
|
||||||
|
|
115
src/rufus.c
115
src/rufus.c
|
@ -78,7 +78,7 @@ static BOOL app_changed_label = FALSE;
|
||||||
static BOOL allowed_filesystem[FS_MAX] = { 0 };
|
static BOOL allowed_filesystem[FS_MAX] = { 0 };
|
||||||
static int64_t last_iso_blocking_status;
|
static int64_t last_iso_blocking_status;
|
||||||
static int selected_pt = -1, selected_fs = FS_UNKNOWN, preselected_fs = FS_UNKNOWN;
|
static int selected_pt = -1, selected_fs = FS_UNKNOWN, preselected_fs = FS_UNKNOWN;
|
||||||
static int image_index = 0, select_index = 0, unattend_xml_mask = UNATTEND_DEFAULT_SELECTION;
|
static int image_index = 0, select_index = 0, unattend_xml_mask = UNATTEND_DEFAULT_SELECTION_MASK;
|
||||||
static RECT relaunch_rc = { -65536, -65536, 0, 0};
|
static RECT relaunch_rc = { -65536, -65536, 0, 0};
|
||||||
static UINT uMBRChecked = BST_UNCHECKED;
|
static UINT uMBRChecked = BST_UNCHECKED;
|
||||||
static HANDLE format_thread = NULL;
|
static HANDLE format_thread = NULL;
|
||||||
|
@ -125,7 +125,7 @@ BOOL write_as_image = FALSE, write_as_esp = FALSE, use_vds = FALSE, ignore_boot_
|
||||||
BOOL appstore_version = FALSE, is_vds_available = TRUE;
|
BOOL appstore_version = FALSE, is_vds_available = TRUE;
|
||||||
float fScale = 1.0f;
|
float fScale = 1.0f;
|
||||||
int dialog_showing = 0, selection_default = BT_IMAGE, persistence_unit_selection = -1, imop_win_sel = 0;
|
int dialog_showing = 0, selection_default = BT_IMAGE, persistence_unit_selection = -1, imop_win_sel = 0;
|
||||||
int default_fs, fs_type, boot_type, partition_type, target_type, unattend_xml_selection = 0;
|
int default_fs, fs_type, boot_type, partition_type, target_type, unattend_xml_flags = 0;
|
||||||
int force_update = 0, default_thread_priority = THREAD_PRIORITY_ABOVE_NORMAL;
|
int force_update = 0, default_thread_priority = THREAD_PRIORITY_ABOVE_NORMAL;
|
||||||
char szFolderPath[MAX_PATH], app_dir[MAX_PATH], system_dir[MAX_PATH], temp_dir[MAX_PATH], sysnative_dir[MAX_PATH];
|
char szFolderPath[MAX_PATH], app_dir[MAX_PATH], system_dir[MAX_PATH], temp_dir[MAX_PATH], sysnative_dir[MAX_PATH];
|
||||||
char app_data_dir[MAX_PATH], user_dir[MAX_PATH];
|
char app_data_dir[MAX_PATH], user_dir[MAX_PATH];
|
||||||
|
@ -1250,14 +1250,21 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* CreateUnattendXml(int arch, int mask)
|
/// <summary>
|
||||||
|
/// Create an installation answer file containing the sections specified by the flags.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="arch">The processor architecture of the Windows image being used.</param>
|
||||||
|
/// <param name="flags">A bitmask representing the sections to enable.
|
||||||
|
/// See "Windows User Experience flags and masks" from in rufus.h</param>
|
||||||
|
/// <returns>The path of a newly created answer file on success or NULL on error.</returns>
|
||||||
|
static char* CreateUnattendXml(int arch, int flags)
|
||||||
{
|
{
|
||||||
static char path[MAX_PATH];
|
static char path[MAX_PATH];
|
||||||
FILE* fd;
|
FILE* fd;
|
||||||
int i, order;
|
int i, order;
|
||||||
const char* xml_arch_names[5] = { "x86", "amd64", "arm", "arm64" };
|
const char* xml_arch_names[5] = { "x86", "amd64", "arm", "arm64" };
|
||||||
unattend_xml_selection = mask;
|
unattend_xml_flags = flags;
|
||||||
if (arch < ARCH_X86_32 || arch >= ARCH_ARM_64 || mask == 0)
|
if (arch < ARCH_X86_32 || arch >= ARCH_ARM_64 || flags == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
arch--;
|
arch--;
|
||||||
// coverity[swapped_arguments]
|
// coverity[swapped_arguments]
|
||||||
|
@ -1274,7 +1281,7 @@ static char* CreateUnattendXml(int arch, int mask)
|
||||||
// as alters the layout and options of the initial Windows installer screens, which may scare users.
|
// as alters the layout and options of the initial Windows installer screens, which may scare users.
|
||||||
// So, in format.c, we'll try to insert the registry keys directly and drop this section. However,
|
// So, in format.c, we'll try to insert the registry keys directly and drop this section. However,
|
||||||
// because Microsoft prevents Store apps from editing an offline registry, we do need this fallback.
|
// because Microsoft prevents Store apps from editing an offline registry, we do need this fallback.
|
||||||
if (mask & UNATTEND_WINPE_SETUP_MASK) {
|
if (flags & UNATTEND_WINPE_SETUP_MASK) {
|
||||||
order = 1;
|
order = 1;
|
||||||
fprintf(fd, " <settings pass=\"windowsPE\">\n");
|
fprintf(fd, " <settings pass=\"windowsPE\">\n");
|
||||||
fprintf(fd, " <component name=\"Microsoft-Windows-Setup\" processorArchitecture=\"%s\" language=\"neutral\" "
|
fprintf(fd, " <component name=\"Microsoft-Windows-Setup\" processorArchitecture=\"%s\" language=\"neutral\" "
|
||||||
|
@ -1288,7 +1295,7 @@ static char* CreateUnattendXml(int arch, int mask)
|
||||||
fprintf(fd, " </UserData>\n");
|
fprintf(fd, " </UserData>\n");
|
||||||
fprintf(fd, " <RunSynchronous>\n");
|
fprintf(fd, " <RunSynchronous>\n");
|
||||||
for (i = 0; i < ARRAYSIZE(bypass_name); i++) {
|
for (i = 0; i < ARRAYSIZE(bypass_name); i++) {
|
||||||
if (!(mask & (1 << (i/2))))
|
if (!(flags & (1 << (i/2))))
|
||||||
continue;
|
continue;
|
||||||
fprintf(fd, " <RunSynchronousCommand wcm:action=\"add\">\n");
|
fprintf(fd, " <RunSynchronousCommand wcm:action=\"add\">\n");
|
||||||
fprintf(fd, " <Order>%d</Order>\n", order++);
|
fprintf(fd, " <Order>%d</Order>\n", order++);
|
||||||
|
@ -1300,7 +1307,7 @@ static char* CreateUnattendXml(int arch, int mask)
|
||||||
fprintf(fd, " </settings>\n");
|
fprintf(fd, " </settings>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mask & UNATTEND_SPECIALIZE_DEPLOYMENT_MASK) {
|
if (flags & UNATTEND_SPECIALIZE_DEPLOYMENT_MASK) {
|
||||||
order = 1;
|
order = 1;
|
||||||
fprintf(fd, " <settings pass=\"specialize\">\n");
|
fprintf(fd, " <settings pass=\"specialize\">\n");
|
||||||
fprintf(fd, " <component name=\"Microsoft-Windows-Deployment\" processorArchitecture=\"%s\" language=\"neutral\" "
|
fprintf(fd, " <component name=\"Microsoft-Windows-Deployment\" processorArchitecture=\"%s\" language=\"neutral\" "
|
||||||
|
@ -1308,7 +1315,7 @@ static char* CreateUnattendXml(int arch, int mask)
|
||||||
"publicKeyToken=\"31bf3856ad364e35\" versionScope=\"nonSxS\">\n", xml_arch_names[arch]);
|
"publicKeyToken=\"31bf3856ad364e35\" versionScope=\"nonSxS\">\n", xml_arch_names[arch]);
|
||||||
fprintf(fd, " <RunSynchronous>\n");
|
fprintf(fd, " <RunSynchronous>\n");
|
||||||
// This part was picked from https://github.com/AveYo/MediaCreationTool.bat/blob/main/bypass11/AutoUnattend.xml
|
// This part was picked from https://github.com/AveYo/MediaCreationTool.bat/blob/main/bypass11/AutoUnattend.xml
|
||||||
if (mask & UNATTEND_NO_ONLINE_ACCOUNT_MASK) {
|
if (flags & UNATTEND_NO_ONLINE_ACCOUNT) {
|
||||||
fprintf(fd, " <RunSynchronousCommand wcm:action=\"add\">\n");
|
fprintf(fd, " <RunSynchronousCommand wcm:action=\"add\">\n");
|
||||||
fprintf(fd, " <Order>%d</Order>\n", order++);
|
fprintf(fd, " <Order>%d</Order>\n", order++);
|
||||||
fprintf(fd, " <Path>reg add HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\OOBE /v BypassNRO /t REG_DWORD /d 1 /f</Path>\n");
|
fprintf(fd, " <Path>reg add HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\OOBE /v BypassNRO /t REG_DWORD /d 1 /f</Path>\n");
|
||||||
|
@ -1319,27 +1326,82 @@ static char* CreateUnattendXml(int arch, int mask)
|
||||||
fprintf(fd, " </settings>\n");
|
fprintf(fd, " </settings>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mask & UNATTEND_OOBE_SHELL_SETUP) {
|
if (flags & UNATTEND_OOBE_MASK) {
|
||||||
order = 1;
|
order = 1;
|
||||||
fprintf(fd, " <settings pass=\"oobeSystem\">\n");
|
fprintf(fd, " <settings pass=\"oobeSystem\">\n");
|
||||||
|
if (flags & UNATTEND_OOBE_SHELL_SETUP_MASK) {
|
||||||
fprintf(fd, " <component name=\"Microsoft-Windows-Shell-Setup\" processorArchitecture=\"%s\" language=\"neutral\" "
|
fprintf(fd, " <component name=\"Microsoft-Windows-Shell-Setup\" processorArchitecture=\"%s\" language=\"neutral\" "
|
||||||
"xmlns:wcm=\"http://schemas.microsoft.com/WMIConfig/2002/State\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
"xmlns:wcm=\"http://schemas.microsoft.com/WMIConfig/2002/State\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
||||||
"publicKeyToken=\"31bf3856ad364e35\" versionScope=\"nonSxS\">\n", xml_arch_names[arch]);
|
"publicKeyToken=\"31bf3856ad364e35\" versionScope=\"nonSxS\">\n", xml_arch_names[arch]);
|
||||||
// https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-shell-setup-oobe-protectyourpc
|
// https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-shell-setup-oobe-protectyourpc
|
||||||
// It is really super insidous of Microsoft to call this option "ProtectYourPC", when it's really only about
|
// It is really super insidous of Microsoft to call this option "ProtectYourPC", when it's really only about
|
||||||
// data collection. But of course, if it was called "AllowDataCollection", everyone would turn it off...
|
// data collection. But of course, if it was called "AllowDataCollection", everyone would turn it off...
|
||||||
if (mask & UNATTEND_NO_DATA_COLLECTION_MASK) {
|
if (flags & UNATTEND_NO_DATA_COLLECTION) {
|
||||||
fprintf(fd, " <OOBE>\n");
|
fprintf(fd, " <OOBE>\n");
|
||||||
fprintf(fd, " <ProtectYourPC>3</ProtectYourPC>\n");
|
fprintf(fd, " <ProtectYourPC>3</ProtectYourPC>\n");
|
||||||
fprintf(fd, " </OOBE>\n");
|
fprintf(fd, " </OOBE>\n");
|
||||||
}
|
}
|
||||||
|
if (flags & UNATTEND_DUPLICATE_USER) {
|
||||||
|
order = 1;
|
||||||
|
char username[128] = { 0 };
|
||||||
|
DWORD size = sizeof(username);
|
||||||
|
if (GetUserNameU(username, &size) && username[0] != 0) {
|
||||||
|
// If we create a local account in unattend.xml, then we can get Windows 11
|
||||||
|
// 22H2 to skip MSA even if the network is connected during installation.
|
||||||
|
fprintf(fd, " <UserAccounts>\n");
|
||||||
|
fprintf(fd, " <LocalAccounts>\n");
|
||||||
|
fprintf(fd, " <LocalAccount wcm:action=\"add\">\n");
|
||||||
|
fprintf(fd, " <Name>%s</Name>\n", username);
|
||||||
|
fprintf(fd, " <DisplayName>%s</DisplayName>\n", username);
|
||||||
|
fprintf(fd, " <Group>Administrators;Power Users</Group>\n");
|
||||||
|
// Sets an empty password for the account (which, in Microsoft's convoluted ways,
|
||||||
|
// needs to be initialized to the Base64 encoded UTF-16 string "Password").
|
||||||
|
// The use of an empty password has both the advantage of not having to ask users
|
||||||
|
// to type in a password in Rufus (which they might be weary of) as well as allowing
|
||||||
|
// automated logon during setup.
|
||||||
|
fprintf(fd, " <Password>\n");
|
||||||
|
fprintf(fd, " <Value>UABhAHMAcwB3AG8AcgBkAA==</Value>\n");
|
||||||
|
fprintf(fd, " <PlainText>false</PlainText>\n");
|
||||||
|
fprintf(fd, " </Password>\n");
|
||||||
|
fprintf(fd, " </LocalAccount>\n");
|
||||||
|
fprintf(fd, " </LocalAccounts>\n");
|
||||||
|
fprintf(fd, " </UserAccounts>\n");
|
||||||
|
// Since we set a blank password, we'll ask the user to change it at next logon.
|
||||||
|
fprintf(fd, " <FirstLogonCommands>\n");
|
||||||
|
fprintf(fd, " <SynchronousCommand wcm:action=\"add\">\n");
|
||||||
|
fprintf(fd, " <Order>%d</Order>\n", order++);
|
||||||
|
fprintf(fd, " <CommandLine>net user "%s" /logonpasswordchg:yes</CommandLine>\n", username);
|
||||||
|
fprintf(fd, " </SynchronousCommand>\n");
|
||||||
|
fprintf(fd, " </FirstLogonCommands>\n");
|
||||||
|
} else {
|
||||||
|
uprintf("Warning: Could not retreive current user name. Local Account was not created");
|
||||||
|
}
|
||||||
|
}
|
||||||
fprintf(fd, " </component>\n");
|
fprintf(fd, " </component>\n");
|
||||||
|
}
|
||||||
|
if (flags & UNATTEND_OOBE_INTERNATIONAL_MASK) {
|
||||||
|
fprintf(fd, " <component name=\"Microsoft-Windows-International-Core\" processorArchitecture=\"%s\" language=\"neutral\" "
|
||||||
|
"xmlns:wcm=\"http://schemas.microsoft.com/WMIConfig/2002/State\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
||||||
|
"publicKeyToken=\"31bf3856ad364e35\" versionScope=\"nonSxS\">\n", xml_arch_names[arch]);
|
||||||
|
// What a frigging mess retreiving and trying to match the various locales
|
||||||
|
// Microsoft has made. And, *NO*, the new User Language Settings have not
|
||||||
|
// improved things in the slightest. They made it much worse for developers!
|
||||||
|
fprintf(fd, " <InputLocale>%s</InputLocale>\n",
|
||||||
|
ReadRegistryKeyStr(REGKEY_HKCU, "Keyboard Layout\\Preload\\1"));
|
||||||
|
fprintf(fd, " <SystemLocale>%s</SystemLocale>\n", ToLocaleName(GetSystemDefaultLCID()));
|
||||||
|
fprintf(fd, " <UserLocale>%s</UserLocale>\n", ToLocaleName(GetUserDefaultLCID()));
|
||||||
|
fprintf(fd, " <UILanguage>%s</UILanguage>\n", ToLocaleName(GetUserDefaultUILanguage()));
|
||||||
|
fprintf(fd, " <UILanguageFallback>%s</UILanguageFallback>\n",
|
||||||
|
// NB: Officially, this is a REG_MULTI_SZ string
|
||||||
|
ReadRegistryKeyStr(REGKEY_HKLM, "SYSTEM\\CurrentControlSet\\Control\\Nls\\Language\\InstallLanguageFallback"));
|
||||||
|
fprintf(fd, " </component>\n");
|
||||||
|
}
|
||||||
fprintf(fd, " </settings>\n");
|
fprintf(fd, " </settings>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mask & UNATTEND_OFFLINE_SERVICING) {
|
if (flags & UNATTEND_OFFLINE_SERVICING_MASK) {
|
||||||
fprintf(fd, " <settings pass=\"offlineServicing\">\n");
|
fprintf(fd, " <settings pass=\"offlineServicing\">\n");
|
||||||
if (mask & UNATTEND_OFFLINE_INTERNAL_DRIVES) {
|
if (flags & UNATTEND_OFFLINE_INTERNAL_DRIVES) {
|
||||||
fprintf(fd, " <component name=\"Microsoft-Windows-PartitionManager\" processorArchitecture=\"%s\" language=\"neutral\" "
|
fprintf(fd, " <component name=\"Microsoft-Windows-PartitionManager\" processorArchitecture=\"%s\" language=\"neutral\" "
|
||||||
"xmlns:wcm=\"http://schemas.microsoft.com/WMIConfig/2002/State\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
"xmlns:wcm=\"http://schemas.microsoft.com/WMIConfig/2002/State\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
||||||
"publicKeyToken=\"31bf3856ad364e35\" versionScope=\"nonSxS\">\n", xml_arch_names[arch]);
|
"publicKeyToken=\"31bf3856ad364e35\" versionScope=\"nonSxS\">\n", xml_arch_names[arch]);
|
||||||
|
@ -1610,12 +1672,16 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
|
||||||
StrArrayCreate(&options, 2);
|
StrArrayCreate(&options, 2);
|
||||||
if (img_report.win_version.build >= 22500) {
|
if (img_report.win_version.build >= 22500) {
|
||||||
StrArrayAdd(&options, lmprintf(MSG_330), TRUE);
|
StrArrayAdd(&options, lmprintf(MSG_330), TRUE);
|
||||||
MAP_BIT(UNATTEND_NO_ONLINE_ACCOUNT_MASK);
|
MAP_BIT(UNATTEND_NO_ONLINE_ACCOUNT);
|
||||||
}
|
}
|
||||||
StrArrayAdd(&options, lmprintf(MSG_331), TRUE);
|
StrArrayAdd(&options, lmprintf(MSG_331), TRUE);
|
||||||
MAP_BIT(UNATTEND_NO_DATA_COLLECTION_MASK);
|
MAP_BIT(UNATTEND_NO_DATA_COLLECTION);
|
||||||
StrArrayAdd(&options, lmprintf(MSG_332), TRUE);
|
StrArrayAdd(&options, lmprintf(MSG_332), TRUE);
|
||||||
MAP_BIT(UNATTEND_OFFLINE_INTERNAL_DRIVES);
|
MAP_BIT(UNATTEND_OFFLINE_INTERNAL_DRIVES);
|
||||||
|
StrArrayAdd(&options, lmprintf(MSG_333), TRUE);
|
||||||
|
MAP_BIT(UNATTEND_DUPLICATE_USER);
|
||||||
|
StrArrayAdd(&options, lmprintf(MSG_334), TRUE);
|
||||||
|
MAP_BIT(UNATTEND_DUPLICATE_LOCALE);
|
||||||
i = SelectionDialog(BS_AUTOCHECKBOX, lmprintf(MSG_326), lmprintf(MSG_327),
|
i = SelectionDialog(BS_AUTOCHECKBOX, lmprintf(MSG_326), lmprintf(MSG_327),
|
||||||
options.String, options.Index, remap8(unattend_xml_mask, map, FALSE));
|
options.String, options.Index, remap8(unattend_xml_mask, map, FALSE));
|
||||||
StrArrayDestroy(&options);
|
StrArrayDestroy(&options);
|
||||||
|
@ -1623,7 +1689,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
|
||||||
goto out;
|
goto out;
|
||||||
// Remap i to the correct bit positions before calling CreateUnattendXml()
|
// Remap i to the correct bit positions before calling CreateUnattendXml()
|
||||||
i = remap8(i, map, TRUE);
|
i = remap8(i, map, TRUE);
|
||||||
unattend_xml_path = CreateUnattendXml(arch, i);
|
unattend_xml_path = CreateUnattendXml(arch, i | UNATTEND_WINDOWS_TO_GO);
|
||||||
// Keep the bits we didn't process
|
// Keep the bits we didn't process
|
||||||
unattend_xml_mask &= ~(remap8(0xff, map, TRUE));
|
unattend_xml_mask &= ~(remap8(0xff, map, TRUE));
|
||||||
// And add back the bits we did process
|
// And add back the bits we did process
|
||||||
|
@ -1666,15 +1732,19 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
|
||||||
uint8_t map[8] = { 0 }, b = 1;
|
uint8_t map[8] = { 0 }, b = 1;
|
||||||
StrArrayCreate(&options, 4);
|
StrArrayCreate(&options, 4);
|
||||||
StrArrayAdd(&options, lmprintf(MSG_328), TRUE);
|
StrArrayAdd(&options, lmprintf(MSG_328), TRUE);
|
||||||
MAP_BIT(UNATTEND_SECUREBOOT_TPM_MASK);
|
MAP_BIT(UNATTEND_SECUREBOOT_TPM);
|
||||||
StrArrayAdd(&options, lmprintf(MSG_329), TRUE);
|
StrArrayAdd(&options, lmprintf(MSG_329), TRUE);
|
||||||
MAP_BIT(UNATTEND_MINRAM_MINDISK_MASK);
|
MAP_BIT(UNATTEND_MINRAM_MINDISK);
|
||||||
if (img_report.win_version.build >= 22500) {
|
if (img_report.win_version.build >= 22500) {
|
||||||
StrArrayAdd(&options, lmprintf(MSG_330), TRUE);
|
StrArrayAdd(&options, lmprintf(MSG_330), TRUE);
|
||||||
MAP_BIT(UNATTEND_NO_ONLINE_ACCOUNT_MASK);
|
MAP_BIT(UNATTEND_NO_ONLINE_ACCOUNT);
|
||||||
}
|
}
|
||||||
StrArrayAdd(&options, lmprintf(MSG_331), TRUE);
|
StrArrayAdd(&options, lmprintf(MSG_331), TRUE);
|
||||||
MAP_BIT(UNATTEND_NO_DATA_COLLECTION_MASK);
|
MAP_BIT(UNATTEND_NO_DATA_COLLECTION);
|
||||||
|
StrArrayAdd(&options, lmprintf(MSG_333), TRUE);
|
||||||
|
MAP_BIT(UNATTEND_DUPLICATE_USER);
|
||||||
|
StrArrayAdd(&options, lmprintf(MSG_334), TRUE);
|
||||||
|
MAP_BIT(UNATTEND_DUPLICATE_LOCALE);
|
||||||
i = SelectionDialog(BS_AUTOCHECKBOX, lmprintf(MSG_326), lmprintf(MSG_327),
|
i = SelectionDialog(BS_AUTOCHECKBOX, lmprintf(MSG_326), lmprintf(MSG_327),
|
||||||
options.String, options.Index, remap8(unattend_xml_mask, map, FALSE));
|
options.String, options.Index, remap8(unattend_xml_mask, map, FALSE));
|
||||||
StrArrayDestroy(&options);
|
StrArrayDestroy(&options);
|
||||||
|
@ -1683,7 +1753,6 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
|
||||||
i = remap8(i, map, TRUE);
|
i = remap8(i, map, TRUE);
|
||||||
unattend_xml_path = CreateUnattendXml(arch, i);
|
unattend_xml_path = CreateUnattendXml(arch, i);
|
||||||
// Remember the user preferences for the current session.
|
// Remember the user preferences for the current session.
|
||||||
// TODO: Do we want to save the current mask as a permanent setting?
|
|
||||||
unattend_xml_mask &= ~(remap8(0xff, map, TRUE));
|
unattend_xml_mask &= ~(remap8(0xff, map, TRUE));
|
||||||
unattend_xml_mask |= i;
|
unattend_xml_mask |= i;
|
||||||
WriteSetting32(SETTING_WUE_OPTIONS, (UNATTEND_DEFAULT_MASK << 16) | unattend_xml_mask);
|
WriteSetting32(SETTING_WUE_OPTIONS, (UNATTEND_DEFAULT_MASK << 16) | unattend_xml_mask);
|
||||||
|
@ -2070,7 +2139,7 @@ static void InitDialog(HWND hDlg)
|
||||||
uprintf("Syslinux versions: %s%s, %s%s", embedded_sl_version_str[0], embedded_sl_version_ext[0],
|
uprintf("Syslinux versions: %s%s, %s%s", embedded_sl_version_str[0], embedded_sl_version_ext[0],
|
||||||
embedded_sl_version_str[1], embedded_sl_version_ext[1]);
|
embedded_sl_version_str[1], embedded_sl_version_ext[1]);
|
||||||
uprintf("Grub versions: %s, %s", GRUB4DOS_VERSION, GRUB2_PACKAGE_VERSION);
|
uprintf("Grub versions: %s, %s", GRUB4DOS_VERSION, GRUB2_PACKAGE_VERSION);
|
||||||
uprintf("System locale ID: 0x%04X (%s)", GetUserDefaultUILanguage(), GetCurrentMUI());
|
uprintf("System locale ID: 0x%04X (%s)", GetUserDefaultUILanguage(), ToLocaleName(GetUserDefaultUILanguage()));
|
||||||
ubflush();
|
ubflush();
|
||||||
if (selected_locale->ctrl_id & LOC_NEEDS_UPDATE) {
|
if (selected_locale->ctrl_id & LOC_NEEDS_UPDATE) {
|
||||||
uprintf("NOTE: The %s translation requires an update, but the current translator hasn't submitted "
|
uprintf("NOTE: The %s translation requires an update, but the current translator hasn't submitted "
|
||||||
|
@ -2756,7 +2825,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
|
||||||
fs_type = (int)ComboBox_GetCurItemData(hFileSystem);
|
fs_type = (int)ComboBox_GetCurItemData(hFileSystem);
|
||||||
write_as_image = FALSE;
|
write_as_image = FALSE;
|
||||||
write_as_esp = FALSE;
|
write_as_esp = FALSE;
|
||||||
unattend_xml_selection = 0;
|
unattend_xml_flags = 0;
|
||||||
// Disable all controls except Cancel
|
// Disable all controls except Cancel
|
||||||
EnableControls(FALSE, FALSE);
|
EnableControls(FALSE, FALSE);
|
||||||
FormatStatus = 0;
|
FormatStatus = 0;
|
||||||
|
|
28
src/rufus.h
28
src/rufus.h
|
@ -498,20 +498,24 @@ enum ArchType {
|
||||||
ARCH_MAX
|
ARCH_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
// Windows User Experience (unattend.xml) options
|
// Windows User Experience (unattend.xml) flags and masks
|
||||||
#define UNATTEND_SECUREBOOT_TPM_MASK 0x00001
|
#define UNATTEND_SECUREBOOT_TPM 0x00001
|
||||||
#define UNATTEND_MINRAM_MINDISK_MASK 0x00002
|
#define UNATTEND_MINRAM_MINDISK 0x00002
|
||||||
#define UNATTEND_NO_ONLINE_ACCOUNT_MASK 0x00004
|
#define UNATTEND_NO_ONLINE_ACCOUNT 0x00004
|
||||||
#define UNATTEND_NO_DATA_COLLECTION_MASK 0x00008
|
#define UNATTEND_NO_DATA_COLLECTION 0x00008
|
||||||
#define UNATTEND_OFFLINE_INTERNAL_DRIVES 0x00010
|
#define UNATTEND_OFFLINE_INTERNAL_DRIVES 0x00010
|
||||||
#define UNATTEND_DEFAULT_MASK 0x0001F
|
#define UNATTEND_DUPLICATE_LOCALE 0x00020
|
||||||
|
#define UNATTEND_DUPLICATE_USER 0x00040
|
||||||
|
#define UNATTEND_DEFAULT_MASK 0x0007F
|
||||||
#define UNATTEND_WINDOWS_TO_GO 0x10000 // Special flag for Windows To Go
|
#define UNATTEND_WINDOWS_TO_GO 0x10000 // Special flag for Windows To Go
|
||||||
|
|
||||||
#define UNATTEND_WINPE_SETUP_MASK (UNATTEND_SECUREBOOT_TPM_MASK | UNATTEND_MINRAM_MINDISK_MASK)
|
#define UNATTEND_WINPE_SETUP_MASK (UNATTEND_SECUREBOOT_TPM | UNATTEND_MINRAM_MINDISK)
|
||||||
#define UNATTEND_SPECIALIZE_DEPLOYMENT_MASK (UNATTEND_NO_ONLINE_ACCOUNT_MASK)
|
#define UNATTEND_SPECIALIZE_DEPLOYMENT_MASK (UNATTEND_NO_ONLINE_ACCOUNT)
|
||||||
#define UNATTEND_OOBE_SHELL_SETUP (UNATTEND_NO_DATA_COLLECTION_MASK)
|
#define UNATTEND_OOBE_SHELL_SETUP_MASK (UNATTEND_NO_DATA_COLLECTION | UNATTEND_DUPLICATE_USER)
|
||||||
#define UNATTEND_OFFLINE_SERVICING (UNATTEND_OFFLINE_INTERNAL_DRIVES)
|
#define UNATTEND_OOBE_INTERNATIONAL_MASK (UNATTEND_DUPLICATE_LOCALE)
|
||||||
#define UNATTEND_DEFAULT_SELECTION (UNATTEND_SECUREBOOT_TPM_MASK | UNATTEND_NO_ONLINE_ACCOUNT_MASK | UNATTEND_OFFLINE_INTERNAL_DRIVES)
|
#define UNATTEND_OOBE_MASK (UNATTEND_OOBE_SHELL_SETUP_MASK | UNATTEND_OOBE_INTERNATIONAL_MASK)
|
||||||
|
#define UNATTEND_OFFLINE_SERVICING_MASK (UNATTEND_OFFLINE_INTERNAL_DRIVES)
|
||||||
|
#define UNATTEND_DEFAULT_SELECTION_MASK (UNATTEND_SECUREBOOT_TPM | UNATTEND_NO_ONLINE_ACCOUNT | UNATTEND_OFFLINE_INTERNAL_DRIVES)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Globals
|
* Globals
|
||||||
|
@ -652,7 +656,7 @@ extern BOOL IsBufferInDB(const unsigned char* buf, const size_t len);
|
||||||
#define printbitslz(x) _printbits(sizeof(x), &x, 1)
|
#define printbitslz(x) _printbits(sizeof(x), &x, 1)
|
||||||
extern char* _printbits(size_t const size, void const * const ptr, int leading_zeroes);
|
extern char* _printbits(size_t const size, void const * const ptr, int leading_zeroes);
|
||||||
extern BOOL IsCurrentProcessElevated(void);
|
extern BOOL IsCurrentProcessElevated(void);
|
||||||
extern char* GetCurrentMUI(void);
|
extern char* ToLocaleName(DWORD lang_id);
|
||||||
extern void SetAlertPromptMessages(void);
|
extern void SetAlertPromptMessages(void);
|
||||||
extern BOOL SetAlertPromptHook(void);
|
extern BOOL SetAlertPromptHook(void);
|
||||||
extern void ClrAlertPromptHook(void);
|
extern void ClrAlertPromptHook(void);
|
||||||
|
|
10
src/rufus.rc
10
src/rufus.rc
|
@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||||
IDD_DIALOG DIALOGEX 12, 12, 232, 326
|
IDD_DIALOG DIALOGEX 12, 12, 232, 326
|
||||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||||
EXSTYLE WS_EX_ACCEPTFILES
|
EXSTYLE WS_EX_ACCEPTFILES
|
||||||
CAPTION "Rufus 3.20.1919"
|
CAPTION "Rufus 3.20.1920"
|
||||||
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
|
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
|
||||||
BEGIN
|
BEGIN
|
||||||
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
|
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
|
||||||
|
@ -395,8 +395,8 @@ END
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 3,20,1919,0
|
FILEVERSION 3,20,1920,0
|
||||||
PRODUCTVERSION 3,20,1919,0
|
PRODUCTVERSION 3,20,1920,0
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -414,13 +414,13 @@ BEGIN
|
||||||
VALUE "Comments", "https://rufus.ie"
|
VALUE "Comments", "https://rufus.ie"
|
||||||
VALUE "CompanyName", "Akeo Consulting"
|
VALUE "CompanyName", "Akeo Consulting"
|
||||||
VALUE "FileDescription", "Rufus"
|
VALUE "FileDescription", "Rufus"
|
||||||
VALUE "FileVersion", "3.20.1919"
|
VALUE "FileVersion", "3.20.1920"
|
||||||
VALUE "InternalName", "Rufus"
|
VALUE "InternalName", "Rufus"
|
||||||
VALUE "LegalCopyright", "© 2011-2022 Pete Batard (GPL v3)"
|
VALUE "LegalCopyright", "© 2011-2022 Pete Batard (GPL v3)"
|
||||||
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
|
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
|
||||||
VALUE "OriginalFilename", "rufus-3.20.exe"
|
VALUE "OriginalFilename", "rufus-3.20.exe"
|
||||||
VALUE "ProductName", "Rufus"
|
VALUE "ProductName", "Rufus"
|
||||||
VALUE "ProductVersion", "3.20.1919"
|
VALUE "ProductVersion", "3.20.1920"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
@ -1017,12 +1017,12 @@ out:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* GetCurrentMUI(void)
|
char* ToLocaleName(DWORD lang_id)
|
||||||
{
|
{
|
||||||
static char mui_str[LOCALE_NAME_MAX_LENGTH];
|
static char mui_str[LOCALE_NAME_MAX_LENGTH];
|
||||||
wchar_t wmui_str[LOCALE_NAME_MAX_LENGTH];
|
wchar_t wmui_str[LOCALE_NAME_MAX_LENGTH];
|
||||||
|
|
||||||
if (LCIDToLocaleName(GetUserDefaultUILanguage(), wmui_str, LOCALE_NAME_MAX_LENGTH, 0) > 0) {
|
if (LCIDToLocaleName(lang_id, wmui_str, LOCALE_NAME_MAX_LENGTH, 0) > 0) {
|
||||||
wchar_to_utf8_no_alloc(wmui_str, mui_str, LOCALE_NAME_MAX_LENGTH);
|
wchar_to_utf8_no_alloc(wmui_str, mui_str, LOCALE_NAME_MAX_LENGTH);
|
||||||
} else {
|
} else {
|
||||||
static_strcpy(mui_str, "en-US");
|
static_strcpy(mui_str, "en-US");
|
||||||
|
|
|
@ -1569,8 +1569,8 @@ void SetFidoCheck(void)
|
||||||
// - Powershell being installed
|
// - Powershell being installed
|
||||||
// - Rufus running in AppStore mode or update check being enabled
|
// - Rufus running in AppStore mode or update check being enabled
|
||||||
// - URL for the script being reachable
|
// - URL for the script being reachable
|
||||||
if ((ReadRegistryKey32(REGKEY_HKLM, "Microsoft\\PowerShell\\1\\Install") <= 0) &&
|
if ((ReadRegistryKey32(REGKEY_HKLM, "Software\\Microsoft\\PowerShell\\1\\Install") <= 0) &&
|
||||||
(ReadRegistryKey32(REGKEY_HKLM, "Microsoft\\PowerShell\\3\\Install") <= 0)) {
|
(ReadRegistryKey32(REGKEY_HKLM, "Software\\Microsoft\\PowerShell\\3\\Install") <= 0)) {
|
||||||
ubprintf("Notice: The ISO download feature has been deactivated because "
|
ubprintf("Notice: The ISO download feature has been deactivated because "
|
||||||
"a compatible PowerShell version was not detected on this system.");
|
"a compatible PowerShell version was not detected on this system.");
|
||||||
return;
|
return;
|
||||||
|
@ -2059,7 +2059,7 @@ void SetAlertPromptMessages(void)
|
||||||
// Fetch the localized strings in the relevant MUI
|
// Fetch the localized strings in the relevant MUI
|
||||||
// Must use sysnative_dir rather than system_dir as we may not find the MUI's otherwise
|
// Must use sysnative_dir rather than system_dir as we may not find the MUI's otherwise
|
||||||
// Also don't bother with LibLibraryEx() since we have a full path here.
|
// Also don't bother with LibLibraryEx() since we have a full path here.
|
||||||
static_sprintf(mui_path, "%s\\%s\\shell32.dll.mui", sysnative_dir, GetCurrentMUI());
|
static_sprintf(mui_path, "%s\\%s\\shell32.dll.mui", sysnative_dir, ToLocaleName(GetUserDefaultUILanguage()));
|
||||||
hMui = LoadLibraryU(mui_path);
|
hMui = LoadLibraryU(mui_path);
|
||||||
if (hMui != NULL) {
|
if (hMui != NULL) {
|
||||||
// 4097 = "You need to format the disk in drive %c: before you can use it." (dialog text)
|
// 4097 = "You need to format the disk in drive %c: before you can use it." (dialog text)
|
||||||
|
|
|
@ -167,8 +167,8 @@ static int _index, progress_op = OP_FILE_COPY, progress_msg = MSG_267;
|
||||||
|
|
||||||
static BOOL Get7ZipPath(void)
|
static BOOL Get7ZipPath(void)
|
||||||
{
|
{
|
||||||
if ( (GetRegistryKeyStr(REGKEY_HKCU, "7-Zip\\Path", sevenzip_path, sizeof(sevenzip_path)))
|
if ( (GetRegistryKeyStr(REGKEY_HKCU, "Software\\7-Zip\\Path", sevenzip_path, sizeof(sevenzip_path)))
|
||||||
|| (GetRegistryKeyStr(REGKEY_HKLM, "7-Zip\\Path", sevenzip_path, sizeof(sevenzip_path))) ) {
|
|| (GetRegistryKeyStr(REGKEY_HKLM, "Software\\7-Zip\\Path", sevenzip_path, sizeof(sevenzip_path))) ) {
|
||||||
static_strcat(sevenzip_path, "\\7z.exe");
|
static_strcat(sevenzip_path, "\\7z.exe");
|
||||||
return (_accessU(sevenzip_path, 0) != -1);
|
return (_accessU(sevenzip_path, 0) != -1);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue