1
1
Fork 0
mirror of https://github.com/pbatard/rufus.git synced 2024-08-14 23:57:05 +00:00

[ui] keep user preferred image type when saving drive to VHD

* Also fix a Coverity warning and use a better description for SELECT image types.
This commit is contained in:
Pete Batard 2023-07-10 11:34:50 +02:00
parent 5bbcba8534
commit 5191c68337
No known key found for this signature in database
GPG key ID: 38E0CF5E69EDD671
8 changed files with 156 additions and 204 deletions

View file

@ -1642,12 +1642,13 @@ DWORD WINAPI FormatThread(void* param)
if ((boot_type == BT_IMAGE) && write_as_image) { if ((boot_type == BT_IMAGE) && write_as_image) {
// Special case for FFU images // Special case for FFU images
if (img_report.compression_type == IMG_COMPRESSION_FFU) { if (img_report.compression_type == IMG_COMPRESSION_FFU) {
char cmd[MAX_PATH + 128], *physical; char cmd[MAX_PATH + 128], *physical = NULL;
// Should have been filtered out beforehand // Should have been filtered out beforehand
assert(has_ffu_support); assert(has_ffu_support);
safe_unlockclose(hPhysicalDrive); safe_unlockclose(hPhysicalDrive);
physical = GetPhysicalName(SelectedDrive.DeviceNumber); physical = GetPhysicalName(SelectedDrive.DeviceNumber);
static_sprintf(cmd, "dism /Apply-Ffu /ApplyDrive:%s /ImageFile:\"%s\"", physical, image_path); static_sprintf(cmd, "dism /Apply-Ffu /ApplyDrive:%s /ImageFile:\"%s\"", physical, image_path);
safe_free(physical);
uprintf("Running command: '%s", cmd); uprintf("Running command: '%s", cmd);
cr = RunCommandWithProgress(cmd, sysnative_dir, TRUE, MSG_261); cr = RunCommandWithProgress(cmd, sysnative_dir, TRUE, MSG_261);
if (cr != 0 && !IS_ERROR(FormatStatus)) { if (cr != 0 && !IS_ERROR(FormatStatus)) {

View file

@ -1040,7 +1040,7 @@ static DWORD WINAPI DownloadISOThread(LPVOID param)
#endif #endif
EXT_DECL(img_ext, GetShortName(url), __VA_GROUP__("*.iso"), __VA_GROUP__(lmprintf(MSG_036))); EXT_DECL(img_ext, GetShortName(url), __VA_GROUP__("*.iso"), __VA_GROUP__(lmprintf(MSG_036)));
img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_ISO; img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_ISO;
img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, 0); img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, NULL);
if (img_save.ImagePath == NULL) { if (img_save.ImagePath == NULL) {
goto out; goto out;
} }

View file

@ -139,7 +139,7 @@ char embedded_sl_version_str[2][12] = { "?.??", "?.??" };
char embedded_sl_version_ext[2][32]; char embedded_sl_version_ext[2][32];
char ClusterSizeLabel[MAX_CLUSTER_SIZES][64]; char ClusterSizeLabel[MAX_CLUSTER_SIZES][64];
char msgbox[1024], msgbox_title[32], *ini_file = NULL, *image_path = NULL, *short_image_path; char msgbox[1024], msgbox_title[32], *ini_file = NULL, *image_path = NULL, *short_image_path;
char *archive_path = NULL, image_option_txt[128], *fido_url = NULL; char *archive_path = NULL, image_option_txt[128], *fido_url = NULL, *save_image_type = NULL;
StrArray BlockingProcess, ImageList; StrArray BlockingProcess, ImageList;
// Number of steps for each FS for FCC_STRUCTURE_PROGRESS // Number of steps for each FS for FCC_STRUCTURE_PROGRESS
const int nb_steps[FS_MAX] = { 5, 5, 12, 1, 10, 1, 1, 1, 1 }; const int nb_steps[FS_MAX] = { 5, 5, 12, 1, 10, 1, 1, 1, 1 };
@ -1013,7 +1013,7 @@ BOOL CALLBACK LogCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
log_size = GetDlgItemTextU(hDlg, IDC_LOG_EDIT, log_buffer, log_size); log_size = GetDlgItemTextU(hDlg, IDC_LOG_EDIT, log_buffer, log_size);
if (log_size != 0) { if (log_size != 0) {
log_size--; // remove NUL terminator log_size--; // remove NUL terminator
filepath = FileDialog(TRUE, user_dir, &log_ext, 0); filepath = FileDialog(TRUE, user_dir, &log_ext, NULL);
if (filepath != NULL) if (filepath != NULL)
FileIO(FILE_IO_WRITE, filepath, &log_buffer, &log_size); FileIO(FILE_IO_WRITE, filepath, &log_buffer, &log_size);
safe_free(filepath); safe_free(filepath);
@ -2567,7 +2567,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
EXT_DECL(arch_ext, NULL, __VA_GROUP__("*.zip"), __VA_GROUP__(lmprintf(MSG_309))); EXT_DECL(arch_ext, NULL, __VA_GROUP__("*.zip"), __VA_GROUP__(lmprintf(MSG_309)));
if (image_path == NULL) if (image_path == NULL)
break; break;
archive_path = FileDialog(FALSE, NULL, &arch_ext, 0); archive_path = FileDialog(FALSE, NULL, &arch_ext, NULL);
if (archive_path != NULL) { if (archive_path != NULL) {
struct __stat64 stat64 = { 0 }; struct __stat64 stat64 = { 0 };
_stat64U(archive_path, &stat64); _stat64U(archive_path, &stat64);
@ -2591,10 +2591,10 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
char extensions[128] = "*.iso;*.img;*.vhd;*.vhdx;*.usb;*.bz2;*.bzip2;*.gz;*.lzma;*.xz;*.Z;*.zip;*.wim;*.esd;*.vtsi"; char extensions[128] = "*.iso;*.img;*.vhd;*.vhdx;*.usb;*.bz2;*.bzip2;*.gz;*.lzma;*.xz;*.Z;*.zip;*.wim;*.esd;*.vtsi";
if (has_ffu_support) if (has_ffu_support)
strcat(extensions, ";*.ffu"); strcat(extensions, ";*.ffu");
// If declared globaly, lmprintf(MSG_036) would be called on each message... // If declared globaly, lmprintf(MSG_280) would be called on each message...
EXT_DECL(img_ext, NULL, __VA_GROUP__(extensions), EXT_DECL(img_ext, NULL, __VA_GROUP__(extensions),
__VA_GROUP__(lmprintf(MSG_036))); __VA_GROUP__(lmprintf(MSG_280)));
image_path = FileDialog(FALSE, NULL, &img_ext, 0); image_path = FileDialog(FALSE, NULL, &img_ext, NULL);
if (image_path == NULL) { if (image_path == NULL) {
if (old_image_path != NULL) { if (old_image_path != NULL) {
// Reselect previous image // Reselect previous image
@ -3556,6 +3556,7 @@ skip_args_processing:
enable_extra_hashes = ReadSettingBool(SETTING_ENABLE_EXTRA_HASHES); enable_extra_hashes = ReadSettingBool(SETTING_ENABLE_EXTRA_HASHES);
ignore_boot_marker = ReadSettingBool(SETTING_IGNORE_BOOT_MARKER); ignore_boot_marker = ReadSettingBool(SETTING_IGNORE_BOOT_MARKER);
persistent_log = ReadSettingBool(SETTING_PERSISTENT_LOG); persistent_log = ReadSettingBool(SETTING_PERSISTENT_LOG);
save_image_type = ReadSettingStr(SETTING_PREFERRED_SAVE_IMAGE_TYPE);
// This restores the Windows User Experience/unattend.xml mask from the saved user // This restores the Windows User Experience/unattend.xml mask from the saved user
// settings, and is designed to work even if we add new options later. // settings, and is designed to work even if we add new options later.
wue_options = ReadSetting32(SETTING_WUE_OPTIONS); wue_options = ReadSetting32(SETTING_WUE_OPTIONS);

View file

@ -655,7 +655,7 @@ extern BOOL DumpFatDir(const char* path, int32_t cluster);
extern BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs); extern BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs);
extern uint16_t GetSyslinuxVersion(char* buf, size_t buf_size, char** ext); extern uint16_t GetSyslinuxVersion(char* buf, size_t buf_size, char** ext);
extern BOOL SetAutorun(const char* path); extern BOOL SetAutorun(const char* path);
extern char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options); extern char* FileDialog(BOOL save, char* path, const ext_t* ext, UINT* selected_ext);
extern BOOL FileIO(enum file_io_type io_type, char* path, char** buffer, DWORD* size); extern BOOL FileIO(enum file_io_type io_type, char* path, char** buffer, DWORD* size);
extern unsigned char* GetResource(HMODULE module, char* name, char* type, const char* desc, DWORD* len, BOOL duplicate); extern unsigned char* GetResource(HMODULE module, char* name, char* type, const char* desc, DWORD* len, BOOL duplicate);
extern DWORD GetResourceSize(HMODULE module, char* name, char* type, const char* desc); extern DWORD GetResourceSize(HMODULE module, char* name, char* type, const char* desc);

View file

@ -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 4.2.2068" CAPTION "Rufus 4.2.2069"
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
@ -392,8 +392,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,2,2068,0 FILEVERSION 4,2,2069,0
PRODUCTVERSION 4,2,2068,0 PRODUCTVERSION 4,2,2069,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -411,13 +411,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", "4.2.2068" VALUE "FileVersion", "4.2.2069"
VALUE "InternalName", "Rufus" VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2023 Pete Batard (GPL v3)" VALUE "LegalCopyright", "© 2011-2023 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-4.2.exe" VALUE "OriginalFilename", "rufus-4.2.exe"
VALUE "ProductName", "Rufus" VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "4.2.2068" VALUE "ProductVersion", "4.2.2069"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -1,7 +1,7 @@
/* /*
* Rufus: The Reliable USB Formatting Utility * Rufus: The Reliable USB Formatting Utility
* Settings access, through either registry or INI file * Settings access, through either registry or INI file
* Copyright © 2015-2022 Pete Batard <pete@akeo.ie> * Copyright © 2015-2023 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
@ -19,6 +19,7 @@
#include <windows.h> #include <windows.h>
#include <stdint.h> #include <stdint.h>
#include "rufus.h" #include "rufus.h"
#include "msapi_utf8.h"
#include "registry.h" #include "registry.h"
#pragma once #pragma once
@ -52,6 +53,7 @@ extern char* ini_file;
#define SETTING_USE_UDF_VERSION "UseUdfVersion" #define SETTING_USE_UDF_VERSION "UseUdfVersion"
#define SETTING_USE_VDS "UseVds" #define SETTING_USE_VDS "UseVds"
#define SETTING_PERSISTENT_LOG "PersistentLog" #define SETTING_PERSISTENT_LOG "PersistentLog"
#define SETTING_PREFERRED_SAVE_IMAGE_TYPE "PreferredSaveImageType"
#define SETTING_PRESERVE_TIMESTAMPS "PreserveTimestamps" #define SETTING_PRESERVE_TIMESTAMPS "PreserveTimestamps"
#define SETTING_VERBOSE_UPDATES "VerboseUpdateCheck" #define SETTING_VERBOSE_UPDATES "VerboseUpdateCheck"
#define SETTING_WUE_OPTIONS "WindowsUserExperienceOptions" #define SETTING_WUE_OPTIONS "WindowsUserExperienceOptions"

View file

@ -90,14 +90,9 @@ void SetDialogFocus(HWND hDlg, HWND hCtrl)
* *EACH* thread you invoke FileDialog from, as GetDisplayName() will * *EACH* thread you invoke FileDialog from, as GetDisplayName() will
* return error 0x8001010E otherwise. * return error 0x8001010E otherwise.
*/ */
char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options) char* FileDialog(BOOL save, char* path, const ext_t* ext, UINT* selected_ext)
{ {
DWORD tmp; size_t i;
OPENFILENAMEA ofn;
char selected_name[MAX_PATH];
char *ext_string = NULL, *all_files = NULL;
size_t i, j, ext_strlen;
BOOL r;
char* filepath = NULL; char* filepath = NULL;
HRESULT hr = FALSE; HRESULT hr = FALSE;
IFileDialog *pfd = NULL; IFileDialog *pfd = NULL;
@ -108,167 +103,107 @@ char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options)
if ((ext == NULL) || (ext->count == 0) || (ext->extension == NULL) || (ext->description == NULL)) if ((ext == NULL) || (ext->count == 0) || (ext->extension == NULL) || (ext->description == NULL))
return NULL; return NULL;
dialog_showing++;
filter_spec = (COMDLG_FILTERSPEC*)calloc(ext->count + 1, sizeof(COMDLG_FILTERSPEC)); filter_spec = (COMDLG_FILTERSPEC*)calloc(ext->count + 1, sizeof(COMDLG_FILTERSPEC));
if (filter_spec != NULL) { if (filter_spec == NULL)
// Setup the file extension filter table return NULL;
for (i = 0; i < ext->count; i++) {
filter_spec[i].pszSpec = utf8_to_wchar(ext->extension[i]);
filter_spec[i].pszName = utf8_to_wchar(ext->description[i]);
}
filter_spec[i].pszSpec = L"*.*";
filter_spec[i].pszName = utf8_to_wchar(lmprintf(MSG_107));
hr = CoCreateInstance(save ? &CLSID_FileSaveDialog : &CLSID_FileOpenDialog, NULL, CLSCTX_INPROC, dialog_showing++;
&IID_IFileDialog, (LPVOID)&pfd);
if (FAILED(hr)) { // Setup the file extension filter table
SetLastError(hr); for (i = 0; i < ext->count; i++) {
uprintf("CoCreateInstance for FileOpenDialog failed: %s\n", WindowsErrorString()); filter_spec[i].pszSpec = utf8_to_wchar(ext->extension[i]);
if (pfd != NULL) { filter_spec[i].pszName = utf8_to_wchar(ext->description[i]);
IFileDialog_Release(pfd); }
pfd = NULL; // Just in case filter_spec[i].pszSpec = L"*.*";
} filter_spec[i].pszName = utf8_to_wchar(lmprintf(MSG_107));
goto fallback;
}
// Set the file extension filters hr = CoCreateInstance(save ? &CLSID_FileSaveDialog : &CLSID_FileOpenDialog, NULL, CLSCTX_INPROC,
IFileDialog_SetFileTypes(pfd, (UINT)ext->count + 1, filter_spec); &IID_IFileDialog, (LPVOID)&pfd);
if (path == NULL) { if (FAILED(hr)) {
// Try to use the "Downloads" folder as the initial default directory SetLastError(hr);
const GUID download_dir_guid = uprintf("CoCreateInstance for FileOpenDialog failed: %s\n", WindowsErrorString());
{ 0x374de290, 0x123f, 0x4565, { 0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b } }; if (pfd != NULL)
hr = SHGetKnownFolderPath(&download_dir_guid, 0, 0, &wpath); goto out;
if (SUCCEEDED(hr)) { }
hr = SHCreateItemFromParsingName(wpath, NULL, &IID_IShellItem, (LPVOID)&si_path);
if (SUCCEEDED(hr)) { // Set the file extension filters
IFileDialog_SetDefaultFolder(pfd, si_path); IFileDialog_SetFileTypes(pfd, (UINT)ext->count + 1, filter_spec);
}
CoTaskMemFree(wpath); if (path == NULL) {
} // Try to use the "Downloads" folder as the initial default directory
} else { const GUID download_dir_guid =
wpath = utf8_to_wchar(path); { 0x374de290, 0x123f, 0x4565, { 0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b } };
hr = SHGetKnownFolderPath(&download_dir_guid, 0, 0, &wpath);
if (SUCCEEDED(hr)) {
hr = SHCreateItemFromParsingName(wpath, NULL, &IID_IShellItem, (LPVOID)&si_path); hr = SHCreateItemFromParsingName(wpath, NULL, &IID_IShellItem, (LPVOID)&si_path);
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
IFileDialog_SetFolder(pfd, si_path); IFileDialog_SetDefaultFolder(pfd, si_path);
} }
safe_free(wpath); CoTaskMemFree(wpath);
} }
} else {
// Set the default filename wpath = utf8_to_wchar(path);
wfilename = utf8_to_wchar((ext->filename == NULL) ? "" : ext->filename); hr = SHCreateItemFromParsingName(wpath, NULL, &IID_IShellItem, (LPVOID)&si_path);
if (wfilename != NULL) {
IFileDialog_SetFileName(pfd, wfilename);
}
// Set a default extension so that when the user switches filters it gets
// automatically updated. Note that the IFileDialog::SetDefaultExtension()
// doc says the extension shouldn't be prefixed with unwanted characters
// but it appears to work regardless so we don't bother cleaning it.
wext = utf8_to_wchar((ext->extension == NULL) ? "" : ext->extension[0]);
if (wext != NULL) {
IFileDialog_SetDefaultExtension(pfd, wext);
}
// Display the dialog
hr = IFileDialog_Show(pfd, hMainDialog);
// Cleanup
safe_free(wext);
safe_free(wfilename);
for (i = 0; i < ext->count; i++) {
safe_free(filter_spec[i].pszSpec);
safe_free(filter_spec[i].pszName);
}
safe_free(filter_spec[i].pszName);
safe_free(filter_spec);
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
// Obtain the result of the user's interaction with the dialog. IFileDialog_SetFolder(pfd, si_path);
hr = IFileDialog_GetResult(pfd, &psiResult);
if (SUCCEEDED(hr)) {
hr = IShellItem_GetDisplayName(psiResult, SIGDN_FILESYSPATH, &wpath);
if (SUCCEEDED(hr)) {
filepath = wchar_to_utf8(wpath);
CoTaskMemFree(wpath);
} else {
SetLastError(hr);
uprintf("Unable to access file path: %s\n", WindowsErrorString());
}
IShellItem_Release(psiResult);
}
} else if ((hr & 0xFFFF) != ERROR_CANCELLED) {
// If it's not a user cancel, assume the dialog didn't show and fallback
SetLastError(hr);
uprintf("Could not show FileOpenDialog: %s\n", WindowsErrorString());
goto fallback;
} }
IFileDialog_Release(pfd); safe_free(wpath);
dialog_showing--;
return filepath;
} }
fallback: // Set the default filename
wfilename = utf8_to_wchar((ext->filename == NULL) ? "" : ext->filename);
if (wfilename != NULL)
IFileDialog_SetFileName(pfd, wfilename);
// Set a default extension so that when the user switches filters it gets
// automatically updated. Note that the IFileDialog::SetDefaultExtension()
// doc says the extension shouldn't be prefixed with unwanted characters
// but it appears to work regardless so we don't bother cleaning it.
wext = utf8_to_wchar((ext->extension == NULL) ? "" : ext->extension[0]);
if (wext != NULL)
IFileDialog_SetDefaultExtension(pfd, wext);
// Set the current selected extension
IFileDialog_SetFileTypeIndex(pfd, selected_ext == NULL ? 0 : *selected_ext);
// Display the dialog and (optionally) get the selected extension index
hr = IFileDialog_Show(pfd, hMainDialog);
if (selected_ext != NULL)
IFileDialog_GetFileTypeIndex(pfd, selected_ext);
// Cleanup
safe_free(wext);
safe_free(wfilename);
for (i = 0; i < ext->count; i++) {
safe_free(filter_spec[i].pszSpec);
safe_free(filter_spec[i].pszName);
}
safe_free(filter_spec[i].pszName);
safe_free(filter_spec); safe_free(filter_spec);
if (pfd != NULL) {
IFileDialog_Release(pfd); if (SUCCEEDED(hr)) {
// Obtain the result of the user's interaction with the dialog.
hr = IFileDialog_GetResult(pfd, &psiResult);
if (SUCCEEDED(hr)) {
hr = IShellItem_GetDisplayName(psiResult, SIGDN_FILESYSPATH, &wpath);
if (SUCCEEDED(hr)) {
filepath = wchar_to_utf8(wpath);
CoTaskMemFree(wpath);
} else {
SetLastError(hr);
uprintf("Unable to access file path: %s", WindowsErrorString());
}
IShellItem_Release(psiResult);
}
} else if ((hr & 0xFFFF) != ERROR_CANCELLED) {
// If it's not a user cancel, assume the dialog didn't show and fallback
SetLastError(hr);
uprintf("Could not show FileOpenDialog: %s", WindowsErrorString());
} }
memset(&ofn, 0, sizeof(ofn)); out:
ofn.lStructSize = sizeof(ofn); if (pfd != NULL)
ofn.hwndOwner = hMainDialog; IFileDialog_Release(pfd);
// Selected File name
static_sprintf(selected_name, "%s", (ext->filename == NULL)?"":ext->filename);
ofn.lpstrFile = selected_name;
ofn.nMaxFile = MAX_PATH;
// Set the file extension filters
all_files = lmprintf(MSG_107);
ext_strlen = 0;
for (i=0; i<ext->count; i++) {
ext_strlen += safe_strlen(ext->description[i]) + 2*safe_strlen(ext->extension[i]) + sizeof(" ()\r\r");
}
ext_strlen += safe_strlen(all_files) + sizeof(" (*.*)\r*.*\r");
ext_string = (char*)malloc(ext_strlen+1);
if (ext_string == NULL)
return NULL;
ext_string[0] = 0;
for (i=0, j=0; i<ext->count; i++) {
j += _snprintf(&ext_string[j], ext_strlen-j, "%s (%s)\r%s\r", ext->description[i], ext->extension[i], ext->extension[i]);
}
j = _snprintf(&ext_string[j], ext_strlen-j, "%s (*.*)\r*.*\r", all_files);
// Microsoft could really have picked a better delimiter!
for (i=0; i<ext_strlen; i++) {
// Since the VS Code Analysis tool is dumb...
#if defined(_MSC_VER)
#pragma warning(suppress: 6385)
#endif
if (ext_string[i] == '\r') {
#if defined(_MSC_VER)
#pragma warning(suppress: 6386)
#endif
ext_string[i] = 0;
}
}
ofn.lpstrFilter = ext_string;
ofn.nFilterIndex = 1;
ofn.lpstrInitialDir = path;
ofn.Flags = OFN_OVERWRITEPROMPT | options;
// Show Dialog
if (save) {
r = GetSaveFileNameU(&ofn);
} else {
r = GetOpenFileNameU(&ofn);
}
if (r) {
filepath = safe_strdup(selected_name);
} else {
tmp = CommDlgExtendedError();
if (tmp != 0) {
uprintf("Could not select file for %s. Error %X\n", save?"save":"open", tmp);
}
}
safe_free(ext_string);
dialog_showing--; dialog_showing--;
return filepath; return filepath;
} }
@ -1700,7 +1635,7 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR
break; break;
} }
dl_ext.filename = PathFindFileNameU(update.download_url); dl_ext.filename = PathFindFileNameU(update.download_url);
filepath = FileDialog(TRUE, app_dir, &dl_ext, OFN_NOCHANGEDIR); filepath = FileDialog(TRUE, app_dir, &dl_ext, NULL);
if (filepath == NULL) { if (filepath == NULL) {
uprintf("Could not get save path"); uprintf("Could not get save path");
break; break;

View file

@ -29,6 +29,7 @@
#include "vhd.h" #include "vhd.h"
#include "missing.h" #include "missing.h"
#include "resource.h" #include "resource.h"
#include "settings.h"
#include "msapi_utf8.h" #include "msapi_utf8.h"
#include "drive.h" #include "drive.h"
@ -58,6 +59,7 @@ typedef struct {
uint32_t wim_nb_files, wim_proc_files, wim_extra_files; uint32_t wim_nb_files, wim_proc_files, wim_extra_files;
HANDLE wim_thread = NULL; HANDLE wim_thread = NULL;
extern int default_thread_priority; extern int default_thread_priority;
extern char* save_image_type;
extern BOOL ignore_boot_marker, has_ffu_support; extern BOOL ignore_boot_marker, has_ffu_support;
extern RUFUS_DRIVE rufus_drive[MAX_DRIVES]; extern RUFUS_DRIVE rufus_drive[MAX_DRIVES];
extern HANDLE format_thread; extern HANDLE format_thread;
@ -1099,68 +1101,79 @@ static DWORD WINAPI FfuSaveImageThread(void* param)
void VhdSaveImage(void) void VhdSaveImage(void)
{ {
static IMG_SAVE img_save = { 0 }; UINT i;
static IMG_SAVE img_save;
char filename[128]; char filename[128];
char path[MAX_PATH]; char path[MAX_PATH];
int DriveIndex = ComboBox_GetCurSel(hDeviceList); int DriveIndex = ComboBox_GetCurSel(hDeviceList);
EXT_DECL(img_ext, filename, __VA_GROUP__("*.vhdx", "*.vhd", "*.ffu"), static EXT_DECL(img_ext, filename, __VA_GROUP__("*.vhd", "*.vhdx", "*.ffu"),
__VA_GROUP__(lmprintf(MSG_342), lmprintf(MSG_343), lmprintf(MSG_344))); __VA_GROUP__(lmprintf(MSG_343), lmprintf(MSG_342), lmprintf(MSG_344)));
ULARGE_INTEGER free_space; ULARGE_INTEGER free_space;
memset(&img_save, 0, sizeof(IMG_SAVE));
if ((DriveIndex < 0) || (format_thread != NULL)) if ((DriveIndex < 0) || (format_thread != NULL))
return; return;
static_sprintf(filename, "%s.vhdx", rufus_drive[DriveIndex].label); static_sprintf(filename, "%s", rufus_drive[DriveIndex].label);
img_save.DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, DriveIndex); img_save.DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, DriveIndex);
img_save.DevicePath = GetPhysicalName(img_save.DeviceNum); img_save.DevicePath = GetPhysicalName(img_save.DeviceNum);
// FFU support requires GPT // FFU support requires GPT
if (!has_ffu_support || SelectedDrive.PartitionStyle != PARTITION_STYLE_GPT) if (!has_ffu_support || SelectedDrive.PartitionStyle != PARTITION_STYLE_GPT)
img_ext.count = 2; img_ext.count = 2;
img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, 0); for (i = 1; i <= (UINT)img_ext.count && (safe_strcmp(&_img_ext_x[i - 1][2], save_image_type) != 0); i++);
img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_VHD; if (i > (UINT)img_ext.count)
if (safe_strstr(img_save.ImagePath, ".vhdx") != NULL) i = 2;
img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, &i);
assert(i > 0 && i <= (UINT)img_ext.count);
save_image_type = (char*) &_img_ext_x[i - 1][2];
WriteSettingStr(SETTING_PREFERRED_SAVE_IMAGE_TYPE, save_image_type);
switch (i) {
case 1:
img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_VHD; img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_VHD;
else if (safe_strstr(img_save.ImagePath, ".ffu") != NULL) break;
case 3:
img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_FFU; img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_FFU;
break;
default:
img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_VHDX;
break;
}
img_save.BufSize = DD_BUFFER_SIZE; img_save.BufSize = DD_BUFFER_SIZE;
img_save.DeviceSize = SelectedDrive.DiskSize; img_save.DeviceSize = SelectedDrive.DiskSize;
if (img_save.DevicePath != NULL && img_save.ImagePath != NULL) { if (img_save.DevicePath != NULL && img_save.ImagePath != NULL) {
// Reset all progress bars // Reset all progress bars
SendMessage(hMainDialog, UM_PROGRESS_INIT, 0, 0); SendMessage(hMainDialog, UM_PROGRESS_INIT, 0, 0);
FormatStatus = 0; FormatStatus = 0;
free_space.QuadPart = 0; if (img_save.Type == VIRTUAL_STORAGE_TYPE_DEVICE_VHD) {
if ((GetVolumePathNameA(img_save.ImagePath, path, sizeof(path))) free_space.QuadPart = 0;
&& (GetDiskFreeSpaceExA(path, &free_space, NULL, NULL)) if ((GetVolumePathNameA(img_save.ImagePath, path, sizeof(path)))
&& ((LONGLONG)free_space.QuadPart > (SelectedDrive.DiskSize + 512))) { && (GetDiskFreeSpaceExA(path, &free_space, NULL, NULL))
// Disable all controls except Cancel && ((LONGLONG)free_space.QuadPart < (SelectedDrive.DiskSize + 512))) {
EnableControls(FALSE, FALSE);
FormatStatus = 0;
InitProgress(TRUE);
format_thread = CreateThread(NULL, 0, img_save.Type == VIRTUAL_STORAGE_TYPE_DEVICE_FFU ?
FfuSaveImageThread : VhdSaveImageThread, &img_save, 0, NULL);
if (format_thread != NULL) {
uprintf("\r\nSave to VHD operation started");
PrintInfo(0, -1);
SendMessage(hMainDialog, UM_TIMER_START, 0, 0);
} else {
uprintf("Unable to start VHD save thread");
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_START_THREAD);
safe_free(img_save.DevicePath);
safe_free(img_save.ImagePath);
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
}
} else {
if (free_space.QuadPart == 0) {
uprintf("Unable to isolate drive name for VHD save");
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_PATH_NOT_FOUND;
} else {
// TODO: Might be salvageable for compressed VHDX
uprintf("The VHD size is too large for the target drive"); uprintf("The VHD size is too large for the target drive");
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_FILE_TOO_LARGE; FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_FILE_TOO_LARGE;
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
goto out;
} }
safe_free(img_save.DevicePath); }
safe_free(img_save.ImagePath); // Disable all controls except Cancel
EnableControls(FALSE, FALSE);
FormatStatus = 0;
InitProgress(TRUE);
format_thread = CreateThread(NULL, 0, img_save.Type == VIRTUAL_STORAGE_TYPE_DEVICE_FFU ?
FfuSaveImageThread : VhdSaveImageThread, &img_save, 0, NULL);
if (format_thread != NULL) {
uprintf("\r\nSave to VHD operation started");
PrintInfo(0, -1);
SendMessage(hMainDialog, UM_TIMER_START, 0, 0);
} else {
uprintf("Unable to start VHD save thread");
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_START_THREAD);
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0); PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
} }
} }
out:
if (format_thread == NULL) {
safe_free(img_save.DevicePath);
safe_free(img_save.ImagePath);
}
} }