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:
		
							parent
							
								
									5bbcba8534
								
							
						
					
					
						commit
						5191c68337
					
				
					 8 changed files with 156 additions and 204 deletions
				
			
		|  | @ -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)) { | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
							
								
								
									
										13
									
								
								src/rufus.c
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								src/rufus.c
									
										
									
									
									
								
							|  | @ -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); | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
|  |  | ||||||
							
								
								
									
										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 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" | ||||||
|  |  | ||||||
|  | @ -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" | ||||||
|  |  | ||||||
							
								
								
									
										239
									
								
								src/stdlg.c
									
										
									
									
									
								
							
							
						
						
									
										239
									
								
								src/stdlg.c
									
										
									
									
									
								
							|  | @ -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; | ||||||
|  |  | ||||||
							
								
								
									
										87
									
								
								src/vhd.c
									
										
									
									
									
								
							
							
						
						
									
										87
									
								
								src/vhd.c
									
										
									
									
									
								
							|  | @ -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); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue