[togo] enable selection of Windows version

* Closes #847
* Also set rufus-next to 2.12
This commit is contained in:
Pete Batard 2016-12-13 14:21:51 +00:00
parent 5113be0a39
commit 7d302d340f
15 changed files with 349 additions and 78 deletions

20
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for rufus 2.11. # Generated by GNU Autoconf 2.69 for rufus 2.12.
# #
# Report bugs to <https://github.com/pbatard/rufus/issues>. # Report bugs to <https://github.com/pbatard/rufus/issues>.
# #
@ -580,8 +580,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='rufus' PACKAGE_NAME='rufus'
PACKAGE_TARNAME='rufus' PACKAGE_TARNAME='rufus'
PACKAGE_VERSION='2.11' PACKAGE_VERSION='2.12'
PACKAGE_STRING='rufus 2.11' PACKAGE_STRING='rufus 2.12'
PACKAGE_BUGREPORT='https://github.com/pbatard/rufus/issues' PACKAGE_BUGREPORT='https://github.com/pbatard/rufus/issues'
PACKAGE_URL='http://rufus.akeo.ie' PACKAGE_URL='http://rufus.akeo.ie'
@ -1228,7 +1228,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures rufus 2.11 to adapt to many kinds of systems. \`configure' configures rufus 2.12 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1294,7 +1294,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of rufus 2.11:";; short | recursive ) echo "Configuration of rufus 2.12:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -1385,7 +1385,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
rufus configure 2.11 rufus configure 2.12
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
@ -1440,7 +1440,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by rufus $as_me 2.11, which was It was created by rufus $as_me 2.12, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
@ -2303,7 +2303,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE='rufus' PACKAGE='rufus'
VERSION='2.11' VERSION='2.12'
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
@ -4482,7 +4482,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by rufus $as_me 2.11, which was This file was extended by rufus $as_me 2.12, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -4536,7 +4536,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
rufus config.status 2.11 rufus config.status 2.12
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View File

@ -1,4 +1,4 @@
AC_INIT([rufus], [2.11], [https://github.com/pbatard/rufus/issues], [rufus], [http://rufus.akeo.ie]) AC_INIT([rufus], [2.12], [https://github.com/pbatard/rufus/issues], [rufus], [http://rufus.akeo.ie])
AM_INIT_AUTOMAKE([-Wno-portability foreign no-dist no-dependencies]) AM_INIT_AUTOMAKE([-Wno-portability foreign no-dist no-dependencies])
AC_CONFIG_SRCDIR([src/rufus.c]) AC_CONFIG_SRCDIR([src/rufus.c])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])

View File

@ -553,6 +553,8 @@ t MSG_287 "Detection of non-USB removable drives"
t MSG_288 "Missing elevated privileges" t MSG_288 "Missing elevated privileges"
t MSG_289 "This application can only run with elevated privileges" t MSG_289 "This application can only run with elevated privileges"
t MSG_290 "File Indexing" t MSG_290 "File Indexing"
t MSG_291 "Version selection"
t MSG_292 "Please select the version of Windows you want to install:"
################################################################################ ################################################################################
############################# TRANSLATOR END COPY ############################## ############################# TRANSLATOR END COPY ##############################

View File

@ -313,7 +313,7 @@ BOOL GetDevices(DWORD devnum)
StrArrayClear(&DriveLabel); StrArrayClear(&DriveLabel);
StrArrayCreate(&dev_if_path, 128); StrArrayCreate(&dev_if_path, 128);
// Add a dummy for string index zero, as this is what non matching hashes will point to // Add a dummy for string index zero, as this is what non matching hashes will point to
StrArrayAdd(&dev_if_path, ""); StrArrayAdd(&dev_if_path, "", TRUE);
device_id = (char*)malloc(MAX_PATH); device_id = (char*)malloc(MAX_PATH);
if (device_id == NULL) if (device_id == NULL)
@ -340,7 +340,7 @@ BOOL GetDevices(DWORD devnum)
// Find the Device IDs for all the children of this hub // Find the Device IDs for all the children of this hub
if (CM_Get_Child(&device_inst, dev_info_data.DevInst, 0) == CR_SUCCESS) { if (CM_Get_Child(&device_inst, dev_info_data.DevInst, 0) == CR_SUCCESS) {
device_id[0] = 0; device_id[0] = 0;
s = StrArrayAdd(&dev_if_path, devint_detail_data->DevicePath); s = StrArrayAdd(&dev_if_path, devint_detail_data->DevicePath, TRUE);
uuprintf(" Hub[%d] = '%s'", s, devint_detail_data->DevicePath); uuprintf(" Hub[%d] = '%s'", s, devint_detail_data->DevicePath);
if ((s>= 0) && (CM_Get_Device_IDA(device_inst, device_id, MAX_PATH, 0) == CR_SUCCESS)) { if ((s>= 0) && (CM_Get_Device_IDA(device_inst, device_id, MAX_PATH, 0) == CR_SUCCESS)) {
if ((k = htab_hash(device_id, &htab_devid)) != 0) { if ((k = htab_hash(device_id, &htab_devid)) != 0) {
@ -741,8 +741,8 @@ BOOL GetDevices(DWORD devnum)
} }
// Must ensure that the combo box is UNSORTED for indexes to be the same // Must ensure that the combo box is UNSORTED for indexes to be the same
StrArrayAdd(&DriveID, buffer); StrArrayAdd(&DriveID, buffer, TRUE);
StrArrayAdd(&DriveLabel, label); StrArrayAdd(&DriveLabel, label, TRUE);
IGNORE_RETVAL(ComboBox_SetItemData(hDeviceList, ComboBox_AddStringU(hDeviceList, entry), drive_index)); IGNORE_RETVAL(ComboBox_SetItemData(hDeviceList, ComboBox_AddStringU(hDeviceList, entry), drive_index));
maxwidth = max(maxwidth, GetEntryWidth(hDeviceList, entry)); maxwidth = max(maxwidth, GetEntryWidth(hDeviceList, entry));

View File

@ -1277,8 +1277,11 @@ static BOOL SetupWinToGo(const char* drive_name, BOOL use_ms_efi)
static char san_policy_path[] = "?:\\san_policy.xml"; static char san_policy_path[] = "?:\\san_policy.xml";
#endif #endif
static char unattend_path[] = "?:\\Windows\\System32\\sysprep\\unattend.xml"; static char unattend_path[] = "?:\\Windows\\System32\\sysprep\\unattend.xml";
StrArray version_name, version_index;
char *mounted_iso, *ms_efi = NULL, image[128], cmd[MAX_PATH]; char *mounted_iso, *ms_efi = NULL, image[128], cmd[MAX_PATH];
char tmp_path[MAX_PATH] = "", xml_file[MAX_PATH] = "";
unsigned char *buffer; unsigned char *buffer;
int i, index;
wchar_t wVolumeName[] = L"?:"; wchar_t wVolumeName[] = L"?:";
DWORD bufsize; DWORD bufsize;
ULONG cluster_size; ULONG cluster_size;
@ -1305,11 +1308,50 @@ static BOOL SetupWinToGo(const char* drive_name, BOOL use_ms_efi)
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT);
return FALSE; return FALSE;
} }
static_sprintf(image, "%s%s", mounted_iso, &img_report.install_wim_path[2]);
uprintf("Mounted ISO as '%s'", mounted_iso); uprintf("Mounted ISO as '%s'", mounted_iso);
// Then we need to take a look at the XML file in install.wim to allow users
// to select the version they want to extract
if ((GetTempPathU(sizeof(tmp_path), tmp_path) == 0)
|| (GetTempFileNameU(tmp_path, APPLICATION_NAME, 0, xml_file) == 0)
|| (xml_file[0] == 0)) {
// Last ditch effort to get a loc file - just extract it to the current directory
safe_strcpy(xml_file, sizeof(xml_file), ".\\RufVXml.tmp");
}
// GetTempFileName() may leave a file behind
DeleteFileU(xml_file);
// Must use the Windows WIM API as 7z messes up the XML
if (!WimExtractFile_API(image, 0, "[1].xml", xml_file)) {
uprintf("Failed to acquire WIM index");
}
StrArrayCreate(&version_name, 16);
StrArrayCreate(&version_index, 16);
for (i = 0; (StrArrayAdd(&version_name, get_token_data_file_indexed("DISPLAYNAME", xml_file, i+1), FALSE) >= 0) &&
(StrArrayAdd(&version_index, get_token_data_file_indexed("IMAGE INDEX", xml_file, i+1), FALSE) >= 0); i++);
DeleteFileU(xml_file);
if (i > 1)
i = Selection(lmprintf(MSG_291), lmprintf(MSG_292), version_name.String, i);
if (i <= 0) {
uprintf("Cancelled by user");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED;
UnMountISO();
StrArrayDestroy(&version_name);
StrArrayDestroy(&version_index);
return FALSE;
} else if (i == 0) {
index = 1;
} else {
index = atoi(version_index.String[i - 1]);
}
uprintf("Selected: '%s' (index %s)", version_name.String[i - 1], version_index.String[i - 1]);
StrArrayDestroy(&version_name);
StrArrayDestroy(&version_index);
// Now we use the WIM API to apply that image // Now we use the WIM API to apply that image
static_sprintf(image, "%s%s", mounted_iso, &img_report.install_wim_path[2]); if (!WimApplyImage(image, index, drive_name)) {
if (!WimApplyImage(image, 1, drive_name)) {
uprintf("Failed to apply Windows To Go image"); uprintf("Failed to apply Windows To Go image");
if (!IS_ERROR(FormatStatus)) if (!IS_ERROR(FormatStatus))
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT);

View File

@ -226,12 +226,12 @@ static BOOL check_iso_props(const char* psz_dirname, int64_t i_file_length, cons
if (props->is_syslinux_cfg) { if (props->is_syslinux_cfg) {
// Maintain a list of all the isolinux/syslinux configs identified so far // Maintain a list of all the isolinux/syslinux configs identified so far
StrArrayAdd(&config_path, psz_fullpath); StrArrayAdd(&config_path, psz_fullpath, TRUE);
} }
for (i=0; i<ARRAYSIZE(isolinux_bin); i++) { for (i=0; i<ARRAYSIZE(isolinux_bin); i++) {
if (safe_stricmp(psz_basename, isolinux_bin[i]) == 0) { if (safe_stricmp(psz_basename, isolinux_bin[i]) == 0) {
// Maintain a list of all the isolinux.bin files found // Maintain a list of all the isolinux.bin files found
StrArrayAdd(&isolinux_path, psz_fullpath); StrArrayAdd(&isolinux_path, psz_fullpath, TRUE);
} }
} }

View File

@ -96,6 +96,20 @@ const loc_control_id control_id[] = {
LOC_CTRL(IDC_SELECTION_LINE), LOC_CTRL(IDC_SELECTION_LINE),
LOC_CTRL(IDC_SELECTION_CHOICE1), LOC_CTRL(IDC_SELECTION_CHOICE1),
LOC_CTRL(IDC_SELECTION_CHOICE2), LOC_CTRL(IDC_SELECTION_CHOICE2),
LOC_CTRL(IDC_SELECTION_CHOICE3),
LOC_CTRL(IDC_SELECTION_CHOICE4),
LOC_CTRL(IDC_SELECTION_CHOICE5),
LOC_CTRL(IDC_SELECTION_CHOICE6),
LOC_CTRL(IDC_SELECTION_CHOICE7),
LOC_CTRL(IDC_SELECTION_CHOICE8),
LOC_CTRL(IDC_SELECTION_CHOICE9),
LOC_CTRL(IDC_SELECTION_CHOICE10),
LOC_CTRL(IDC_SELECTION_CHOICE11),
LOC_CTRL(IDC_SELECTION_CHOICE12),
LOC_CTRL(IDC_SELECTION_CHOICE13),
LOC_CTRL(IDC_SELECTION_CHOICE14),
LOC_CTRL(IDC_SELECTION_CHOICE15),
LOC_CTRL(IDC_SELECTION_CHOICEMAX),
LOC_CTRL(IDS_DEVICE_TXT), LOC_CTRL(IDS_DEVICE_TXT),
LOC_CTRL(IDS_PARTITION_TYPE_TXT), LOC_CTRL(IDS_PARTITION_TYPE_TXT),
LOC_CTRL(IDS_FILESYSTEM_TXT), LOC_CTRL(IDS_FILESYSTEM_TXT),

View File

@ -571,20 +571,24 @@ out:
/* /*
* Parse a line of UTF-16 text and return the data if it matches the 'token' * Parse a line of UTF-16 text and return the data if it matches the 'token'
* The parsed line is of the form: [ ]token[ ]=[ ]["]data["][ ] and is * The parsed line is of the form: [ ][<][ ]token[ ][=|>][ ]["]data["][ ][<] and is
* modified by the parser * modified by the parser
*/ */
static wchar_t* get_token_data_line(const wchar_t* wtoken, wchar_t* wline) static wchar_t* get_token_data_line(const wchar_t* wtoken, wchar_t* wline)
{ {
size_t i, r; size_t i, r;
BOOLEAN quoteth = FALSE; BOOLEAN quoteth = FALSE;
BOOLEAN xml = FALSE;
if ((wtoken == NULL) || (wline == NULL) || (wline[0] == 0)) if ((wtoken == NULL) || (wline == NULL) || (wline[0] == 0))
return NULL; return NULL;
i = 0; i = 0;
// Skip leading spaces // Skip leading spaces and opening '<'
i += wcsspn(&wline[i], wspace);
if (wline[i] == L'<')
i++;
i += wcsspn(&wline[i], wspace); i += wcsspn(&wline[i], wspace);
// Our token should begin a line // Our token should begin a line
@ -597,12 +601,14 @@ static wchar_t* get_token_data_line(const wchar_t* wtoken, wchar_t* wline)
// Skip spaces // Skip spaces
i += wcsspn(&wline[i], wspace); i += wcsspn(&wline[i], wspace);
// Check for an equal sign // Check for '=' or '>' sign
if (wline[i] != L'=') if (wline[i] == L'>')
xml = TRUE;
else if (wline[i] != L'=')
return NULL; return NULL;
i++; i++;
// Skip spaces after equal sign // Skip spaces
i += wcsspn(&wline[i], wspace); i += wcsspn(&wline[i], wspace);
// eliminate leading quote, if it exists // eliminate leading quote, if it exists
@ -615,7 +621,7 @@ static wchar_t* get_token_data_line(const wchar_t* wtoken, wchar_t* wline)
r = i; r = i;
// locate end of string or quote // locate end of string or quote
while ( (wline[i] != 0) && ((wline[i] != L'"') || ((wline[i] == L'"') && (!quoteth))) ) while ( (wline[i] != 0) && (((wline[i] != L'"') && (wline[i] != L'<')) || ((wline[i] == L'"') && (!quoteth)) || ((wline[i] == L'<') && (!xml))) )
i++; i++;
wline[i--] = 0; wline[i--] = 0;
@ -627,11 +633,12 @@ static wchar_t* get_token_data_line(const wchar_t* wtoken, wchar_t* wline)
} }
/* /*
* Parse a file (ANSI or UTF-8 or UTF-16) and return the data for the first occurrence of 'token' * Parse a file (ANSI or UTF-8 or UTF-16) and return the data for the 'index'th occurrence of 'token'
* The returned string is UTF-8 and MUST be freed by the caller * The returned string is UTF-8 and MUST be freed by the caller
*/ */
char* get_token_data_file(const char* token, const char* filename) char* get_token_data_file_indexed(const char* token, const char* filename, int index)
{ {
int i = 0;
wchar_t *wtoken = NULL, *wdata= NULL, *wfilename = NULL; wchar_t *wtoken = NULL, *wdata= NULL, *wfilename = NULL;
wchar_t buf[1024]; wchar_t buf[1024];
FILE* fd = NULL; FILE* fd = NULL;
@ -659,7 +666,7 @@ char* get_token_data_file(const char* token, const char* filename)
// Ideally, we'd check that our buffer fits the line // Ideally, we'd check that our buffer fits the line
while (fgetws(buf, ARRAYSIZE(buf), fd) != NULL) { while (fgetws(buf, ARRAYSIZE(buf), fd) != NULL) {
wdata = get_token_data_line(wtoken, buf); wdata = get_token_data_line(wtoken, buf);
if (wdata != NULL) { if ((wdata != NULL) && (++i == index)) {
ret = wchar_to_utf8(wdata); ret = wchar_to_utf8(wdata);
break; break;
} }

View File

@ -134,6 +134,20 @@
#define IDC_SELECTION_LINE 1076 #define IDC_SELECTION_LINE 1076
#define IDC_SELECTION_CHOICE1 1077 #define IDC_SELECTION_CHOICE1 1077
#define IDC_SELECTION_CHOICE2 1078 #define IDC_SELECTION_CHOICE2 1078
#define IDC_SELECTION_CHOICE3 1079
#define IDC_SELECTION_CHOICE4 1080
#define IDC_SELECTION_CHOICE5 1081
#define IDC_SELECTION_CHOICE6 1082
#define IDC_SELECTION_CHOICE7 1083
#define IDC_SELECTION_CHOICE8 1084
#define IDC_SELECTION_CHOICE9 1085
#define IDC_SELECTION_CHOICE10 1086
#define IDC_SELECTION_CHOICE11 1087
#define IDC_SELECTION_CHOICE12 1088
#define IDC_SELECTION_CHOICE13 1089
#define IDC_SELECTION_CHOICE14 1090
#define IDC_SELECTION_CHOICE15 1091
#define IDC_SELECTION_CHOICEMAX 1092
#define IDS_DEVICE_TXT 2000 #define IDS_DEVICE_TXT 2000
#define IDS_PARTITION_TYPE_TXT 2001 #define IDS_PARTITION_TYPE_TXT 2001
#define IDS_FILESYSTEM_TXT 2002 #define IDS_FILESYSTEM_TXT 2002

View File

@ -2108,6 +2108,10 @@ void SaveISO(void)
} }
} }
#ifdef RUFUS_TEST
extern int SelectionDyn(char* title, char* message, char** szChoice, int nChoices);
#endif
/* /*
* Main dialog callback * Main dialog callback
*/ */
@ -2140,6 +2144,8 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
case WM_COMMAND: case WM_COMMAND:
#ifdef RUFUS_TEST #ifdef RUFUS_TEST
if (LOWORD(wParam) == IDC_TEST) { if (LOWORD(wParam) == IDC_TEST) {
char* choices[] = { "Choice 1", "Choice 2", "Choice 3" };
SelectionDyn("Test Choice", "Unused", choices, ARRAYSIZE(choices));
break; break;
} }
#endif #endif
@ -2438,8 +2444,9 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
(ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType)) == BT_ISO)) { (ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType)) == BT_ISO)) {
char* iso_image = lmprintf(MSG_036); char* iso_image = lmprintf(MSG_036);
char* dd_image = lmprintf(MSG_095); char* dd_image = lmprintf(MSG_095);
char* choices[2] = { lmprintf(MSG_276, iso_image), lmprintf(MSG_277, dd_image) };
i = Selection(lmprintf(MSG_274), lmprintf(MSG_275, iso_image, dd_image, iso_image, dd_image), i = Selection(lmprintf(MSG_274), lmprintf(MSG_275, iso_image, dd_image, iso_image, dd_image),
lmprintf(MSG_276, iso_image), lmprintf(MSG_277, dd_image)); choices, 2);
if (i < 0) { // Cancel if (i < 0) { // Cancel
format_op_in_progress = FALSE; format_op_in_progress = FALSE;
PROCESS_QUEUED_EVENTS; PROCESS_QUEUED_EVENTS;

View File

@ -422,7 +422,7 @@ extern BOOL CreateTooltip(HWND hControl, const char* message, int duration);
extern void DestroyTooltip(HWND hWnd); extern void DestroyTooltip(HWND hWnd);
extern void DestroyAllTooltips(void); extern void DestroyAllTooltips(void);
extern BOOL Notification(int type, const notification_info* more_info, char* title, char* format, ...); extern BOOL Notification(int type, const notification_info* more_info, char* title, char* format, ...);
extern int Selection(char* title, char* message, char* selection1, char* selection2); extern int Selection(char* title, char* message, char** choices, int size);
extern SIZE GetTextSize(HWND hCtrl); extern SIZE GetTextSize(HWND hCtrl);
extern BOOL ExtractDOS(const char* path); extern BOOL ExtractDOS(const char* path);
extern BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan); extern BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan);
@ -450,7 +450,8 @@ extern BOOL SetUpdateCheck(void);
extern BOOL CheckForUpdates(BOOL force); extern BOOL CheckForUpdates(BOOL force);
extern void DownloadNewVersion(void); extern void DownloadNewVersion(void);
extern BOOL IsShown(HWND hDlg); extern BOOL IsShown(HWND hDlg);
extern char* get_token_data_file(const char* token, const char* filename); extern char* get_token_data_file_indexed(const char* token, const char* filename, int index);
#define get_token_data_file(token, filename) get_token_data_file_indexed(token, filename, 1)
extern char* set_token_data_file(const char* token, const char* data, const char* filename); extern char* set_token_data_file(const char* token, const char* data, const char* filename);
extern char* get_token_data_buffer(const char* token, unsigned int n, const char* buffer, size_t buffer_size); extern char* get_token_data_buffer(const char* token, unsigned int n, const char* buffer, size_t buffer_size);
extern char* insert_section_data(const char* filename, const char* section, const char* data, BOOL dos2unix); extern char* insert_section_data(const char* filename, const char* section, const char* data, BOOL dos2unix);
@ -459,6 +460,8 @@ extern char* replace_char(const char* src, const char c, const char* rep);
extern void parse_update(char* buf, size_t len); extern void parse_update(char* buf, size_t len);
extern uint8_t WimExtractCheck(void); extern uint8_t WimExtractCheck(void);
extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst); extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst);
extern BOOL WimExtractFile_API(const char* image, int index, const char* src, const char* dst);
extern BOOL WimExtractFile_7z(const char* image, int index, const char* src, const char* dst);
extern BOOL WimApplyImage(const char* image, int index, const char* dst); extern BOOL WimApplyImage(const char* image, int index, const char* dst);
extern BOOL IsBootableImage(const char* path); extern BOOL IsBootableImage(const char* path);
extern BOOL AppendVHDFooter(const char* vhd_path); extern BOOL AppendVHDFooter(const char* vhd_path);
@ -507,7 +510,7 @@ typedef struct {
uint32_t Max; // Maximum array size uint32_t Max; // Maximum array size
} StrArray; } StrArray;
extern void StrArrayCreate(StrArray* arr, uint32_t initial_size); extern void StrArrayCreate(StrArray* arr, uint32_t initial_size);
extern int32_t StrArrayAdd(StrArray* arr, const char* str); extern int32_t StrArrayAdd(StrArray* arr, const char* str, BOOL );
extern void StrArrayClear(StrArray* arr); extern void StrArrayClear(StrArray* arr);
extern void StrArrayDestroy(StrArray* arr); extern void StrArrayDestroy(StrArray* arr);
#define IsStrArrayEmpty(arr) (arr.Index == 0) #define IsStrArrayEmpty(arr) (arr.Index == 0)

View File

@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 242, 376 IDD_DIALOG DIALOGEX 12, 12, 242, 376
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 2.11.1007" CAPTION "Rufus 2.12.1008"
FONT 8, "Segoe UI Symbol", 400, 0, 0x0 FONT 8, "Segoe UI Symbol", 400, 0, 0x0
BEGIN BEGIN
LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8
@ -144,10 +144,24 @@ BEGIN
LTEXT "",IDC_STATIC,0,0,312,46 LTEXT "",IDC_STATIC,0,0,312,46
ICON IDI_ICON,IDC_SELECTION_ICON,6,6,20,20,0,WS_EX_TRANSPARENT ICON IDI_ICON,IDC_SELECTION_ICON,6,6,20,20,0,WS_EX_TRANSPARENT
LTEXT "Message",IDC_SELECTION_TEXT,35,5,269,8 LTEXT "Message",IDC_SELECTION_TEXT,35,5,269,8
DEFPUSHBUTTON "Cancel",IDCANCEL,254,52,50,14 DEFPUSHBUTTON "OK",IDOK,196,52,50,14
PUSHBUTTON "OK",IDOK,196,52,50,14 PUSHBUTTON "Cancel",IDCANCEL,254,52,50,14
CONTROL "Choice 1",IDC_SELECTION_CHOICE1,"Button",BS_AUTORADIOBUTTON,35,18,269,10,WS_EX_TRANSPARENT CONTROL "Choice 1",IDC_SELECTION_CHOICE1,"Button",BS_AUTORADIOBUTTON | WS_GROUP,35,18,269,10,WS_EX_TRANSPARENT
CONTROL "Choice 2",IDC_SELECTION_CHOICE2,"Button",BS_AUTORADIOBUTTON,35,31,269,10,WS_EX_TRANSPARENT CONTROL "Choice 2",IDC_SELECTION_CHOICE2,"Button",BS_AUTORADIOBUTTON,35,31,269,10,WS_EX_TRANSPARENT
CONTROL "Choice 3",IDC_SELECTION_CHOICE3,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE,35,44,269,10,WS_EX_TRANSPARENT
CONTROL "Choice 4",IDC_SELECTION_CHOICE4,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE,35,57,269,10,WS_EX_TRANSPARENT
CONTROL "Choice 5",IDC_SELECTION_CHOICE5,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE,35,70,269,10,WS_EX_TRANSPARENT
CONTROL "Choice 6",IDC_SELECTION_CHOICE6,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE,35,83,269,10,WS_EX_TRANSPARENT
CONTROL "Choice 7",IDC_SELECTION_CHOICE7,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE,35,96,269,10,WS_EX_TRANSPARENT
CONTROL "Choice 8",IDC_SELECTION_CHOICE8,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE,35,109,269,10,WS_EX_TRANSPARENT
CONTROL "Choice 9",IDC_SELECTION_CHOICE9,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE,35,122,269,10,WS_EX_TRANSPARENT
CONTROL "Choice 10",IDC_SELECTION_CHOICE10,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE,35,135,269,10,WS_EX_TRANSPARENT
CONTROL "Choice 11",IDC_SELECTION_CHOICE11,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE,35,148,269,10,WS_EX_TRANSPARENT
CONTROL "Choice 12",IDC_SELECTION_CHOICE12,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE,35,161,269,10,WS_EX_TRANSPARENT
CONTROL "Choice 13",IDC_SELECTION_CHOICE13,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE,35,174,269,10,WS_EX_TRANSPARENT
CONTROL "Choice 14",IDC_SELECTION_CHOICE14,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE,35,187,269,10,WS_EX_TRANSPARENT
CONTROL "Choice 15",IDC_SELECTION_CHOICE15,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE,35,200,269,10,WS_EX_TRANSPARENT
CONTROL "Choice 16",IDC_SELECTION_CHOICEMAX,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE,35,21,269,10,WS_EX_TRANSPARENT
END END
IDD_UPDATE_POLICY DIALOGEX 0, 0, 287, 198 IDD_UPDATE_POLICY DIALOGEX 0, 0, 287, 198
@ -320,8 +334,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,11,1007,0 FILEVERSION 2,12,1008,0
PRODUCTVERSION 2,11,1007,0 PRODUCTVERSION 2,12,1008,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -338,13 +352,13 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
VALUE "FileDescription", "Rufus" VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "2.11.1007" VALUE "FileVersion", "2.12.1008"
VALUE "InternalName", "Rufus" VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2016 Pete Batard (GPL v3)" VALUE "LegalCopyright", "© 2011-2016 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus.exe" VALUE "OriginalFilename", "rufus.exe"
VALUE "ProductName", "Rufus" VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "2.11.1007" VALUE "ProductVersion", "2.12.1008"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -348,10 +348,10 @@ void StrArrayCreate(StrArray* arr, uint32_t initial_size)
uprintf("Could not allocate string array\n"); uprintf("Could not allocate string array\n");
} }
int32_t StrArrayAdd(StrArray* arr, const char* str) int32_t StrArrayAdd(StrArray* arr, const char* str, BOOL duplicate)
{ {
char** old_table; char** old_table;
if ((arr == NULL) || (arr->String == NULL)) if ((arr == NULL) || (arr->String == NULL) || (str == NULL))
return -1; return -1;
if (arr->Index == arr->Max) { if (arr->Index == arr->Max) {
arr->Max *= 2; arr->Max *= 2;
@ -363,7 +363,7 @@ int32_t StrArrayAdd(StrArray* arr, const char* str)
return -1; return -1;
} }
} }
arr->String[arr->Index] = safe_strdup(str); arr->String[arr->Index] = (duplicate)?safe_strdup(str):(char*)str;
if (arr->String[arr->Index] == NULL) { if (arr->String[arr->Index] == NULL) {
uprintf("Could not store string in array\n"); uprintf("Could not store string in array\n");
return -1; return -1;

View File

@ -54,7 +54,8 @@ PF_TYPE_DECL(WINAPI, LPITEMIDLIST, SHSimpleIDListFromPath, (PCWSTR pszPath));
static HICON hMessageIcon = (HICON)INVALID_HANDLE_VALUE; static HICON hMessageIcon = (HICON)INVALID_HANDLE_VALUE;
static char* szMessageText = NULL; static char* szMessageText = NULL;
static char* szMessageTitle = NULL; static char* szMessageTitle = NULL;
static char *szChoice1, *szChoice2; static char **szChoice;
static int nChoices;
static HWND hBrowseEdit; static HWND hBrowseEdit;
extern HWND hUpdatesDlg; extern HWND hUpdatesDlg;
static WNDPROC pOrgBrowseWndproc; static WNDPROC pOrgBrowseWndproc;
@ -68,6 +69,14 @@ static char *fp_title_str = "Microsoft Windows", *fp_button_str = "Format disk";
extern loc_cmd* selected_locale; extern loc_cmd* selected_locale;
/*
* https://blogs.msdn.microsoft.com/oldnewthing/20040802-00/?p=38283/
*/
void SetDialogFocus(HWND hDlg, HWND hCtrl)
{
SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)hCtrl, TRUE);
}
/* /*
* We need a sub-callback to read the content of the edit box on exit and update * We need a sub-callback to read the content of the edit box on exit and update
* our path, else if what the user typed does match the selection, it is discarded. * our path, else if what the user typed does match the selection, it is discarded.
@ -99,7 +108,7 @@ INT CALLBACK BrowseInfoCallback(HWND hDlg, UINT message, LPARAM lParam, LPARAM p
// Get a handle to the edit control to fix that // Get a handle to the edit control to fix that
hBrowseEdit = FindWindowExA(hDlg, NULL, "Edit", NULL); hBrowseEdit = FindWindowExA(hDlg, NULL, "Edit", NULL);
SetWindowTextU(hBrowseEdit, szFolderPath); SetWindowTextU(hBrowseEdit, szFolderPath);
SetFocus(hBrowseEdit); SetDialogFocus(hDlg, hBrowseEdit);
// On XP, BFFM_SETSELECTION can't be used with a Unicode Path in SendMessageW // On XP, BFFM_SETSELECTION can't be used with a Unicode Path in SendMessageW
// or a pidl (at least with MinGW) => must use SendMessageA // or a pidl (at least with MinGW) => must use SendMessageA
if (nWindowsVersion <= WINDOWS_XP) { if (nWindowsVersion <= WINDOWS_XP) {
@ -849,6 +858,13 @@ INT_PTR CALLBACK SelectionCallback(HWND hDlg, UINT message, WPARAM wParam, LPARA
switch (message) { switch (message) {
case WM_INITDIALOG: case WM_INITDIALOG:
// Don't overflow our max radio button
if (nChoices > (IDC_SELECTION_CHOICEMAX - IDC_SELECTION_CHOICE1)) {
uprintf("WARNING: Too many options requested for Selection (%d vs %d)",
nChoices, IDC_SELECTION_CHOICEMAX - IDC_SELECTION_CHOICE1);
nChoices = IDC_SELECTION_CHOICEMAX - IDC_SELECTION_CHOICE1;
}
// TODO: This shouldn't be needed when using DS_SHELLFONT
// Get the system message box font. See http://stackoverflow.com/a/6057761 // Get the system message box font. See http://stackoverflow.com/a/6057761
ncm.cbSize = sizeof(ncm); ncm.cbSize = sizeof(ncm);
// If we're compiling with the Vista SDK or later, the NONCLIENTMETRICS struct // If we're compiling with the Vista SDK or later, the NONCLIENTMETRICS struct
@ -865,8 +881,8 @@ INT_PTR CALLBACK SelectionCallback(HWND hDlg, UINT message, WPARAM wParam, LPARA
// Set the dialog to use the system message box font // Set the dialog to use the system message box font
SendMessage(hDlg, WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0)); SendMessage(hDlg, WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
SendMessage(GetDlgItem(hDlg, IDC_SELECTION_TEXT), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0)); SendMessage(GetDlgItem(hDlg, IDC_SELECTION_TEXT), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
SendMessage(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0)); for (i = 0; i < nChoices; i++)
SendMessage(GetDlgItem(hDlg, IDC_SELECTION_CHOICE2), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0)); SendMessage(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
SendMessage(GetDlgItem(hDlg, IDYES), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0)); SendMessage(GetDlgItem(hDlg, IDYES), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
SendMessage(GetDlgItem(hDlg, IDNO), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0)); SendMessage(GetDlgItem(hDlg, IDNO), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
@ -880,9 +896,10 @@ INT_PTR CALLBACK SelectionCallback(HWND hDlg, UINT message, WPARAM wParam, LPARA
SetWindowTextU(hDlg, szMessageTitle); SetWindowTextU(hDlg, szMessageTitle);
SetWindowTextU(GetDlgItem(hDlg, IDCANCEL), lmprintf(MSG_007)); SetWindowTextU(GetDlgItem(hDlg, IDCANCEL), lmprintf(MSG_007));
SetWindowTextU(GetDlgItem(hDlg, IDC_SELECTION_TEXT), szMessageText); SetWindowTextU(GetDlgItem(hDlg, IDC_SELECTION_TEXT), szMessageText);
SetWindowTextU(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1), szChoice1); for (i = 0; i < nChoices; i++) {
SetWindowTextU(GetDlgItem(hDlg, IDC_SELECTION_CHOICE2), szChoice2); SetWindowTextU(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i), szChoice[i]);
ShowWindow(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i), SW_SHOW);
}
// Move/Resize the controls as needed to fit our text // Move/Resize the controls as needed to fit our text
hCtrl = GetDlgItem(hDlg, IDC_SELECTION_TEXT); hCtrl = GetDlgItem(hDlg, IDC_SELECTION_TEXT);
hDC = GetDC(hCtrl); hDC = GetDC(hCtrl);
@ -893,13 +910,16 @@ INT_PTR CALLBACK SelectionCallback(HWND hDlg, UINT message, WPARAM wParam, LPARA
dh = rect.bottom - rect.top - dh; dh = rect.bottom - rect.top - dh;
if (hDC != NULL) if (hDC != NULL)
ReleaseDC(hCtrl, hDC); ReleaseDC(hCtrl, hDC);
ResizeMoveCtrl(hDlg, hCtrl, 0, 0, 0, dh, 1.0f); ResizeMoveCtrl(hDlg, hCtrl, 0, 0, 0, dh, 1.0f);
for (i = 0; i < nChoices; i++)
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i), 0, dh, 0, 0, 1.0f);
if (nChoices > 2) {
GetWindowRect(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1), &rect);
dh += (nChoices - 1) * (rect.bottom - rect.top) - 5;
}
ResizeMoveCtrl(hDlg, hDlg, 0, 0, 0, dh, 1.0f); ResizeMoveCtrl(hDlg, hDlg, 0, 0, 0, dh, 1.0f);
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, -1), 0, 0, 0, dh, 1.0f); // IDC_STATIC = -1 ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, -1), 0, 0, 0, dh, 1.0f); // IDC_STATIC = -1
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_SELECTION_LINE), 0, dh, 0, 0, 1.0f); ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_SELECTION_LINE), 0, dh, 0, 0, 1.0f);
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_SELECTION_CHOICE1), 0, dh, 0, 0, 1.0f);
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_SELECTION_CHOICE2), 0, dh, 0, 0, 1.0f);
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDOK), 0, dh, 0, 0, 1.0f); ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDOK), 0, dh, 0, 0, 1.0f);
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDCANCEL), 0, dh, 0, 0, 1.0f); ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDCANCEL), 0, dh, 0, 0, 1.0f);
@ -926,10 +946,10 @@ INT_PTR CALLBACK SelectionCallback(HWND hDlg, UINT message, WPARAM wParam, LPARA
case WM_COMMAND: case WM_COMMAND:
switch (LOWORD(wParam)) { switch (LOWORD(wParam)) {
case IDOK: case IDOK:
if (Button_GetCheck(GetDlgItem(hDlg, IDC_SELECTION_CHOICE2)) == BST_CHECKED) for (i = 0; (i < nChoices) &&
r = 2; (Button_GetCheck(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i)) != BST_CHECKED); i++);
else if (i < nChoices)
r = 1; r = i + 1;
// Fall through // Fall through
case IDNO: case IDNO:
case IDCANCEL: case IDCANCEL:
@ -944,15 +964,15 @@ INT_PTR CALLBACK SelectionCallback(HWND hDlg, UINT message, WPARAM wParam, LPARA
/* /*
* Display a selection question * Display a selection question
*/ */
int Selection(char* title, char* message, char* choice1, char* choice2) int Selection(char* title, char* message, char** choices, int size)
{ {
int ret; int ret;
dialog_showing++; dialog_showing++;
szMessageTitle = title; szMessageTitle = title;
szMessageText = message; szMessageText = message;
szChoice1 = choice1; szChoice = choices;
szChoice2 = choice2; nChoices = size;
ret = (int)MyDialogBox(hMainInstance, IDD_SELECTION, hMainDialog, SelectionCallback); ret = (int)MyDialogBox(hMainInstance, IDD_SELECTION, hMainDialog, SelectionCallback);
dialog_showing--; dialog_showing--;
@ -1819,3 +1839,134 @@ void ClrFormatPromptHook(void) {
UnhookWinEvent(fp_weh); UnhookWinEvent(fp_weh);
fp_weh = NULL; fp_weh = NULL;
} }
#ifdef RUFUS_TEST
static inline LPWORD lpwAlign(LPWORD addr)
{
return (LPWORD)((((uintptr_t)addr) + 3) & (~3));
}
INT_PTR CALLBACK SelectionDynCallback(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
int r = -1;
switch (message) {
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
r = 0;
case IDCANCEL:
EndDialog(hwndDlg, r);
return (INT_PTR)TRUE;
}
}
return FALSE;
}
int SelectionDyn(char* title, char* message, char** szChoice, int nChoices)
{
#define ID_RADIO 12345
LPCWSTR lpwszTypeFace = L"MS Shell Dlg";
LPDLGTEMPLATEA lpdt;
LPDLGITEMTEMPLATEA lpdit;
LPCWSTR lpwszCaption;
LPWORD lpw;
LPWSTR lpwsz;
int i, ret, nchar;
lpdt = (LPDLGTEMPLATE)calloc(512 + nChoices * 256, 1);
// Set up a dialog window
lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION | DS_MODALFRAME | DS_CENTER | DS_SHELLFONT;
lpdt->cdit = 2 + nChoices;
lpdt->x = 10;
lpdt->y = 10;
lpdt->cx = 300;
lpdt->cy = 100;
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms645394.aspx:
// In a standard template for a dialog box, the DLGTEMPLATE structure is always immediately followed by
// three variable-length arrays that specify the menu, class, and title for the dialog box.
// When the DS_SETFONT style is specified, these arrays are also followed by a 16-bit value specifying
// point size and another variable-length array specifying a typeface name. Each array consists of one
// or more 16-bit elements. The menu, class, title, and font arrays must be aligned on WORD boundaries.
lpw = (LPWORD)(&lpdt[1]);
*lpw++ = 0; // No menu
*lpw++ = 0; // Default dialog class
lpwsz = (LPWSTR)lpw;
nchar = MultiByteToWideChar(CP_UTF8, 0, title, -1, lpwsz, 50);
lpw += nchar;
// Set point size and typeface name if required
if (lpdt->style & (DS_SETFONT | DS_SHELLFONT)) {
*lpw++ = 8;
for (lpwsz = (LPWSTR)lpw, lpwszCaption = lpwszTypeFace; (*lpwsz++ = *lpwszCaption++) != 0; );
lpw = (LPWORD)lpwsz;
}
// Add an OK button
lpw = lpwAlign(lpw);
lpdit = (LPDLGITEMTEMPLATE)lpw;
lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON;
lpdit->x = 10;
lpdit->y = 70;
lpdit->cx = 50;
lpdit->cy = 14;
lpdit->id = IDOK;
lpw = (LPWORD)(&lpdit[1]);
*lpw++ = 0xFFFF;
*lpw++ = 0x0080; // Button class
lpwsz = (LPWSTR)lpw;
nchar = MultiByteToWideChar(CP_UTF8, 0, "OK", -1, lpwsz, 50);
lpw += nchar;
*lpw++ = 0; // No creation data
// Add a Cancel button
lpw = lpwAlign(lpw);
lpdit = (LPDLGITEMTEMPLATE)lpw;
lpdit->x = 90;
lpdit->y = 70;
lpdit->cx = 50;
lpdit->cy = 14;
lpdit->id = IDCANCEL;
lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON;
lpw = (LPWORD)(&lpdit[1]);
*lpw++ = 0xFFFF;
*lpw++ = 0x0080;
lpwsz = (LPWSTR)lpw;
nchar = MultiByteToWideChar(CP_UTF8, 0, lmprintf(MSG_007), -1, lpwsz, 50);
lpw += nchar;
*lpw++ = 0;
// Add radio buttons
for (i = 0; i < nChoices; i++) {
lpw = lpwAlign(lpw);
lpdit = (LPDLGITEMTEMPLATE)lpw;
lpdit->x = 10;
lpdit->y = 10 + 15 * i;
lpdit->cx = 40;
lpdit->cy = 20;
lpdit->id = ID_RADIO;
lpdit->style = WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | (i == 0 ? WS_GROUP : 0);
lpw = (LPWORD)(&lpdit[1]);
*lpw++ = 0xFFFF;
*lpw++ = 0x0080;
lpwsz = (LPWSTR)lpw;
nchar = MultiByteToWideChar(CP_UTF8, 0, szChoice[i], -1, lpwsz, 150);
lpw += nchar;
*lpw++ = 0;
}
ret = (int)DialogBoxIndirect(hMainInstance, (LPDLGTEMPLATE)lpdt, hMainDialog, (DLGPROC)SelectionDynCallback);
free(lpdt);
return ret;
}
#endif

View File

@ -93,6 +93,7 @@ PF_TYPE_DECL(WINAPI, BOOL, WIMSetTemporaryPath, (HANDLE, PWSTR));
PF_TYPE_DECL(WINAPI, HANDLE, WIMLoadImage, (HANDLE, DWORD)); PF_TYPE_DECL(WINAPI, HANDLE, WIMLoadImage, (HANDLE, DWORD));
PF_TYPE_DECL(WINAPI, BOOL, WIMApplyImage, (HANDLE, PCWSTR, DWORD)); PF_TYPE_DECL(WINAPI, BOOL, WIMApplyImage, (HANDLE, PCWSTR, DWORD));
PF_TYPE_DECL(WINAPI, BOOL, WIMExtractImagePath, (HANDLE, PWSTR, PWSTR, DWORD)); PF_TYPE_DECL(WINAPI, BOOL, WIMExtractImagePath, (HANDLE, PWSTR, PWSTR, DWORD));
PF_TYPE_DECL(WINAPI, BOOL, WIMGetImageInformation, (HANDLE, PVOID, PDWORD));
PF_TYPE_DECL(WINAPI, BOOL, WIMCloseHandle, (HANDLE)); PF_TYPE_DECL(WINAPI, BOOL, WIMCloseHandle, (HANDLE));
PF_TYPE_DECL(WINAPI, DWORD, WIMRegisterMessageCallback, (HANDLE, FARPROC, PVOID)); PF_TYPE_DECL(WINAPI, DWORD, WIMRegisterMessageCallback, (HANDLE, FARPROC, PVOID));
PF_TYPE_DECL(WINAPI, DWORD, WIMUnregisterMessageCallback, (HANDLE, FARPROC)); PF_TYPE_DECL(WINAPI, DWORD, WIMUnregisterMessageCallback, (HANDLE, FARPROC));
@ -345,6 +346,7 @@ uint8_t WimExtractCheck(void)
PF_INIT(WIMLoadImage, Wimgapi); PF_INIT(WIMLoadImage, Wimgapi);
PF_INIT(WIMApplyImage, Wimgapi); PF_INIT(WIMApplyImage, Wimgapi);
PF_INIT(WIMExtractImagePath, Wimgapi); PF_INIT(WIMExtractImagePath, Wimgapi);
PF_INIT(WIMGetImageInformation, Wimgapi);
PF_INIT(WIMRegisterMessageCallback, Wimgapi); PF_INIT(WIMRegisterMessageCallback, Wimgapi);
PF_INIT(WIMUnregisterMessageCallback, Wimgapi); PF_INIT(WIMUnregisterMessageCallback, Wimgapi);
PF_INIT(WIMCloseHandle, Wimgapi); PF_INIT(WIMCloseHandle, Wimgapi);
@ -368,16 +370,19 @@ uint8_t WimExtractCheck(void)
// Extract a file from a WIM image using wimgapi.dll (Windows 7 or later) // Extract a file from a WIM image using wimgapi.dll (Windows 7 or later)
// NB: if you want progress from a WIM callback, you must run the WIM API call in its own thread // NB: if you want progress from a WIM callback, you must run the WIM API call in its own thread
// (which we don't do here) as it won't work otherwise. Thanks go to Erwan for figuring this out! // (which we don't do here) as it won't work otherwise. Thanks go to Erwan for figuring this out!
static BOOL WimExtractFile_API(const char* image, int index, const char* src, const char* dst) BOOL WimExtractFile_API(const char* image, int index, const char* src, const char* dst)
{ {
static char* index_name = "[1].xml";
BOOL r = FALSE; BOOL r = FALSE;
DWORD dw = 0; DWORD dw = 0;
HANDLE hWim = NULL; HANDLE hWim = NULL;
HANDLE hImage = NULL; HANDLE hImage = NULL;
HANDLE hFile = NULL;
wchar_t wtemp[MAX_PATH] = {0}; wchar_t wtemp[MAX_PATH] = {0};
wchar_t* wimage = utf8_to_wchar(image); wchar_t* wimage = utf8_to_wchar(image);
wchar_t* wsrc = utf8_to_wchar(src); wchar_t* wsrc = utf8_to_wchar(src);
wchar_t* wdst = utf8_to_wchar(dst); wchar_t* wdst = utf8_to_wchar(dst);
char* wim_info;
PF_INIT_OR_OUT(WIMCreateFile, Wimgapi); PF_INIT_OR_OUT(WIMCreateFile, Wimgapi);
PF_INIT_OR_OUT(WIMSetTemporaryPath, Wimgapi); PF_INIT_OR_OUT(WIMSetTemporaryPath, Wimgapi);
@ -402,19 +407,30 @@ static BOOL WimExtractFile_API(const char* image, int index, const char* src, co
goto out; goto out;
} }
hImage = pfWIMLoadImage(hWim, (DWORD)index);
if (hImage == NULL) {
uprintf(" Could not set index: %s", WindowsErrorString());
goto out;
}
uprintf("Extracting: %s (From %s)", dst, src); uprintf("Extracting: %s (From %s)", dst, src);
if (!pfWIMExtractImagePath(hImage, wsrc, wdst, 0)) { if (safe_strcmp(src, index_name) == 0) {
uprintf(" Could not extract file: %s", WindowsErrorString()); if (!pfWIMGetImageInformation(hWim, &wim_info, &dw)) {
goto out; uprintf(" Could not access WIM info: %s", WindowsErrorString());
goto out;
}
hFile = CreateFileW(wdst, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if ((hFile == INVALID_HANDLE_VALUE) || (!WriteFile(hFile, wim_info, dw, &dw, NULL))) {
uprintf(" Could not extract file: %s", WindowsErrorString());
goto out;
}
} else {
hImage = pfWIMLoadImage(hWim, (DWORD)index);
if (hImage == NULL) {
uprintf(" Could not set index: %s", WindowsErrorString());
goto out;
}
if (!pfWIMExtractImagePath(hImage, wsrc, wdst, 0)) {
uprintf(" Could not extract file: %s", WindowsErrorString());
goto out;
}
} }
r = TRUE; r = TRUE;
UpdateProgress(OP_FINALIZE, -1.0f);
out: out:
if ((hImage != NULL) || (hWim != NULL)) { if ((hImage != NULL) || (hWim != NULL)) {
@ -422,6 +438,7 @@ out:
if (hImage != NULL) pfWIMCloseHandle(hImage); if (hImage != NULL) pfWIMCloseHandle(hImage);
if (hWim != NULL) pfWIMCloseHandle(hWim); if (hWim != NULL) pfWIMCloseHandle(hWim);
} }
safe_closehandle(hFile);
safe_free(wimage); safe_free(wimage);
safe_free(wsrc); safe_free(wsrc);
safe_free(wdst); safe_free(wdst);
@ -429,7 +446,7 @@ out:
} }
// Extract a file from a WIM image using 7-Zip // Extract a file from a WIM image using 7-Zip
static BOOL WimExtractFile_7z(const char* image, int index, const char* src, const char* dst) BOOL WimExtractFile_7z(const char* image, int index, const char* src, const char* dst)
{ {
int n; int n;
size_t i; size_t i;
@ -455,10 +472,7 @@ static BOOL WimExtractFile_7z(const char* image, int index, const char* src, con
// to issue 2 passes. See github issue #680. // to issue 2 passes. See github issue #680.
for (n = 0; n < 2; n++) { for (n = 0; n < 2; n++) {
safe_strcpy(tmpdst, sizeof(tmpdst), dst); safe_strcpy(tmpdst, sizeof(tmpdst), dst);
for (i = strlen(tmpdst) - 1; i > 0; i--) { for (i = strlen(tmpdst) - 1; (i > 0) && (tmpdst[i] != '\\') && (tmpdst[i] != '/'); i--);
if (tmpdst[i] == '\\')
break;
}
tmpdst[i] = 0; tmpdst[i] = 0;
safe_sprintf(cmdline, sizeof(cmdline), "\"%s\" -y e \"%s\" %s%s", sevenzip_path, safe_sprintf(cmdline, sizeof(cmdline), "\"%s\" -y e \"%s\" %s%s", sevenzip_path,
@ -468,7 +482,10 @@ static BOOL WimExtractFile_7z(const char* image, int index, const char* src, con
return FALSE; return FALSE;
} }
safe_strcat(tmpdst, sizeof(tmpdst), "\\bootmgfw.efi"); for (i = safe_strlen(src); (i > 0) && (src[i] != '\\') && (src[i] != '/'); i--);
if (i == 0)
safe_strcat(tmpdst, sizeof(tmpdst), "\\");
safe_strcat(tmpdst, sizeof(tmpdst), &src[i]);
if (_access(tmpdst, 0) == 0) if (_access(tmpdst, 0) == 0)
// File was extracted => move on // File was extracted => move on
break; break;
@ -481,7 +498,7 @@ static BOOL WimExtractFile_7z(const char* image, int index, const char* src, con
// coverity[toctou] // coverity[toctou]
if (rename(tmpdst, dst) != 0) { if (rename(tmpdst, dst) != 0) {
uprintf(" Could not rename %s to %s", tmpdst, dst); uprintf(" Could not rename %s to %s: errno %d", tmpdst, dst, errno);
return FALSE; return FALSE;
} }