"Fossies" - the Fresh Open Source Software Archive 
Member "rufus-3.13/src/rufus.c" (20 Nov 2020, 154986 Bytes) of package /linux/misc/rufus-3.13.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "rufus.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
3.12_vs_3.13.
1 /*
2 * Rufus: The Reliable USB Formatting Utility
3 * Copyright © 2011-2020 Pete Batard <pete@akeo.ie>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /* Memory leaks detection - define _CRTDBG_MAP_ALLOC as preprocessor macro */
20 #ifdef _CRTDBG_MAP_ALLOC
21 #include <stdlib.h>
22 #include <crtdbg.h>
23 #endif
24
25
26 #include <windows.h>
27 #include <windowsx.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <math.h>
32 #include <winioctl.h>
33 #include <shlobj.h>
34 #include <process.h>
35 #include <dwmapi.h>
36 #include <dbt.h>
37 #include <io.h>
38 #include <getopt.h>
39 #include <assert.h>
40
41 #include "rufus.h"
42 #include "missing.h"
43 #include "resource.h"
44 #include "msapi_utf8.h"
45 #include "localization.h"
46
47 #include "ui.h"
48 #include "drive.h"
49 #include "settings.h"
50 #include "bled/bled.h"
51 #include "cdio/logging.h"
52 #include "../res/grub/grub_version.h"
53 #include "../res/grub2/grub2_version.h"
54
55 enum bootcheck_return {
56 BOOTCHECK_PROCEED = 0,
57 BOOTCHECK_CANCEL = -1,
58 BOOTCHECK_DOWNLOAD_ERROR = -2,
59 BOOTCHECK_GENERAL_ERROR = -3,
60 };
61
62 static const char* cmdline_hogger = "rufus.com";
63 static const char* ep_reg = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer";
64 static const char* vs_reg = "Software\\Microsoft\\VisualStudio";
65 static const char* arch_name[MAX_ARCHS] = {
66 "x86_32", "Itanic", "x86_64", "ARM", "ARM64", "EBC","Risc-V 32", "Risc-V 64", "Risc-V 128" };
67 static BOOL existing_key = FALSE; // For LGP set/restore
68 static BOOL size_check = TRUE;
69 static BOOL log_displayed = FALSE;
70 static BOOL img_provided = FALSE;
71 static BOOL user_notified = FALSE;
72 static BOOL relaunch = FALSE;
73 static BOOL dont_display_image_name = FALSE;
74 static BOOL user_changed_label = FALSE;
75 static BOOL app_changed_label = FALSE;
76 static BOOL allowed_filesystem[FS_MAX] = { 0 };
77 static int64_t last_iso_blocking_status;
78 static int selected_pt = -1, selected_fs = FS_UNKNOWN, preselected_fs = FS_UNKNOWN;
79 static int image_index = 0, select_index = 0;
80 static RECT relaunch_rc = { -65536, -65536, 0, 0};
81 static UINT uMBRChecked = BST_UNCHECKED;
82 static HANDLE format_thread = NULL;
83 static HWND hSelectImage = NULL, hStart = NULL;
84 static char szTimer[12] = "00:00:00";
85 static unsigned int timer;
86 static char uppercase_select[2][64], uppercase_start[64], uppercase_close[64], uppercase_cancel[64];
87
88 extern HANDLE update_check_thread, apply_wim_thread;
89 extern BOOL enable_iso, enable_joliet, enable_rockridge, enable_extra_hashes;
90 extern BYTE* fido_script;
91 extern HWND hFidoDlg;
92 extern uint8_t* grub2_buf;
93 extern long grub2_len;
94 extern char* szStatusMessage;
95 extern const char* old_c32_name[NB_OLD_C32];
96 extern const char* cert_name[3];
97 extern const char* FileSystemLabel[FS_MAX];
98
99 /*
100 * Globals
101 */
102 OPENED_LIBRARIES_VARS;
103 RUFUS_UPDATE update = { { 0,0,0 },{ 0,0 }, NULL, NULL };
104 HINSTANCE hMainInstance;
105 HWND hMainDialog, hMultiToolbar, hSaveToolbar, hHashToolbar, hAdvancedDeviceToolbar, hAdvancedFormatToolbar, hUpdatesDlg = NULL;
106 HFONT hInfoFont;
107 uint8_t image_options = IMOP_WINTOGO;
108 uint16_t rufus_version[3], embedded_sl_version[2];
109 uint32_t dur_mins, dur_secs, DrivePort[MAX_DRIVES];;
110 loc_cmd* selected_locale = NULL;
111 WORD selected_langid = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
112 DWORD MainThreadId;
113 HWND hDeviceList, hPartitionScheme, hTargetSystem, hFileSystem, hClusterSize, hLabel, hBootType, hNBPasses, hLog = NULL;
114 HWND hImageOption, hLogDialog = NULL, hProgress = NULL, hDiskID;
115 HANDLE dialog_handle = NULL;
116 BOOL is_x86_32, use_own_c32[NB_OLD_C32] = { FALSE, FALSE }, mbr_selected_by_user = FALSE;
117 BOOL op_in_progress = TRUE, right_to_left_mode = FALSE, has_uefi_csm = FALSE, its_a_me_mario = FALSE;
118 BOOL enable_HDDs = FALSE, enable_VHDs = TRUE, enable_ntfs_compression = FALSE, no_confirmation_on_cancel = FALSE, lock_drive = TRUE;
119 BOOL advanced_mode_device, advanced_mode_format, allow_dual_uefi_bios, detect_fakes, enable_vmdk, force_large_fat32, usb_debug;
120 BOOL use_fake_units, preserve_timestamps = FALSE, fast_zeroing = FALSE, app_changed_size = FALSE;
121 BOOL zero_drive = FALSE, list_non_usb_removable_drives = FALSE, enable_file_indexing, large_drive = FALSE;
122 BOOL write_as_image = FALSE, write_as_esp = FALSE, installed_uefi_ntfs = FALSE, use_vds = FALSE, ignore_boot_marker = FALSE;
123 BOOL windows_to_go_selected = FALSE;
124 float fScale = 1.0f;
125 int dialog_showing = 0, selection_default = BT_IMAGE, persistence_unit_selection = -1;
126 int default_fs, fs_type, boot_type, partition_type, target_type; // file system, boot type, partition type, target type
127 int force_update = 0, default_thread_priority = THREAD_PRIORITY_ABOVE_NORMAL;
128 char szFolderPath[MAX_PATH], app_dir[MAX_PATH], system_dir[MAX_PATH], temp_dir[MAX_PATH], sysnative_dir[MAX_PATH];
129 char embedded_sl_version_str[2][12] = { "?.??", "?.??" };
130 char embedded_sl_version_ext[2][32];
131 char ClusterSizeLabel[MAX_CLUSTER_SIZES][64];
132 char msgbox[1024], msgbox_title[32], *ini_file = NULL, *image_path = NULL, *short_image_path;
133 char *archive_path = NULL, image_option_txt[128], *fido_url = NULL;
134 StrArray DriveId, DriveName, DriveLabel, DriveHub, BlockingProcess, ImageList;
135 // Number of steps for each FS for FCC_STRUCTURE_PROGRESS
136 const int nb_steps[FS_MAX] = { 5, 5, 12, 1, 10, 1, 1, 1, 1 };
137 const char* flash_type[BADLOCKS_PATTERN_TYPES] = { "SLC", "MLC", "TLC" };
138
139 // TODO: Remember to update copyright year in stdlg's AboutCallback() WM_INITDIALOG,
140 // localization_data.sh and the .rc when the year changes!
141
142 // Fill in the cluster size names
143 static void SetClusterSizeLabels(void)
144 {
145 unsigned int i, j, msg_id;
146 safe_sprintf(ClusterSizeLabel[0], 64, "%s", lmprintf(MSG_029));
147 for (i=512, j=1, msg_id=MSG_026; j<MAX_CLUSTER_SIZES; i<<=1, j++) {
148 if (i > 8192) {
149 i /= 1024;
150 msg_id++;
151 }
152 safe_sprintf(ClusterSizeLabel[j], 64, "%d %s", i, lmprintf(msg_id));
153 }
154 }
155
156 static void SetAllowedFileSystems(void)
157 {
158 int i;
159
160 memset(allowed_filesystem, 0, sizeof(allowed_filesystem));
161 // Nothing is allowed if we don't have a drive
162 if (ComboBox_GetCurSel(hDeviceList) < 0)
163 return;
164 switch (selection_default) {
165 case BT_NON_BOOTABLE:
166 for (i = 0; i < FS_MAX; i++)
167 allowed_filesystem[i] = TRUE;
168 break;
169 case BT_MSDOS:
170 case BT_FREEDOS:
171 allowed_filesystem[FS_FAT16] = TRUE;
172 allowed_filesystem[FS_FAT32] = TRUE;
173 break;
174 case BT_IMAGE:
175 allowed_filesystem[FS_NTFS] = TRUE;
176 // Don't allow anything besides NTFS if the image has a >4GB file
177 if ((image_path != NULL) && (img_report.has_4GB_file))
178 break;
179 if (!HAS_WINDOWS(img_report) || (target_type != TT_BIOS) || allow_dual_uefi_bios) {
180 if (!HAS_WINTOGO(img_report) || (!ComboBox_GetCurItemData(hImageOption))) {
181 allowed_filesystem[FS_FAT16] = TRUE;
182 allowed_filesystem[FS_FAT32] = TRUE;
183 }
184 }
185 break;
186 case BT_SYSLINUX_V6:
187 case BT_GRUB4DOS:
188 allowed_filesystem[FS_NTFS] = TRUE;
189 // Fall through
190 case BT_SYSLINUX_V4:
191 case BT_REACTOS:
192 case BT_GRUB2:
193 allowed_filesystem[FS_FAT16] = TRUE;
194 allowed_filesystem[FS_FAT32] = TRUE;
195 break;
196 case BT_UEFI_NTFS:
197 allowed_filesystem[FS_NTFS] = TRUE;
198 allowed_filesystem[FS_EXFAT] = TRUE;
199 break;
200 }
201
202 // Reset disk ID to 0x80 if Rufus MBR is used
203 if (selection_default != BT_IMAGE) {
204 IGNORE_RETVAL(ComboBox_SetCurSel(hDiskID, 0));
205 }
206 }
207
208 // Populate the Boot selection dropdown
209 static void SetBootOptions(void)
210 {
211 char tmp[32];
212
213 IGNORE_RETVAL(ComboBox_ResetContent(hBootType));
214 IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, lmprintf(MSG_279)), BT_NON_BOOTABLE));
215 if (nWindowsVersion < WINDOWS_10) // The diskcopy.dll along with its MS-DOS floppy image was removed in Windows 10
216 IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, "MS-DOS"), BT_MSDOS));
217 IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, "FreeDOS"), BT_FREEDOS));
218 image_index = (nWindowsVersion < WINDOWS_10) ? 3 : 2;
219 IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType,
220 (image_path == NULL) ? lmprintf(MSG_281, lmprintf(MSG_280)) : short_image_path), BT_IMAGE));
221
222 if (advanced_mode_device) {
223 static_sprintf(tmp, "Syslinux %s", embedded_sl_version_str[0]);
224 IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, tmp), BT_SYSLINUX_V4));
225 static_sprintf(tmp, "Syslinux %s", embedded_sl_version_str[1]);
226 IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, tmp), BT_SYSLINUX_V6));
227 IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, "ReactOS"), BT_REACTOS));
228 IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType,
229 "Grub " GRUB2_PACKAGE_VERSION), BT_GRUB2));
230 IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType,
231 "Grub4DOS " GRUB4DOS_VERSION), BT_GRUB4DOS));
232 IGNORE_RETVAL(ComboBox_SetItemData(hBootType, ComboBox_AddStringU(hBootType, "UEFI:NTFS"), BT_UEFI_NTFS));
233 }
234 if ((!advanced_mode_device) && (selection_default >= BT_SYSLINUX_V4)) {
235 selection_default = BT_IMAGE;
236 CheckDlgButton(hMainDialog, IDC_DISK_ID, BST_UNCHECKED);
237 }
238 SetComboEntry(hBootType, selection_default);
239 }
240
241 static void SetPartitionSchemeAndTargetSystem(BOOL only_target)
242 {
243 // MBR, GPT, SFD
244 BOOL allowed_partition_scheme[3] = { TRUE, TRUE, FALSE };
245 // BIOS, UEFI, DUAL
246 BOOL allowed_target_system[3] = { TRUE, TRUE, FALSE };
247 BOOL is_windows_to_go_selected;
248
249 if (!only_target)
250 IGNORE_RETVAL(ComboBox_ResetContent(hPartitionScheme));
251 IGNORE_RETVAL(ComboBox_ResetContent(hTargetSystem));
252
253 boot_type = (int)ComboBox_GetCurItemData(hBootType);
254 is_windows_to_go_selected = (boot_type == BT_IMAGE) && (image_path != NULL) && HAS_WINTOGO(img_report) &&
255 ComboBox_GetCurItemData(hImageOption);
256 // If no device is selected, don't populate anything
257 if (ComboBox_GetCurSel(hDeviceList) < 0)
258 return;
259 switch (boot_type) {
260 case BT_NON_BOOTABLE:
261 allowed_partition_scheme[PARTITION_STYLE_SFD] = TRUE;
262 allowed_target_system[0] = FALSE;
263 allowed_target_system[1] = FALSE;
264 allowed_target_system[2] = TRUE;
265 break;
266 case BT_IMAGE:
267 if (image_path == NULL)
268 break;
269 // Check if image is EFI bootable
270 if (!IS_EFI_BOOTABLE(img_report)) {
271 allowed_partition_scheme[PARTITION_STYLE_GPT] = FALSE;
272 allowed_target_system[1] = FALSE;
273 break;
274 }
275 // Image is EFI bootable => set dual BIOS + UEFI and so on...
276 if (IS_BIOS_BOOTABLE(img_report)) {
277 if (!HAS_WINDOWS(img_report) || allow_dual_uefi_bios || is_windows_to_go_selected) {
278 allowed_target_system[0] = FALSE;
279 allowed_target_system[1] = TRUE;
280 allowed_target_system[2] = TRUE;
281 }
282 // Syslinux 4.x or earlier has no support for NTFS so if an image is using Syslinux 4.x only
283 // and has a 4 GB file (which forces us to use NTFS) then disable MBR altogether as we won't
284 // be able to make a working MBR install of Syslinux.
285 if (HAS_SYSLINUX(img_report) && (SL_MAJOR(img_report.sl_version) < 5) && img_report.has_4GB_file &&
286 !HAS_BOOTMGR(img_report) && !HAS_WINPE(img_report) && !HAS_GRUB(img_report))
287 allowed_partition_scheme[PARTITION_STYLE_MBR] = FALSE;
288 } else {
289 allowed_target_system[0] = FALSE;
290 }
291 break;
292 case BT_MSDOS:
293 case BT_FREEDOS:
294 case BT_SYSLINUX_V4:
295 case BT_SYSLINUX_V6:
296 case BT_REACTOS:
297 case BT_GRUB4DOS:
298 case BT_GRUB2:
299 allowed_partition_scheme[PARTITION_STYLE_GPT] = FALSE;
300 allowed_target_system[1] = FALSE;
301 break;
302 case BT_UEFI_NTFS:
303 allowed_target_system[0] = FALSE;
304 break;
305 }
306
307 if (!only_target) {
308 // Override partition type selection to GPT for drives larger than 2TB
309 if (SelectedDrive.DiskSize > 2 * TB)
310 selected_pt = PARTITION_STYLE_GPT;
311 // Try to reselect the current drive's partition scheme
312 int preferred_pt = SelectedDrive.PartitionStyle;
313 if (allowed_partition_scheme[PARTITION_STYLE_MBR])
314 IGNORE_RETVAL(ComboBox_SetItemData(hPartitionScheme,
315 ComboBox_AddStringU(hPartitionScheme, "MBR"), PARTITION_STYLE_MBR));
316 if (allowed_partition_scheme[PARTITION_STYLE_GPT])
317 IGNORE_RETVAL(ComboBox_SetItemData(hPartitionScheme,
318 ComboBox_AddStringU(hPartitionScheme, "GPT"), PARTITION_STYLE_GPT));
319 if (allowed_partition_scheme[PARTITION_STYLE_SFD])
320 IGNORE_RETVAL(ComboBox_SetItemData(hPartitionScheme,
321 ComboBox_AddStringU(hPartitionScheme, sfd_name), PARTITION_STYLE_SFD));
322 // Override the partition scheme according to the current
323 if (boot_type == BT_NON_BOOTABLE)
324 preferred_pt = (selected_pt >= 0) ? selected_pt : PARTITION_STYLE_MBR;
325 else if (boot_type == BT_UEFI_NTFS)
326 preferred_pt = (selected_pt >= 0) ? selected_pt : PARTITION_STYLE_GPT;
327 else if ((boot_type == BT_IMAGE) && (image_path != NULL) && (img_report.is_iso || img_report.is_windows_img)) {
328 if (HAS_WINDOWS(img_report) && img_report.has_efi)
329 preferred_pt = allow_dual_uefi_bios? PARTITION_STYLE_MBR :
330 ((selected_pt >= 0) ? selected_pt : PARTITION_STYLE_GPT);
331 if (img_report.is_bootable_img)
332 preferred_pt = (selected_pt >= 0) ? selected_pt : PARTITION_STYLE_MBR;
333 }
334 SetComboEntry(hPartitionScheme, preferred_pt);
335 partition_type = (int)ComboBox_GetCurItemData(hPartitionScheme);
336 }
337
338 has_uefi_csm = FALSE;
339 if (allowed_target_system[0] && (partition_type != PARTITION_STYLE_GPT)) {
340 IGNORE_RETVAL(ComboBox_SetItemData(hTargetSystem,
341 ComboBox_AddStringU(hTargetSystem, lmprintf(MSG_031)), TT_BIOS));
342 has_uefi_csm = TRUE;
343 }
344 if (allowed_target_system[1] && !((partition_type == PARTITION_STYLE_MBR) && (boot_type == BT_IMAGE) && IS_BIOS_BOOTABLE(img_report) && IS_EFI_BOOTABLE(img_report)) )
345 IGNORE_RETVAL(ComboBox_SetItemData(hTargetSystem,
346 ComboBox_AddStringU(hTargetSystem, lmprintf(MSG_032)), TT_UEFI));
347 if (allowed_target_system[2] && ((partition_type != PARTITION_STYLE_GPT) || (boot_type == BT_NON_BOOTABLE)))
348 IGNORE_RETVAL(ComboBox_SetItemData(hTargetSystem,
349 ComboBox_AddStringU(hTargetSystem, lmprintf(MSG_033)), TT_BIOS));
350 IGNORE_RETVAL(ComboBox_SetCurSel(hTargetSystem, 0));
351 target_type = (int)ComboBox_GetCurItemData(hTargetSystem);
352 // Can't update a tooltip from a thread, so we send a message instead
353 SendMessage(hMainDialog, UM_UPDATE_CSM_TOOLTIP, 0, 0);
354 }
355
356 // Populate the Allocation unit size field
357 static BOOL SetClusterSizes(int FSType)
358 {
359 char* szClustSize;
360 int i, k, default_index = 0;
361 ULONG j;
362
363 IGNORE_RETVAL(ComboBox_ResetContent(hClusterSize));
364
365 if ((FSType < 0) || (FSType >= FS_MAX)) {
366 return FALSE;
367 }
368
369 if ((SelectedDrive.ClusterSize[FSType].Allowed == 0)
370 || (SelectedDrive.ClusterSize[FSType].Default == 0)) {
371 return FALSE;
372 }
373
374 for (i = 0, j = 0x100, k = 0; j<0x10000000; i++, j <<= 1) {
375 if (j & SelectedDrive.ClusterSize[FSType].Allowed) {
376 if (j == SelectedDrive.ClusterSize[FSType].Default) {
377 szClustSize = lmprintf(MSG_030, ClusterSizeLabel[i]);
378 default_index = k;
379 } else {
380 szClustSize = ClusterSizeLabel[i];
381 }
382 IGNORE_RETVAL(ComboBox_SetItemData(hClusterSize, ComboBox_AddStringU(hClusterSize, szClustSize), j));
383 k++;
384 }
385 }
386
387 IGNORE_RETVAL(ComboBox_SetCurSel(hClusterSize, default_index));
388 return TRUE;
389 }
390
391 // Populate the File System and Cluster Size dropdowns
392 static BOOL SetFileSystemAndClusterSize(char* fs_name)
393 {
394 int fs_index;
395 LONGLONG i;
396 char tmp[128] = "", *entry;
397
398 IGNORE_RETVAL(ComboBox_ResetContent(hFileSystem));
399 IGNORE_RETVAL(ComboBox_ResetContent(hClusterSize));
400 default_fs = FS_UNKNOWN;
401 memset(&SelectedDrive.ClusterSize, 0, sizeof(SelectedDrive.ClusterSize));
402
403 /*
404 * See https://support.microsoft.com/en-gb/help/140365/default-cluster-size-for-ntfs--fat--and-exfat
405 * The following are MS's allowed cluster sizes for FAT16 and FAT32:
406 *
407 * FAT16
408 * 31M : 512 - 4096
409 * 63M : 1024 - 8192
410 * 127M : 2048 - 16k
411 * 255M : 4096 - 32k
412 * 511M : 8192 - 64k
413 * 1023M: 16k - 64k
414 * 2047M: 32k - 64k
415 * 4095M: 64k
416 * 4GB+ : N/A
417 *
418 * FAT32
419 * 31M : N/A
420 * 63M : N/A (NB unlike MS, we're allowing 512-512 here)
421 * 127M : 512 - 1024
422 * 255M : 512 - 2048
423 * 511M : 512 - 4096
424 * 1023M: 512 - 8192
425 * 2047M: 512 - 16k
426 * 4095M: 1024 - 32k
427 * 7GB : 2048 - 64k
428 * 15GB : 4096 - 64k
429 * 31GB : 8192 - 64k This is as far as Microsoft's FormatEx goes...
430 * 63GB : 16k - 64k ...but we can go higher using fat32format from RidgeCrop.
431 * 2TB+ : N/A
432 *
433 */
434
435 // FAT 16
436 if (SelectedDrive.DiskSize < 4*GB) {
437 SelectedDrive.ClusterSize[FS_FAT16].Allowed = 0x00001E00;
438 for (i=32; i<=4096; i<<=1) { // 8 MB -> 4 GB
439 if (SelectedDrive.DiskSize < i*MB) {
440 SelectedDrive.ClusterSize[FS_FAT16].Default = 16*(ULONG)i;
441 break;
442 }
443 SelectedDrive.ClusterSize[FS_FAT16].Allowed <<= 1;
444 }
445 SelectedDrive.ClusterSize[FS_FAT16].Allowed &= 0x0001FE00;
446 }
447
448 // FAT 32
449 // > 32GB FAT32 is not supported by MS and FormatEx but is achieved using fat32format
450 // See: http://www.ridgecrop.demon.co.uk/index.htm?fat32format.htm
451 // < 32 MB FAT32 is not allowed by FormatEx, so we don't bother
452 if ((SelectedDrive.DiskSize >= 32*MB) && (1.0f*SelectedDrive.DiskSize < 1.0f*MAX_FAT32_SIZE*TB)) {
453 SelectedDrive.ClusterSize[FS_FAT32].Allowed = 0x000001F8;
454 for (i=32; i<=(32*1024); i<<=1) { // 32 MB -> 32 GB
455 if (SelectedDrive.DiskSize*1.0f < i*MB*FAT32_CLUSTER_THRESHOLD) { // MS
456 SelectedDrive.ClusterSize[FS_FAT32].Default = 8*(ULONG)i;
457 break;
458 }
459 SelectedDrive.ClusterSize[FS_FAT32].Allowed <<= 1;
460 }
461 SelectedDrive.ClusterSize[FS_FAT32].Allowed &= 0x0001FE00;
462
463 // Default cluster sizes in the 256MB to 32 GB range do not follow the rule above
464 if ((SelectedDrive.DiskSize >= 256*MB) && (SelectedDrive.DiskSize < 32*GB)) {
465 for (i=8; i<=32; i<<=1) { // 256 MB -> 32 GB
466 if (SelectedDrive.DiskSize*1.0f < i*GB*FAT32_CLUSTER_THRESHOLD) {
467 SelectedDrive.ClusterSize[FS_FAT32].Default = ((ULONG)i/2)*KB;
468 break;
469 }
470 }
471 }
472 // More adjustments for large drives
473 if (SelectedDrive.DiskSize >= 32*GB) {
474 SelectedDrive.ClusterSize[FS_FAT32].Allowed &= 0x0001C000;
475 SelectedDrive.ClusterSize[FS_FAT32].Default = 0x00008000;
476 }
477 }
478
479 if (SelectedDrive.DiskSize < 256*TB) {
480 // NTFS
481 SelectedDrive.ClusterSize[FS_NTFS].Allowed = 0x0001FE00;
482 for (i=16; i<=256; i<<=1) { // 7 MB -> 256 TB
483 if (SelectedDrive.DiskSize < i*TB) {
484 SelectedDrive.ClusterSize[FS_NTFS].Default = ((ULONG)i/4)*KB;
485 break;
486 }
487 }
488
489 // exFAT
490 SelectedDrive.ClusterSize[FS_EXFAT].Allowed = 0x03FFFE00;
491 if (SelectedDrive.DiskSize < 256*MB) // < 256 MB
492 SelectedDrive.ClusterSize[FS_EXFAT].Default = 4*KB;
493 else if (SelectedDrive.DiskSize < 32*GB) // < 32 GB
494 SelectedDrive.ClusterSize[FS_EXFAT].Default = 32*KB;
495 else
496 SelectedDrive.ClusterSize[FS_EXFAT].Default = 128*KB;
497
498 // UDF
499 SelectedDrive.ClusterSize[FS_UDF].Allowed = SINGLE_CLUSTERSIZE_DEFAULT;
500 SelectedDrive.ClusterSize[FS_UDF].Default = 1;
501
502 // ext2/ext3/ext4
503 if (advanced_mode_format && (SelectedDrive.DiskSize >= MIN_EXT_SIZE)) {
504 SelectedDrive.ClusterSize[FS_EXT2].Allowed = SINGLE_CLUSTERSIZE_DEFAULT;
505 SelectedDrive.ClusterSize[FS_EXT2].Default = 1;
506 SelectedDrive.ClusterSize[FS_EXT3].Allowed = SINGLE_CLUSTERSIZE_DEFAULT;
507 SelectedDrive.ClusterSize[FS_EXT3].Default = 1;
508 }
509
510 // ReFS (only supported for Windows 8.1 and later and for fixed disks)
511 // TODO: Check later versions of Windows 10 for disabled ReFS (IVdsService::QueryFileSystemTypes?)
512 if (SelectedDrive.DiskSize >= 512*MB) {
513 if ((nWindowsVersion >= WINDOWS_8_1) && (SelectedDrive.MediaType == FixedMedia)) {
514 SelectedDrive.ClusterSize[FS_REFS].Allowed = SINGLE_CLUSTERSIZE_DEFAULT;
515 SelectedDrive.ClusterSize[FS_REFS].Default = 1;
516 }
517 }
518 }
519
520 // Only add the filesystems we can service
521 SetAllowedFileSystems();
522 SetClusterSizeLabels();
523
524 for (fs_index = 0; fs_index < FS_MAX; fs_index++) {
525 // Remove all cluster sizes that are below the sector size
526 if (SelectedDrive.ClusterSize[fs_index].Allowed != SINGLE_CLUSTERSIZE_DEFAULT) {
527 SelectedDrive.ClusterSize[fs_index].Allowed &= ~(SelectedDrive.SectorSize - 1);
528 if ((SelectedDrive.ClusterSize[fs_index].Default & SelectedDrive.ClusterSize[fs_index].Allowed) == 0)
529 // We lost our default => Use rightmost bit to select the new one
530 SelectedDrive.ClusterSize[fs_index].Default =
531 SelectedDrive.ClusterSize[fs_index].Allowed & (-(LONG)SelectedDrive.ClusterSize[fs_index].Allowed);
532 }
533
534 if (SelectedDrive.ClusterSize[fs_index].Allowed != 0) {
535 tmp[0] = 0;
536 // Tell the user if we're going to use Large FAT32 or regular
537 if ((fs_index == FS_FAT32) && ((SelectedDrive.DiskSize > LARGE_FAT32_SIZE) || (force_large_fat32)))
538 static_strcat(tmp, "Large ");
539 static_strcat(tmp, FileSystemLabel[fs_index]);
540 if (default_fs == FS_UNKNOWN) {
541 entry = lmprintf(MSG_030, tmp);
542 default_fs = fs_index;
543 } else {
544 entry = tmp;
545 }
546 if (allowed_filesystem[fs_index]) {
547 IGNORE_RETVAL(ComboBox_SetItemData(hFileSystem,
548 ComboBox_AddStringU(hFileSystem, entry), fs_index));
549 }
550 }
551 }
552
553 // re-select existing FS if it's one we know
554 SelectedDrive.FSType = FS_UNKNOWN;
555 if (safe_strlen(fs_name) != 0) {
556 for (SelectedDrive.FSType = FS_MAX - 1; SelectedDrive.FSType >= 0; SelectedDrive.FSType--) {
557 if (safe_strcmp(fs_name, FileSystemLabel[SelectedDrive.FSType]) == 0) {
558 break;
559 }
560 }
561 } else {
562 // Re-select last user-selected FS
563 SelectedDrive.FSType = selected_fs;
564 }
565
566 for (i = 0; i<ComboBox_GetCount(hFileSystem); i++) {
567 if (ComboBox_GetItemData(hFileSystem, i) == SelectedDrive.FSType) {
568 IGNORE_RETVAL(ComboBox_SetCurSel(hFileSystem, i));
569 break;
570 }
571 }
572
573 if (i == ComboBox_GetCount(hFileSystem)) {
574 // failed to reselect => pick default
575 SetComboEntry(hFileSystem, default_fs);
576 }
577
578 return SetClusterSizes((int)ComboBox_GetCurItemData(hFileSystem));
579 }
580
581 static void SetFSFromISO(void)
582 {
583 int i, fs_tmp, preferred_fs = FS_UNKNOWN;
584 uint32_t fs_mask = FS_FAT32 | FS_NTFS;
585 BOOL windows_to_go = (image_options & IMOP_WINTOGO) && (boot_type == BT_IMAGE) &&
586 HAS_WINTOGO(img_report) && ComboBox_GetCurItemData(hImageOption);
587
588 if (image_path == NULL)
589 return;
590
591 // Create a mask of all the FS's available
592 for (i=0; i<ComboBox_GetCount(hFileSystem); i++) {
593 fs_tmp = (int)ComboBox_GetItemData(hFileSystem, i);
594 fs_mask |= 1<<fs_tmp;
595 }
596
597 if ((preferred_fs == FS_UNKNOWN) && (preselected_fs != FS_UNKNOWN)) {
598 // If the FS requested from the command line is valid use it
599 if (fs_mask & (1 << preselected_fs)) {
600 preferred_fs = preselected_fs;
601 }
602 }
603
604 if (preferred_fs == FS_UNKNOWN) {
605 // Syslinux and EFI have precedence over bootmgr (unless the user selected BIOS as target type)
606 if ((HAS_SYSLINUX(img_report)) || (HAS_REACTOS(img_report)) || HAS_KOLIBRIOS(img_report) ||
607 (IS_EFI_BOOTABLE(img_report) && (target_type == TT_UEFI) && (!windows_to_go))) {
608 if (fs_mask & (1 << FS_FAT32)) {
609 preferred_fs = FS_FAT32;
610 } else if ((fs_mask & (1 << FS_FAT16)) && !HAS_KOLIBRIOS(img_report)) {
611 preferred_fs = FS_FAT16;
612 }
613 } else if ((windows_to_go) || HAS_BOOTMGR(img_report) || HAS_WINPE(img_report)) {
614 if (fs_mask & (1 << FS_NTFS)) {
615 preferred_fs = FS_NTFS;
616 }
617 }
618 }
619
620 // The presence of a 4GB file forces the use of NTFS as default FS if available
621 if (img_report.has_4GB_file && (fs_mask & (1 << FS_NTFS))) {
622 preferred_fs = FS_NTFS;
623 }
624
625 // Try to select the FS
626 for (i = 0; i < ComboBox_GetCount(hFileSystem); i++) {
627 fs_tmp = (int)ComboBox_GetItemData(hFileSystem, i);
628 if (fs_tmp == preferred_fs) {
629 IGNORE_RETVAL(ComboBox_SetCurSel(hFileSystem, i));
630 break;
631 }
632 }
633 if (selected_fs == FS_UNKNOWN)
634 selected_fs = preferred_fs;
635
636 SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE_INTERNAL<<16) | IDC_FILE_SYSTEM,
637 ComboBox_GetCurSel(hFileSystem));
638 }
639
640 static void SetMBRProps(void)
641 {
642 BOOL needs_masquerading = HAS_WINPE(img_report) && (!img_report.uses_minint);
643
644 if ((!mbr_selected_by_user) && ((image_path == NULL) || (boot_type != BT_IMAGE) || (fs_type != FS_NTFS) || HAS_GRUB(img_report) ||
645 ((image_options & IMOP_WINTOGO) && ComboBox_GetCurItemData(hImageOption)) )) {
646 CheckDlgButton(hMainDialog, IDC_RUFUS_MBR, BST_UNCHECKED);
647 IGNORE_RETVAL(ComboBox_SetCurSel(hDiskID, 0));
648 return;
649 }
650
651 uMBRChecked = (needs_masquerading || HAS_BOOTMGR(img_report) || mbr_selected_by_user)?BST_CHECKED:BST_UNCHECKED;
652 if (IsWindowEnabled(GetDlgItem(hMainDialog, IDC_RUFUS_MBR)))
653 CheckDlgButton(hMainDialog, IDC_RUFUS_MBR, uMBRChecked);
654 IGNORE_RETVAL(ComboBox_SetCurSel(hDiskID, needs_masquerading?1:0));
655 }
656
657 static void SetProposedLabel(int ComboIndex)
658 {
659 const char no_label[] = STR_NO_LABEL, empty[] = "";
660
661 app_changed_label = TRUE;
662 // If bootable ISO creation is selected, and we have an ISO selected with a valid name, use that
663 // Also some distros (eg. Arch) require the USB to have the same label as the ISO
664 if ((boot_type == BT_IMAGE) && (image_path != NULL) && (img_report.label[0] != 0)) {
665 SetWindowTextU(hLabel, img_report.label);
666 // If we force the ISO label, we need to reset the user_changed_label flag
667 user_changed_label = FALSE;
668 return;
669 }
670
671 // If the user manually changed the label, try to preserve it
672 if (user_changed_label) {
673 app_changed_label = FALSE;
674 return;
675 }
676
677 // Empty the label if no device is currently selected
678 if (ComboIndex < 0) {
679 SetWindowTextU(hLabel, "");
680 return;
681 }
682
683 // Else if no existing label is available, propose one according to the size (eg: "256MB", "8GB")
684 if ((_stricmp(no_label, DriveLabel.String[ComboIndex]) == 0) || (_stricmp(no_label, empty) == 0)
685 || (safe_stricmp(lmprintf(MSG_207), DriveLabel.String[ComboIndex]) == 0)) {
686 SetWindowTextU(hLabel, SelectedDrive.proposed_label);
687 } else {
688 SetWindowTextU(hLabel, DriveLabel.String[ComboIndex]);
689 }
690 }
691
692 // This handles the enabling/disabling of the "Add fixes for old BIOSes" and "Use Rufus MBR" controls
693 static void EnableMBRBootOptions(BOOL enable, BOOL remove_checkboxes)
694 {
695 BOOL actual_enable_mbr = (boot_type > BT_IMAGE) ? FALSE: enable;
696 BOOL actual_enable_fix = enable;
697 static UINT uXPartChecked = BST_UNCHECKED;
698
699 if ((partition_type != PARTITION_STYLE_MBR) || (target_type != TT_BIOS) || (boot_type == BT_NON_BOOTABLE) ||
700 ((boot_type == BT_IMAGE) && (!IS_BIOS_BOOTABLE(img_report) || IS_DD_ONLY(img_report)))) {
701 // These options cannot apply if we aren't using MBR+BIOS, or are using an image that isn't BIOS bootable
702 actual_enable_mbr = FALSE;
703 actual_enable_fix = FALSE;
704 } else {
705 // If we are using an image, the Rufus MBR only applies if it's for Windows
706 if ((boot_type == BT_IMAGE) && !HAS_WINPE(img_report) && !HAS_BOOTMGR(img_report)) {
707 actual_enable_mbr = FALSE;
708 mbr_selected_by_user = FALSE;
709 }
710 if (boot_type == BT_NON_BOOTABLE) {
711 actual_enable_fix = FALSE;
712 }
713 }
714
715 if (remove_checkboxes) {
716 // Store/Restore the checkbox states
717 if (IsWindowEnabled(GetDlgItem(hMainDialog, IDC_RUFUS_MBR)) && !actual_enable_mbr) {
718 uMBRChecked = IsChecked(IDC_RUFUS_MBR);
719 CheckDlgButton(hMainDialog, IDC_RUFUS_MBR, BST_UNCHECKED);
720 } else if (!IsWindowEnabled(GetDlgItem(hMainDialog, IDC_RUFUS_MBR)) && actual_enable_mbr) {
721 CheckDlgButton(hMainDialog, IDC_RUFUS_MBR, uMBRChecked);
722 }
723 if (IsWindowEnabled(GetDlgItem(hMainDialog, IDC_OLD_BIOS_FIXES)) && !actual_enable_fix) {
724 uXPartChecked = IsChecked(IDC_OLD_BIOS_FIXES);
725 CheckDlgButton(hMainDialog, IDC_OLD_BIOS_FIXES, BST_UNCHECKED);
726 } else if (!IsWindowEnabled(GetDlgItem(hMainDialog, IDC_OLD_BIOS_FIXES)) && actual_enable_fix) {
727 CheckDlgButton(hMainDialog, IDC_OLD_BIOS_FIXES, uXPartChecked);
728 }
729 }
730
731 EnableWindow(GetDlgItem(hMainDialog, IDC_OLD_BIOS_FIXES), actual_enable_fix);
732 EnableWindow(GetDlgItem(hMainDialog, IDC_RUFUS_MBR), actual_enable_mbr);
733 EnableWindow(hDiskID, actual_enable_mbr);
734 }
735
736 static void EnableExtendedLabel(BOOL enable, BOOL remove_checkboxes)
737 {
738 static UINT checked, state = 0;
739 HWND hCtrl = GetDlgItem(hMainDialog, IDC_EXTENDED_LABEL);
740
741 if ((fs_type >= FS_EXT2) || ((boot_type == BT_IMAGE) && IS_DD_ONLY(img_report)))
742 enable = FALSE;
743
744 if (remove_checkboxes) {
745 if (!enable && (state != 1)) {
746 checked = IsChecked(IDC_EXTENDED_LABEL);
747 CheckDlgButton(hMainDialog, IDC_EXTENDED_LABEL, BST_UNCHECKED);
748 state = 1;
749 } else if (enable && !IsWindowEnabled(hCtrl) && (state != 2)) {
750 if (state != 0)
751 CheckDlgButton(hMainDialog, IDC_EXTENDED_LABEL, checked);
752 state = 2;
753 }
754 }
755 EnableWindow(hCtrl, enable);
756 }
757
758 static void EnableQuickFormat(BOOL enable, BOOL remove_checkboxes)
759 {
760 static UINT checked, state = 0;
761 HWND hCtrl = GetDlgItem(hMainDialog, IDC_QUICK_FORMAT);
762
763 if ((boot_type == BT_IMAGE) && IS_DD_ONLY(img_report))
764 enable = FALSE;
765
766 // Disable/restore the quick format control depending on large FAT32 or ReFS
767 if (((fs_type == FS_FAT32) && ((SelectedDrive.DiskSize > LARGE_FAT32_SIZE) || (force_large_fat32))) || (fs_type == FS_REFS)) {
768 enable = FALSE;
769 // Quick Format is the only option for the above
770 remove_checkboxes = FALSE;
771 CheckDlgButton(hMainDialog, IDC_QUICK_FORMAT, BST_CHECKED);
772 }
773
774 if (remove_checkboxes) {
775 if (!enable && (state != 1)) {
776 checked = IsChecked(IDC_QUICK_FORMAT);
777 CheckDlgButton(hMainDialog, IDC_QUICK_FORMAT, BST_UNCHECKED);
778 state = 1;
779 } else if (enable && !IsWindowEnabled(hCtrl) && (state != 2)) {
780 if (state != 0)
781 CheckDlgButton(hMainDialog, IDC_QUICK_FORMAT, checked);
782 state = 2;
783 }
784 }
785 EnableWindow(hCtrl, enable);
786 }
787
788 static void EnableBootOptions(BOOL enable, BOOL remove_checkboxes)
789 {
790 BOOL actual_enable_bb, actual_enable = enable;
791
792 // If no device is selected, don't enable anything and also don't remove the checkboxes
793 if (ComboBox_GetCurSel(hDeviceList) < 0) {
794 actual_enable = FALSE;
795 remove_checkboxes = FALSE;
796 }
797 // If boot selection is set to image, but no image is currently selected, don't enable anything
798 if ((boot_type == BT_IMAGE) && (image_path == NULL))
799 actual_enable = FALSE;
800 actual_enable_bb = actual_enable;
801 // If we are dealing with a pure DD image, remove all options except Bad Blocks check
802 if ((boot_type == BT_IMAGE) && (img_report.is_bootable_img) && (!img_report.is_iso))
803 actual_enable = FALSE;
804
805 EnableWindow(hImageOption, actual_enable);
806 EnableWindow(GetDlgItem(hMainDialog, IDC_PERSISTENCE_SLIDER), actual_enable);
807 // Make sure we set the range if we have persistence
808 if ((image_path != NULL) && HAS_PERSISTENCE(img_report))
809 SetPersistenceSize();
810 EnableWindow(GetDlgItem(hMainDialog, IDC_PERSISTENCE_SIZE), (persistence_size != 0) && actual_enable);
811 EnableWindow(GetDlgItem(hMainDialog, IDC_PERSISTENCE_UNITS), (persistence_size != 0) && actual_enable);
812 EnableMBRBootOptions(actual_enable, remove_checkboxes);
813
814 EnableWindow(GetDlgItem(hMainDialog, IDC_LABEL), actual_enable);
815 if (boot_type == BT_IMAGE) {
816 if (IS_DD_ONLY(img_report))
817 remove_checkboxes = TRUE;
818 else if (image_path == NULL)
819 remove_checkboxes = FALSE;
820 }
821 EnableQuickFormat(actual_enable, remove_checkboxes);
822 EnableExtendedLabel(actual_enable, remove_checkboxes);
823 EnableWindow(GetDlgItem(hMainDialog, IDC_BAD_BLOCKS), actual_enable_bb);
824 EnableWindow(GetDlgItem(hMainDialog, IDC_NB_PASSES), actual_enable_bb);
825 }
826
827 // Toggle controls according to operation
828 static void EnableControls(BOOL enable, BOOL remove_checkboxes)
829 {
830 op_in_progress = !enable;
831
832 // The following only get disabled on format/checksum and otherwise remain enabled,
833 // even if no device or image are selected
834 EnableWindow(hDeviceList, enable);
835 EnableWindow(hBootType, enable);
836 EnableWindow(hSelectImage, enable);
837 EnableWindow(GetDlgItem(hMainDialog, IDC_LIST_USB_HDD), enable);
838 EnableWindow(hAdvancedDeviceToolbar, enable);
839 EnableWindow(hAdvancedFormatToolbar, enable);
840 SendMessage(hMultiToolbar, TB_ENABLEBUTTON, (WPARAM)IDC_LANG, (LPARAM)enable);
841 SendMessage(hMultiToolbar, TB_ENABLEBUTTON, (WPARAM)IDC_ABOUT, (LPARAM)enable);
842 SendMessage(hMultiToolbar, TB_ENABLEBUTTON, (WPARAM)IDC_SETTINGS, (LPARAM)enable);
843
844 // Checksum button is enabled if an image has been selected
845 EnableWindow(hHashToolbar, enable && (boot_type == BT_IMAGE) && (image_path != NULL));
846
847 // Toggle CLOSE/CANCEL
848 SetDlgItemTextU(hMainDialog, IDCANCEL, enable ? uppercase_close : uppercase_cancel);
849
850 // Only enable the following controls if a device is active
851 enable = (ComboBox_GetCurSel(hDeviceList) < 0) ? FALSE : enable;
852 EnableWindow(hImageOption, enable);
853 EnableWindow(hSaveToolbar, enable);
854
855 // Enable or disable the Start button and the other boot options
856 enable = ((boot_type == BT_IMAGE) && (image_path == NULL)) ? FALSE : enable;
857 EnableWindow(hStart, enable);
858 EnableBootOptions(enable, remove_checkboxes);
859
860 // Finally, only enable the half-size dropdowns if we aren't dealing with a pure DD image
861 enable = ((boot_type == BT_IMAGE) && (image_path != NULL) &&
862 (!(img_report.is_iso || img_report.is_windows_img))) ? FALSE : enable;
863 EnableWindow(hPartitionScheme, enable);
864 EnableWindow(hTargetSystem, enable);
865 EnableWindow(GetDlgItem(hMainDialog, IDS_CSM_HELP_TXT), enable);
866 EnableWindow(hFileSystem, enable);
867 EnableWindow(hClusterSize, enable);
868 }
869
870 // Populate the UI main dropdown properties.
871 // This should be called on device or boot type change.
872 static BOOL PopulateProperties(void)
873 {
874 char* device_tooltip;
875 int device_index = ComboBox_GetCurSel(hDeviceList);
876 char fs_name[32];
877
878 memset(&SelectedDrive, 0, sizeof(SelectedDrive));
879 EnableWindow(hStart, FALSE);
880
881 if (device_index < 0)
882 goto out;
883
884 persistence_unit_selection = -1;
885 // Get data from the currently selected drive
886 SelectedDrive.DeviceNumber = (DWORD)ComboBox_GetItemData(hDeviceList, device_index);
887 // This fills the SelectedDrive properties
888 GetDrivePartitionData(SelectedDrive.DeviceNumber, fs_name, sizeof(fs_name), FALSE);
889 SetPartitionSchemeAndTargetSystem(FALSE);
890 // Attempt to reselect the last file system explicitly set by the user
891 if (!SetFileSystemAndClusterSize((selected_fs == FS_UNKNOWN) ? fs_name : NULL)) {
892 SetProposedLabel(-1);
893 uprintf("No file system is selectable for this drive\n");
894 return FALSE;
895 }
896
897 EnableControls(TRUE, FALSE);
898
899 // Set a proposed label according to the size (eg: "256MB", "8GB")
900 static_sprintf(SelectedDrive.proposed_label, "%s",
901 SizeToHumanReadable(SelectedDrive.DiskSize, FALSE, TRUE));
902
903 // Add a tooltip (with the size of the device in parenthesis)
904 device_tooltip = (char*) malloc(safe_strlen(DriveName.String[device_index]) + 32);
905 if (device_tooltip != NULL) {
906 if (right_to_left_mode)
907 safe_sprintf(device_tooltip, safe_strlen(DriveName.String[device_index]) + 32, "(%s) %s",
908 SizeToHumanReadable(SelectedDrive.DiskSize, FALSE, FALSE), DriveName.String[device_index]);
909 else
910 safe_sprintf(device_tooltip, safe_strlen(DriveName.String[device_index]) + 32, "%s (%s)",
911 DriveName.String[device_index], SizeToHumanReadable(SelectedDrive.DiskSize, FALSE, FALSE));
912 CreateTooltip(hDeviceList, device_tooltip, -1);
913 free(device_tooltip);
914 }
915
916 out:
917 SetProposedLabel(device_index);
918 return TRUE;
919 }
920
921 // Callback for the log window
922 BOOL CALLBACK LogCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
923 {
924 HDC hDC;
925 HFONT hf;
926 LONG lfHeight;
927 LONG_PTR style;
928 DWORD log_size;
929 char *log_buffer = NULL, *filepath;
930 EXT_DECL(log_ext, "rufus.log", __VA_GROUP__("*.log"), __VA_GROUP__("Rufus log"));
931 switch (message) {
932 case WM_INITDIALOG:
933 apply_localization(IDD_LOG, hDlg);
934 hLog = GetDlgItem(hDlg, IDC_LOG_EDIT);
935
936 // Increase the size of our log textbox to MAX_LOG_SIZE (unsigned word)
937 PostMessage(hLog, EM_LIMITTEXT, MAX_LOG_SIZE , 0);
938 // Set the font to Unicode so that we can display anything
939 hDC = GetDC(NULL);
940 lfHeight = -MulDiv(9, GetDeviceCaps(hDC, LOGPIXELSY), 72);
941 safe_release_dc(NULL, hDC);
942 hf = CreateFontA(lfHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
943 DEFAULT_CHARSET, 0, 0, PROOF_QUALITY, 0, "Consolas");
944 SendDlgItemMessageA(hDlg, IDC_LOG_EDIT, WM_SETFONT, (WPARAM)hf, TRUE);
945 // Set 'Close Log' as the selected button
946 SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, IDCANCEL), TRUE);
947
948 // Suppress any inherited RTL flags from our edit control's style. Otherwise
949 // the displayed text becomes a mess due to Windows trying to interpret
950 // dots, parenthesis, columns and so on in an RTL context...
951 // We also take this opportunity to fix the scroll bar and text alignment.
952 style = GetWindowLongPtr(hLog, GWL_EXSTYLE);
953 style &= ~(WS_EX_RTLREADING | WS_EX_RIGHT | WS_EX_LEFTSCROLLBAR);
954 SetWindowLongPtr(hLog, GWL_EXSTYLE, style);
955 style = GetWindowLongPtr(hLog, GWL_STYLE);
956 style &= ~(ES_RIGHT);
957 SetWindowLongPtr(hLog, GWL_STYLE, style);
958 break;
959 case WM_COMMAND:
960 switch (LOWORD(wParam)) {
961 case IDCANCEL:
962 ShowWindow(hDlg, SW_HIDE);
963 log_displayed = FALSE;
964 // Set focus to the Cancel button on the main dialog
965 // This avoids intempestive tooltip display from the log toolbar buttom
966 SendMessage(hMainDialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hMainDialog, IDCANCEL), TRUE);
967 return TRUE;
968 case IDC_LOG_CLEAR:
969 SetWindowTextA(hLog, "");
970 return TRUE;
971 case IDC_LOG_SAVE:
972 log_size = GetWindowTextLengthU(hLog);
973 if (log_size <= 0)
974 break;
975 log_buffer = (char*)malloc(log_size);
976 if (log_buffer != NULL) {
977 log_size = GetDlgItemTextU(hDlg, IDC_LOG_EDIT, log_buffer, log_size);
978 if (log_size != 0) {
979 log_size--; // remove NUL terminator
980 filepath = FileDialog(TRUE, app_dir, &log_ext, 0);
981 if (filepath != NULL) {
982 FileIO(TRUE, filepath, &log_buffer, &log_size);
983 }
984 safe_free(filepath);
985 }
986 safe_free(log_buffer);
987 }
988 break;
989 }
990 break;
991 case WM_CLOSE:
992 ShowWindow(hDlg, SW_HIDE);
993 reset_localization(IDD_LOG);
994 log_displayed = FALSE;
995 // Set focus to the Cancel button on the main dialog
996 // This avoids intempestive tooltip display from the log toolbar buttom
997 SendMessage(hMainDialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hMainDialog, IDCANCEL), TRUE);
998 return TRUE;
999 case UM_RESIZE_BUTTONS:
1000 // Resize our buttons for low scaling factors
1001 ResizeButtonHeight(hDlg, IDCANCEL);
1002 ResizeButtonHeight(hDlg, IDC_LOG_SAVE);
1003 ResizeButtonHeight(hDlg, IDC_LOG_CLEAR);
1004 return TRUE;
1005 }
1006 return FALSE;
1007 }
1008
1009 // Timer in the right part of the status area
1010 static void CALLBACK ClockTimer(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
1011 {
1012 timer++;
1013 static_sprintf(szTimer, "%02d:%02d:%02d", timer/3600, (timer%3600)/60, timer%60);
1014 SendMessageA(hStatus, SB_SETTEXTA, SBT_OWNERDRAW | SB_SECTION_RIGHT, (LPARAM)szTimer);
1015 }
1016
1017 // Device Refresh Timer
1018 static void CALLBACK RefreshTimer(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
1019 {
1020 // DO NOT USE WM_DEVICECHANGE - IT MAY BE FILTERED OUT BY WINDOWS!
1021 SendMessage(hWnd, UM_MEDIA_CHANGE, 0, 0);
1022 }
1023
1024 // Detect and notify about a blocking operation during ISO extraction cancellation
1025 static void CALLBACK BlockingTimer(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
1026 {
1027 if (iso_blocking_status < 0) {
1028 KillTimer(hMainDialog, TID_BLOCKING_TIMER);
1029 user_notified = FALSE;
1030 uprintf("Killed blocking I/O timer\n");
1031 } else if(!user_notified) {
1032 if (last_iso_blocking_status == iso_blocking_status) {
1033 // A write or close operation hasn't made any progress since our last check
1034 user_notified = TRUE;
1035 uprintf("Blocking I/O operation detected\n");
1036 MessageBoxExU(hMainDialog, lmprintf(MSG_080), lmprintf(MSG_048),
1037 MB_OK|MB_ICONINFORMATION|MB_IS_RTL, selected_langid);
1038 } else {
1039 last_iso_blocking_status = iso_blocking_status;
1040 }
1041 }
1042 }
1043
1044 // Report the features of the selected ISO images
1045 #define PRINT_ISO_PROP(b, ...) do {if (b) uprintf(__VA_ARGS__);} while(0)
1046 static void DisplayISOProps(void)
1047 {
1048 static char inst_str[] = " [1/#]";
1049 int i;
1050
1051 uprintf("ISO label: '%s'", img_report.label);
1052 uprintf(" Size: %s (Projected)", SizeToHumanReadable(img_report.projected_size, FALSE, FALSE));
1053 if (img_report.mismatch_size > 0) {
1054 uprintf(" ERROR: Detected that file on disk has been truncated by %s!",
1055 SizeToHumanReadable(img_report.mismatch_size, FALSE, FALSE));
1056 MessageBoxExU(hMainDialog, lmprintf(MSG_298, SizeToHumanReadable(img_report.mismatch_size, FALSE, FALSE)),
1057 lmprintf(MSG_297), MB_ICONWARNING | MB_IS_RTL, selected_langid);
1058 } else if (img_report.mismatch_size < 0) {
1059 // Not an error (ISOHybrid?), but we report it just in case
1060 uprintf(" Note: File on disk is larger than reported ISO size by %s...",
1061 SizeToHumanReadable(-img_report.mismatch_size, FALSE, FALSE));
1062 }
1063
1064 PRINT_ISO_PROP(img_report.has_4GB_file, " Has a >4GB file");
1065 PRINT_ISO_PROP(img_report.has_long_filename, " Has a >64 chars filename");
1066 PRINT_ISO_PROP(img_report.has_deep_directories, " Has a Rock Ridge deep directory");
1067 PRINT_ISO_PROP(HAS_SYSLINUX(img_report), " Uses: Syslinux/Isolinux v%s", img_report.sl_version_str);
1068 if (HAS_SYSLINUX(img_report) && (SL_MAJOR(img_report.sl_version) < 5)) {
1069 for (i = 0; i<NB_OLD_C32; i++) {
1070 PRINT_ISO_PROP(img_report.has_old_c32[i], " With an old %s", old_c32_name[i]);
1071 }
1072 }
1073 PRINT_ISO_PROP(HAS_KOLIBRIOS(img_report), " Uses: KolibriOS");
1074 PRINT_ISO_PROP(HAS_REACTOS(img_report), " Uses: ReactOS");
1075 PRINT_ISO_PROP(img_report.has_grub4dos, " Uses: Grub4DOS");
1076 PRINT_ISO_PROP(img_report.has_grub2, " Uses: GRUB2");
1077 if (img_report.has_efi == 0x80)
1078 uprintf(" Uses: EFI (through '%s')", img_report.efi_img_path);
1079 else
1080 PRINT_ISO_PROP(img_report.has_efi, " Uses: EFI %s", HAS_WIN7_EFI(img_report) ? "(win7_x64)" : "");
1081 PRINT_ISO_PROP(HAS_BOOTMGR(img_report), " Uses: Bootmgr (%s)",
1082 HAS_BOOTMGR_BIOS(img_report) ? (HAS_BOOTMGR_EFI(img_report) ? "BIOS and UEFI" : "BIOS only") : "UEFI only");
1083 PRINT_ISO_PROP(HAS_WINPE(img_report), " Uses: WinPE %s", (img_report.uses_minint) ? "(with /minint)" : "");
1084 if (HAS_WININST(img_report)) {
1085 inst_str[4] = '0' + img_report.wininst_index;
1086 uprintf(" Uses: Install.%s%s (version %d.%d.%d%s)", &img_report.wininst_path[0][strlen(img_report.wininst_path[0]) - 3],
1087 (img_report.wininst_index > 1) ? inst_str : "", (img_report.wininst_version >> 24) & 0xff,
1088 (img_report.wininst_version >> 16) & 0xff, (img_report.wininst_version >> 8) & 0xff,
1089 (img_report.wininst_version >= SPECIAL_WIM_VERSION) ? "+": "");
1090 }
1091 PRINT_ISO_PROP(img_report.has_symlinks,
1092 " Note: This ISO uses symbolic links, which will not be replicated due to file system");
1093 PRINT_ISO_PROP((img_report.has_symlinks == SYMLINKS_RR),
1094 " limitations. Because of this, some features from this image may not work...");
1095 PRINT_ISO_PROP((img_report.has_symlinks == SYMLINKS_UDF),
1096 " limitations. Because of this, the size required for the target media may be much\r\n"
1097 " larger than size of the ISO...");
1098 }
1099
1100 // Insert the image name into the Boot selection dropdown and (re)populate the Image option dropdown
1101 static void UpdateImage(BOOL update_image_option_only)
1102 {
1103 assert(image_index != 0);
1104
1105 if (!update_image_option_only) {
1106 if (ComboBox_GetItemData(hBootType, image_index) == BT_IMAGE)
1107 ComboBox_DeleteString(hBootType, image_index);
1108 ComboBox_InsertStringU(hBootType, image_index,
1109 (image_path == NULL) ? lmprintf(MSG_281, lmprintf(MSG_280)) : short_image_path);
1110 ComboBox_SetItemData(hBootType, image_index, BT_IMAGE);
1111 IGNORE_RETVAL(ComboBox_SetCurSel(hBootType, image_index));
1112 boot_type = (int)ComboBox_GetCurItemData(hBootType);
1113 SetBootTypeDropdownWidth();
1114 }
1115
1116 ComboBox_ResetContent(hImageOption);
1117 if (!img_report.is_windows_img)
1118 IGNORE_RETVAL(ComboBox_SetItemData(hImageOption, ComboBox_AddStringU(hImageOption, lmprintf(MSG_117)), FALSE));
1119 IGNORE_RETVAL(ComboBox_SetItemData(hImageOption, ComboBox_AddStringU(hImageOption, lmprintf(MSG_118)), TRUE));
1120 IGNORE_RETVAL(ComboBox_SetCurSel(hImageOption, (img_report.is_windows_img || !windows_to_go_selected) ? 0 : 1));
1121 }
1122
1123 static uint8_t FindArch(const char* filename)
1124 {
1125 uint8_t ret = 0;
1126 HANDLE hFile = NULL, hFileMapping = NULL;
1127 PIMAGE_DOS_HEADER pImageDOSHeader = NULL;
1128 // NB: The field we are after is at the same location for 32 and 64-bit
1129 // PE headers, so we don't need to care about using PIMAGE_NT_HEADERS[32|64]
1130 PIMAGE_NT_HEADERS pImageNTHeader = NULL;
1131
1132 hFile = CreateFileU(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1133 if (hFile == NULL) {
1134 uprintf("FindArch: Could not open file '%s': %s", filename, WindowsErrorString());
1135 return 0;
1136 }
1137
1138 hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
1139 if (hFileMapping == NULL) {
1140 uprintf("FindArch: Could not create file mapping: %s", WindowsErrorString());
1141 goto out;
1142 }
1143
1144 pImageDOSHeader = (PIMAGE_DOS_HEADER)MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
1145 if (pImageDOSHeader == NULL) {
1146 uprintf("FindArch: Could not get mapped view address: %s", WindowsErrorString());
1147 goto out;
1148 }
1149 if (pImageDOSHeader->e_magic != IMAGE_DOS_SIGNATURE) {
1150 uprintf("FindArch: DOS header not found");
1151 goto out;
1152 }
1153 pImageNTHeader = (PIMAGE_NT_HEADERS)((uintptr_t)pImageDOSHeader + pImageDOSHeader->e_lfanew);
1154 if (pImageNTHeader->Signature != IMAGE_NT_SIGNATURE) {
1155 uprintf("FindArch: NT header not found");
1156 goto out;
1157 }
1158
1159 switch (pImageNTHeader->FileHeader.Machine) {
1160 case IMAGE_FILE_MACHINE_I386:
1161 ret = 1;
1162 break;
1163 case IMAGE_FILE_MACHINE_IA64:
1164 ret = 2;
1165 break;
1166 case IMAGE_FILE_MACHINE_AMD64:
1167 ret = 3;
1168 break;
1169 case IMAGE_FILE_MACHINE_ARM:
1170 ret = 4;
1171 break;
1172 case IMAGE_FILE_MACHINE_ARM64:
1173 ret = 5;
1174 break;
1175 case IMAGE_FILE_MACHINE_EBC:
1176 ret = 6;
1177 break;
1178 case IMAGE_FILE_MACHINE_RISCV32:
1179 ret = 7;
1180 break;
1181 case IMAGE_FILE_MACHINE_RISCV64:
1182 ret = 8;
1183 break;
1184 case IMAGE_FILE_MACHINE_RISCV128:
1185 ret = 9;
1186 break;
1187 }
1188
1189 out:
1190 if (pImageDOSHeader != NULL)
1191 UnmapViewOfFile(pImageDOSHeader);
1192 safe_closehandle(hFileMapping);
1193 safe_closehandle(hFile);
1194 assert(ret <= MAX_ARCHS);
1195 return ret;
1196 }
1197
1198 // The scanning process can be blocking for message processing => use a thread
1199 DWORD WINAPI ImageScanThread(LPVOID param)
1200 {
1201 int i;
1202 uint8_t arch;
1203 char tmp_path[MAX_PATH];
1204
1205 if (image_path == NULL)
1206 goto out;
1207 PrintInfoDebug(0, MSG_202);
1208 user_notified = FALSE;
1209 EnableControls(FALSE, FALSE);
1210 memset(&img_report, 0, sizeof(img_report));
1211 img_report.is_iso = (BOOLEAN)ExtractISO(image_path, "", TRUE);
1212 img_report.is_bootable_img = IsBootableImage(image_path);
1213 ComboBox_ResetContent(hImageOption);
1214
1215 if ((FormatStatus == (ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_CANCELLED)) ||
1216 (img_report.image_size == 0) ||
1217 (!img_report.is_iso && !img_report.is_bootable_img && !img_report.is_windows_img)) {
1218 // Failed to scan image
1219 SendMessage(hMainDialog, UM_PROGRESS_EXIT, 0, 0);
1220 safe_free(image_path);
1221 UpdateImage(FALSE);
1222 SetMBRProps();
1223 PopulateProperties();
1224 PrintInfoDebug(0, MSG_203);
1225 PrintStatus(0, MSG_203);
1226 EnableControls(TRUE, FALSE);
1227 MessageBoxExU(hMainDialog, lmprintf(MSG_082), lmprintf(MSG_081), MB_OK | MB_ICONINFORMATION | MB_IS_RTL, selected_langid);
1228 goto out;
1229 }
1230
1231 if (img_report.is_windows_img) {
1232 selection_default = BT_IMAGE;
1233 // coverity[swapped_arguments]
1234 if (GetTempFileNameU(temp_dir, APPLICATION_NAME, 0, tmp_path) != 0) {
1235 // Only look at index 1 for now. If people complain, we may look for more.
1236 if (WimExtractFile(image_path, 1, "Windows\\Boot\\EFI\\bootmgr.efi", tmp_path, TRUE)) {
1237 arch = FindArch(tmp_path);
1238 if (arch != 0) {
1239 uprintf(" Image contains a%s %s EFI boot manager", arch_name[arch - 1], (arch < 7) ? "n" : "");
1240 img_report.has_efi = 1 | (1 << arch);
1241 img_report.has_bootmgr_efi = TRUE;
1242 img_report.wininst_index = 1;
1243 } else {
1244 uprintf(" Image does not contain an EFI boot manager");
1245 }
1246 }
1247 DeleteFileU(tmp_path);
1248 }
1249 uprintf(" Image is %sa UEFI bootable Windows installation image", img_report.has_efi ? "" : "NOT ");
1250 } else if (img_report.is_bootable_img) {
1251 if (img_report.is_bootable_img == 2)
1252 uprintf(" Image is a FORCED non-bootable image");
1253 else
1254 uprintf(" Image is a %sbootable %s image",
1255 (img_report.compression_type != BLED_COMPRESSION_NONE) ? "compressed " : "", img_report.is_vhd ? "VHD" : "disk");
1256 selection_default = BT_IMAGE;
1257 }
1258
1259 if (img_report.is_iso) {
1260 DisplayISOProps();
1261 // If we have an ISOHybrid, but without an ISO method we support, disable ISO support altogether
1262 if (IS_DD_BOOTABLE(img_report) && (img_report.disable_iso ||
1263 (!IS_BIOS_BOOTABLE(img_report) && !IS_EFI_BOOTABLE(img_report)))) {
1264 uprintf("Note: ISO mode will be disabled because this ISOHybrid is not compatible with ISO boot.");
1265 img_report.is_iso = FALSE;
1266 }
1267 selection_default = BT_IMAGE;
1268 }
1269 if (!IS_DD_BOOTABLE(img_report) && !IS_BIOS_BOOTABLE(img_report) && !IS_EFI_BOOTABLE(img_report)) {
1270 // No boot method that we support
1271 PrintInfo(0, MSG_081);
1272 safe_free(image_path);
1273 MessageBoxExU(hMainDialog, lmprintf(MSG_082), lmprintf(MSG_081), MB_OK | MB_ICONINFORMATION | MB_IS_RTL, selected_langid);
1274 PrintStatus(0, MSG_086);
1275 EnableControls(TRUE, FALSE);
1276 SetMBRProps();
1277 } else {
1278 if (!dont_display_image_name) {
1279 for (i = (int)safe_strlen(image_path); (i > 0) && (image_path[i] != '\\'); i--);
1280 if (i != 0)
1281 i++;
1282 short_image_path = &image_path[i];
1283 PrintStatus(0, MSG_205, short_image_path);
1284 uprintf("Using image: %s (%s)", short_image_path, SizeToHumanReadable(img_report.image_size, FALSE, FALSE));
1285 }
1286 UpdateImage(dont_display_image_name);
1287 ToggleImageOptions();
1288 EnableControls(TRUE, FALSE);
1289 // Set Target and FS accordingly
1290 if (img_report.is_iso || img_report.is_windows_img) {
1291 IGNORE_RETVAL(ComboBox_SetCurSel(hBootType, image_index));
1292 SetPartitionSchemeAndTargetSystem(FALSE);
1293 SetFileSystemAndClusterSize(NULL);
1294 SetFSFromISO();
1295 SetMBRProps();
1296 SetProposedLabel(ComboBox_GetCurSel(hDeviceList));
1297 } else {
1298 SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE_INTERNAL<<16) | IDC_FILE_SYSTEM,
1299 ComboBox_GetCurSel(hFileSystem));
1300 }
1301 // Lose the focus on the select ISO (but place it on Close)
1302 SendMessage(hMainDialog, WM_NEXTDLGCTL, (WPARAM)FALSE, 0);
1303 // Lose the focus from Close and set it back to Start
1304 SendMessage(hMainDialog, WM_NEXTDLGCTL, (WPARAM)hStart, TRUE);
1305 }
1306
1307 // Need to invalidate as we may have changed the UI and may get artifacts if we don't
1308 // Oh and we need to invoke BOTH RedrawWindow() and InvalidateRect() because UI refresh
1309 // in the Microsoft worlds SUCKS!!!! (we may lose the disabled "Start" button otherwise)
1310 RedrawWindow(hMainDialog, NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW);
1311 InvalidateRect(hMainDialog, NULL, TRUE);
1312
1313 out:
1314 dont_display_image_name = FALSE;
1315 PrintInfo(0, MSG_210);
1316 ExitThread(0);
1317 }
1318
1319 // Likewise, boot check will block message processing => use a thread
1320 static DWORD WINAPI BootCheckThread(LPVOID param)
1321 {
1322 int i, r;
1323 FILE *fd;
1324 DWORD len;
1325 WPARAM ret = BOOTCHECK_CANCEL;
1326 BOOL in_files_dir = FALSE;
1327 const char* grub = "grub";
1328 const char* core_img = "core.img";
1329 const char* ldlinux = "ldlinux";
1330 const char* syslinux = "syslinux";
1331 const char* ldlinux_ext[3] = { "sys", "bss", "c32" };
1332 char tmp[MAX_PATH], tmp2[MAX_PATH];
1333
1334 syslinux_ldlinux_len[0] = 0; syslinux_ldlinux_len[1] = 0;
1335 safe_free(grub2_buf);
1336
1337 if (ComboBox_GetCurSel(hDeviceList) == CB_ERR)
1338 goto out;
1339
1340 if ((zero_drive) || (boot_type == BT_NON_BOOTABLE)) {
1341 // Nothing to check
1342 ret = BOOTCHECK_PROCEED;
1343 goto out;
1344 }
1345
1346 if (boot_type == BT_IMAGE) {
1347 assert(image_path != NULL);
1348 if (image_path == NULL)
1349 goto out;
1350 if ((size_check) && (img_report.projected_size > (uint64_t)SelectedDrive.DiskSize)) {
1351 // This ISO image is too big for the selected target
1352 MessageBoxExU(hMainDialog, lmprintf(MSG_089), lmprintf(MSG_088), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid);
1353 goto out;
1354 }
1355 if (IS_DD_BOOTABLE(img_report) && !img_report.is_iso) {
1356 // Pure DD images are fine at this stage
1357 ret = BOOTCHECK_PROCEED;
1358 goto out;
1359 }
1360 if ((image_options & IMOP_WINTOGO) && ComboBox_GetCurItemData(hImageOption)) {
1361 if (fs_type != FS_NTFS) {
1362 // Windows To Go only works for NTFS
1363 MessageBoxExU(hMainDialog, lmprintf(MSG_097, "Windows To Go"), lmprintf(MSG_092), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid);
1364 goto out;
1365 }
1366 if (SelectedDrive.MediaType != FixedMedia) {
1367 if ((target_type == TT_UEFI) && (partition_type == PARTITION_STYLE_GPT) && (nWindowsBuildNumber < 15000)) {
1368 // Up to Windows 10 Creators Update (1703), we were screwed, since we need access to 2 partitions at the same time.
1369 // Thankfully, the newer Windows allow mounting multiple partitions on the same REMOVABLE drive.
1370 MessageBoxExU(hMainDialog, lmprintf(MSG_198), lmprintf(MSG_190), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid);
1371 goto out;
1372 }
1373 }
1374 // If multiple versions are available, asks the user to select one before we commit to format the drive
1375 switch(SetWinToGoIndex()) {
1376 case -1:
1377 MessageBoxExU(hMainDialog, lmprintf(MSG_073), lmprintf(MSG_291), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid);
1378 // fall through
1379 case -2:
1380 goto out;
1381 default:
1382 break;
1383 }
1384 } else if (target_type == TT_UEFI) {
1385 if (!IS_EFI_BOOTABLE(img_report)) {
1386 // Unsupported ISO
1387 MessageBoxExU(hMainDialog, lmprintf(MSG_091), lmprintf(MSG_090), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid);
1388 goto out;
1389 }
1390 if (HAS_WIN7_EFI(img_report) && (!WimExtractCheck(FALSE))) {
1391 // Your platform cannot extract files from WIM archives => download 7-zip?
1392 if (MessageBoxExU(hMainDialog, lmprintf(MSG_102), lmprintf(MSG_101), MB_YESNO | MB_ICONERROR | MB_IS_RTL, selected_langid) == IDYES)
1393 ShellExecuteA(hMainDialog, "open", SEVENZIP_URL, NULL, NULL, SW_SHOWNORMAL);
1394 goto out;
1395 }
1396 } else if ( ((fs_type == FS_NTFS) && !HAS_WINDOWS(img_report) && !HAS_GRUB(img_report) &&
1397 (!HAS_SYSLINUX(img_report) || (SL_MAJOR(img_report.sl_version) <= 5)))
1398 || ((IS_FAT(fs_type)) && (!HAS_SYSLINUX(img_report)) && (!allow_dual_uefi_bios) && !IS_EFI_BOOTABLE(img_report) &&
1399 (!HAS_REACTOS(img_report)) && !HAS_KOLIBRIOS(img_report) && (!HAS_GRUB(img_report)))
1400 || ((IS_FAT(fs_type)) && (HAS_WINDOWS(img_report) || HAS_WININST(img_report)) && (!allow_dual_uefi_bios)) ) {
1401 // Incompatible FS and ISO
1402 MessageBoxExU(hMainDialog, lmprintf(MSG_096), lmprintf(MSG_092), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid);
1403 goto out;
1404 } else if ((fs_type == FS_FAT16) && HAS_KOLIBRIOS(img_report)) {
1405 // KolibriOS doesn't support FAT16
1406 MessageBoxExU(hMainDialog, lmprintf(MSG_189), lmprintf(MSG_099), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid);
1407 goto out;
1408 }
1409 if ((IS_FAT(fs_type)) && (img_report.has_4GB_file)) {
1410 // This ISO image contains a file larger than 4GB file (FAT32)
1411 MessageBoxExU(hMainDialog, lmprintf(MSG_100), lmprintf(MSG_099), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid);
1412 goto out;
1413 }
1414
1415 // If the selected target doesn't include include BIOS, skip file downloads for GRUB/Syslinux
1416 if (target_type != TT_BIOS)
1417 goto uefi_target;
1418
1419 if ((partition_type == PARTITION_STYLE_MBR) && (img_report.has_grub2) && (img_report.grub2_version[0] != 0) &&
1420 (strcmp(img_report.grub2_version, GRUB2_PACKAGE_VERSION) != 0)) {
1421 // We may have to download a different Grub2 version if we can find one
1422 IGNORE_RETVAL(_chdirU(app_dir));
1423 IGNORE_RETVAL(_mkdir(FILES_DIR));
1424 IGNORE_RETVAL(_chdir(FILES_DIR));
1425 static_sprintf(tmp, "%s-%s/%s", grub, img_report.grub2_version, core_img);
1426 fd = fopen(tmp, "rb");
1427 if (fd != NULL) {
1428 // If a file already exists in the current directory, use that one
1429 uprintf("Will reuse '%s' from './" FILES_DIR "/%s-%s/' for Grub 2.x installation",
1430 core_img, grub, img_report.grub2_version);
1431 fseek(fd, 0, SEEK_END);
1432 grub2_len = ftell(fd);
1433 fseek(fd, 0, SEEK_SET);
1434 if (grub2_len > 0)
1435 grub2_buf = malloc(grub2_len);
1436
1437 // grub2_buf was set to NULL at the beginning of this call
1438 if ((grub2_buf == NULL) || (fread(grub2_buf, 1, (size_t)grub2_len, fd) != (size_t)grub2_len)) {
1439 uprintf("Failed to read existing '%s' data - will use embedded version", core_img);
1440 safe_free(grub2_buf);
1441 }
1442 fclose(fd);
1443 } else {
1444 r = MessageBoxExU(hMainDialog, lmprintf(MSG_116, img_report.grub2_version, GRUB2_PACKAGE_VERSION),
1445 lmprintf(MSG_115), MB_YESNOCANCEL|MB_ICONWARNING|MB_IS_RTL, selected_langid);
1446 if (r == IDCANCEL)
1447 goto out;
1448 else if (r == IDYES) {
1449 static_sprintf(tmp, "%s-%s", grub, img_report.grub2_version);
1450 IGNORE_RETVAL(_mkdir(tmp));
1451 IGNORE_RETVAL(_chdir(tmp));
1452 static_sprintf(tmp, "%s/%s-%s/%s", FILES_URL, grub, img_report.grub2_version, core_img);
1453 grub2_len = (long)DownloadSignedFile(tmp, core_img, hMainDialog, FALSE);
1454 if ((grub2_len == 0) && (DownloadStatus == 404)) {
1455 // Manjaro (always them!) are using "2.03.5" as identifier, so we must detect first dot...
1456 BOOL first_dot = TRUE;
1457 // Couldn't locate the file on the server => try to download without the version extra
1458 uprintf("Extended version was not found, trying main version...");
1459 static_strcpy(tmp2, img_report.grub2_version);
1460 // Isolate the #.### part
1461 for (i = 0; ((tmp2[i] >= '0') && (tmp2[i] <= '9')) || ((tmp2[i] == '.') && first_dot); i++) {
1462 if (tmp2[i] == '.')
1463 first_dot = FALSE;
1464 }
1465 tmp2[i] = 0;
1466 static_sprintf(tmp, "%s/%s-%s/%s", FILES_URL, grub, tmp2, core_img);
1467 grub2_len = (long)DownloadSignedFile(tmp, core_img, hMainDialog, FALSE);
1468 static_sprintf(tmp, "%s/%s-%s/%s", FILES_URL, grub, img_report.grub2_version, core_img);
1469 }
1470 if (grub2_len <= 0) {
1471 PrintInfo(0, MSG_195, "Grub2");
1472 uprintf("%s was not found - will use embedded version", tmp);
1473 } else {
1474 PrintInfo(0, MSG_193, tmp);
1475 fd = fopen(core_img, "rb");
1476 grub2_buf = malloc(grub2_len);
1477 if ((fd == NULL) || (grub2_buf == NULL) || (fread(grub2_buf, 1, (size_t)grub2_len, fd) != (size_t)grub2_len)) {
1478 uprintf("Failed to read '%s' data - will use embedded version", core_img);
1479 safe_free(grub2_buf);
1480 }
1481 if (fd != NULL)
1482 fclose(fd);
1483 }
1484 }
1485 }
1486 }
1487
1488 if ((partition_type == PARTITION_STYLE_MBR) && HAS_SYSLINUX(img_report)) {
1489 if (SL_MAJOR(img_report.sl_version) < 5) {
1490 IGNORE_RETVAL(_chdirU(app_dir));
1491 for (i=0; i<NB_OLD_C32; i++) {
1492 if (img_report.has_old_c32[i]) {
1493 if (!in_files_dir) {
1494 IGNORE_RETVAL(_mkdir(FILES_DIR));
1495 IGNORE_RETVAL(_chdir(FILES_DIR));
1496 in_files_dir = TRUE;
1497 }
1498 static_sprintf(tmp, "%s-%s/%s", syslinux, embedded_sl_version_str[0], old_c32_name[i]);
1499 fd = fopen(tmp, "rb");
1500 if (fd != NULL) {
1501 // If a file already exists in the current directory, use that one
1502 uprintf("Will replace obsolete '%s' from ISO with the one found in './" FILES_DIR "/%s'", old_c32_name[i], tmp);
1503 fclose(fd);
1504 use_own_c32[i] = TRUE;
1505 } else {
1506 PrintInfo(0, MSG_204, old_c32_name[i]);
1507 if (MessageBoxExU(hMainDialog, lmprintf(MSG_084, old_c32_name[i], old_c32_name[i]),
1508 lmprintf(MSG_083, old_c32_name[i]), MB_YESNO|MB_ICONWARNING|MB_IS_RTL, selected_langid) == IDYES) {
1509 static_sprintf(tmp, "%s-%s", syslinux, embedded_sl_version_str[0]);
1510 IGNORE_RETVAL(_mkdir(tmp));
1511 static_sprintf(tmp, "%s/%s-%s/%s", FILES_URL, syslinux, embedded_sl_version_str[0], old_c32_name[i]);
1512 len = DownloadSignedFile(tmp, &tmp[sizeof(FILES_URL)], hMainDialog, TRUE);
1513 if (len == 0) {
1514 uprintf("Could not download file - cancelling");
1515 ret = BOOTCHECK_DOWNLOAD_ERROR;
1516 goto out;
1517 }
1518 use_own_c32[i] = TRUE;
1519 }
1520 }
1521 }
1522 }
1523 } else if ((img_report.sl_version != embedded_sl_version[1]) ||
1524 (safe_strcmp(img_report.sl_version_ext, embedded_sl_version_ext[1]) != 0)) {
1525 // Unlike what was the case for v4 and earlier, Syslinux v5+ versions are INCOMPATIBLE with one another!
1526 IGNORE_RETVAL(_chdirU(app_dir));
1527 IGNORE_RETVAL(_mkdir(FILES_DIR));
1528 IGNORE_RETVAL(_chdir(FILES_DIR));
1529 for (i=0; i<2; i++) {
1530 // Check if we already have the relevant ldlinux_v#.##.sys & ldlinux_v#.##.bss files
1531 static_sprintf(tmp, "%s-%s%s/%s.%s", syslinux, img_report.sl_version_str,
1532 img_report.sl_version_ext, ldlinux, ldlinux_ext[i]);
1533 fd = fopen(tmp, "rb");
1534 if (fd != NULL) {
1535 fseek(fd, 0, SEEK_END);
1536 syslinux_ldlinux_len[i] = (DWORD)ftell(fd);
1537 fclose(fd);
1538 }
1539 }
1540 if ((syslinux_ldlinux_len[0] != 0) && (syslinux_ldlinux_len[1] != 0)) {
1541 uprintf("Will reuse '%s.%s' and '%s.%s' from './" FILES_DIR "/%s/%s-%s%s/' for Syslinux installation",
1542 ldlinux, ldlinux_ext[0], ldlinux, ldlinux_ext[1], FILES_DIR, syslinux,
1543 img_report.sl_version_str, img_report.sl_version_ext);
1544 } else {
1545 r = MessageBoxExU(hMainDialog, lmprintf(MSG_114, img_report.sl_version_str, img_report.sl_version_ext,
1546 embedded_sl_version_str[1], embedded_sl_version_ext[1]),
1547 lmprintf(MSG_115), MB_YESNO|MB_ICONWARNING|MB_IS_RTL, selected_langid);
1548 if (r != IDYES)
1549 goto out;
1550 for (i=0; i<2; i++) {
1551 static_sprintf(tmp, "%s-%s", syslinux, img_report.sl_version_str);
1552 IGNORE_RETVAL(_mkdir(tmp));
1553 if (*img_report.sl_version_ext != 0) {
1554 IGNORE_RETVAL(_chdir(tmp));
1555 IGNORE_RETVAL(_mkdir(&img_report.sl_version_ext[1]));
1556 IGNORE_RETVAL(_chdir(".."));
1557 }
1558 static_sprintf(tmp, "%s/%s-%s%s/%s.%s", FILES_URL, syslinux, img_report.sl_version_str,
1559 img_report.sl_version_ext, ldlinux, ldlinux_ext[i]);
1560 syslinux_ldlinux_len[i] = DownloadSignedFile(tmp, &tmp[sizeof(FILES_URL)],
1561 hMainDialog, (*img_report.sl_version_ext == 0));
1562 if ((syslinux_ldlinux_len[i] == 0) && (DownloadStatus == 404) && (*img_report.sl_version_ext != 0)) {
1563 // Couldn't locate the file on the server => try to download without the version extra
1564 uprintf("Extended version was not found, trying main version...");
1565 static_sprintf(tmp, "%s/%s-%s/%s.%s", FILES_URL, syslinux, img_report.sl_version_str,
1566 ldlinux, ldlinux_ext[i]);
1567 syslinux_ldlinux_len[i] = DownloadSignedFile(tmp, &tmp[sizeof(FILES_URL)],
1568 hMainDialog, (*img_report.sl_version_ext == 0));
1569 if (syslinux_ldlinux_len[i] != 0) {
1570 // Duplicate the file so that the user won't be prompted to download again
1571 static_sprintf(tmp, "%s-%s\\%s.%s", syslinux, img_report.sl_version_str, ldlinux, ldlinux_ext[i]);
1572 static_sprintf(tmp2, "%s-%s\\%s\\%s.%s", syslinux, img_report.sl_version_str,
1573 &img_report.sl_version_ext[1], ldlinux, ldlinux_ext[i]);
1574 CopyFileA(tmp, tmp2, FALSE);
1575 }
1576 }
1577 if (syslinux_ldlinux_len[i] == 0) {
1578 // If the version matches our embedded one, try to use that as a last ditch effort
1579 if (img_report.sl_version == embedded_sl_version[1]) {
1580 uprintf("Could not download the file - will try to use embedded %s version instead", img_report.sl_version_str);
1581 } else {
1582 uprintf("Could not download the file - cancelling");
1583 ret = BOOTCHECK_DOWNLOAD_ERROR;
1584 goto out;
1585 }
1586 }
1587 }
1588 }
1589 }
1590 }
1591 } else if (boot_type == BT_SYSLINUX_V6) {
1592 IGNORE_RETVAL(_chdirU(app_dir));
1593 IGNORE_RETVAL(_mkdir(FILES_DIR));
1594 IGNORE_RETVAL(_chdir(FILES_DIR));
1595 static_sprintf(tmp, "%s-%s/%s.%s", syslinux, embedded_sl_version_str[1], ldlinux, ldlinux_ext[2]);
1596 fd = fopenU(tmp, "rb");
1597 if (fd != NULL) {
1598 uprintf("Will reuse './%s/%s' for Syslinux installation", FILES_DIR, tmp);
1599 fclose(fd);
1600 } else {
1601 static_sprintf(tmp, "%s.%s", ldlinux, ldlinux_ext[2]);
1602 PrintInfo(0, MSG_206, tmp);
1603 // MSG_104: "Syslinux v5.0 or later requires a '%s' file to be installed"
1604 r = MessageBoxExU(hMainDialog, lmprintf(MSG_104, "Syslinux v5.0", tmp, "Syslinux v5+", tmp),
1605 lmprintf(MSG_103, tmp), MB_YESNOCANCEL|MB_ICONWARNING|MB_IS_RTL, selected_langid);
1606 if (r == IDCANCEL)
1607 goto out;
1608 if (r == IDYES) {
1609 static_sprintf(tmp, "%s-%s", syslinux, embedded_sl_version_str[1]);
1610 IGNORE_RETVAL(_mkdir(tmp));
1611 static_sprintf(tmp, "%s/%s-%s/%s.%s", FILES_URL, syslinux, embedded_sl_version_str[1], ldlinux, ldlinux_ext[2]);
1612 if (DownloadSignedFile(tmp, &tmp[sizeof(FILES_URL)], hMainDialog, TRUE) == 0) {
1613 ret = BOOTCHECK_DOWNLOAD_ERROR;
1614 goto out;
1615 }
1616 }
1617 }
1618 } else if (boot_type == BT_MSDOS) {
1619 if ((size_check) && (ComboBox_GetCurItemData(hClusterSize) >= 65536)) {
1620 // MS-DOS cannot boot from a drive using a 64 kilobytes Cluster size
1621 MessageBoxExU(hMainDialog, lmprintf(MSG_110), lmprintf(MSG_111), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid);
1622 goto out;
1623 }
1624 } else if (boot_type == BT_GRUB4DOS) {
1625 IGNORE_RETVAL(_chdirU(app_dir));
1626 IGNORE_RETVAL(_mkdir(FILES_DIR));
1627 IGNORE_RETVAL(_chdir(FILES_DIR));
1628 static_sprintf(tmp, "grub4dos-%s/grldr", GRUB4DOS_VERSION);
1629 fd = fopenU(tmp, "rb");
1630 if (fd != NULL) {
1631 uprintf("Will reuse './%s/%s' for Grub4DOS installation", FILES_DIR, tmp);
1632 fclose(fd);
1633 } else {
1634 static_sprintf(tmp, "grldr");
1635 PrintInfo(0, MSG_206, tmp);
1636 r = MessageBoxExU(hMainDialog, lmprintf(MSG_104, "Grub4DOS 0.4", tmp, "Grub4DOS", tmp),
1637 lmprintf(MSG_103, tmp), MB_YESNOCANCEL|MB_ICONWARNING|MB_IS_RTL, selected_langid);
1638 if (r == IDCANCEL)
1639 goto out;
1640 if (r == IDYES) {
1641 static_sprintf(tmp, "grub4dos-%s", GRUB4DOS_VERSION);
1642 IGNORE_RETVAL(_mkdir(tmp));
1643 static_sprintf(tmp, "%s/grub4dos-%s/grldr", FILES_URL, GRUB4DOS_VERSION);
1644 if (DownloadSignedFile(tmp, &tmp[sizeof(FILES_URL)], hMainDialog, TRUE) == 0) {
1645 ret = BOOTCHECK_DOWNLOAD_ERROR;
1646 goto out;
1647 }
1648 }
1649 }
1650 }
1651
1652 uefi_target:
1653 if (boot_type == BT_UEFI_NTFS) {
1654 fs_type = (int)ComboBox_GetCurItemData(hFileSystem);
1655 if (fs_type != FS_NTFS && fs_type != FS_EXFAT) {
1656 MessageBoxExU(hMainDialog, lmprintf(MSG_097, "UEFI:NTFS"), lmprintf(MSG_092), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid);
1657 goto out;
1658 }
1659 }
1660 ret = BOOTCHECK_PROCEED;
1661
1662 out:
1663 PostMessage(hMainDialog, UM_FORMAT_START, ret, 0);
1664 ExitThread((DWORD)ret);
1665 }
1666
1667 static __inline const char* IsAlphaOrBeta(void)
1668 {
1669 #if defined(ALPHA)
1670 return " (Alpha) ";
1671 #elif defined(BETA)
1672 return " (Beta) ";
1673 #elif defined(TEST)
1674 # define TEST_STR(x) " (Test" STRINGIFY(x) ") "
1675 return TEST_STR(TEST);
1676 #else
1677 return " ";
1678 #endif
1679 }
1680
1681 static void InitDialog(HWND hDlg)
1682 {
1683 DWORD len;
1684 HDC hDC;
1685 int i, lfHeight;
1686 char tmp[128], *token, *buf, *ext, *msg;
1687 static char* resource[2] = { MAKEINTRESOURCEA(IDR_SL_LDLINUX_V4_SYS), MAKEINTRESOURCEA(IDR_SL_LDLINUX_V6_SYS) };
1688
1689 #ifdef RUFUS_TEST
1690 ShowWindow(GetDlgItem(hDlg, IDC_TEST), SW_SHOW);
1691 #endif
1692
1693 hDC = GetDC(hDlg);
1694 lfHeight = -MulDiv(9, GetDeviceCaps(hDC, LOGPIXELSY), 72);
1695 safe_release_dc(hDlg, hDC);
1696
1697 // Quite a burden to carry around as parameters
1698 hMainDialog = hDlg;
1699 MainThreadId = GetCurrentThreadId();
1700 hDeviceList = GetDlgItem(hDlg, IDC_DEVICE);
1701 hPartitionScheme = GetDlgItem(hDlg, IDC_PARTITION_TYPE);
1702 hTargetSystem = GetDlgItem(hDlg, IDC_TARGET_SYSTEM);
1703 hFileSystem = GetDlgItem(hDlg, IDC_FILE_SYSTEM);
1704 hClusterSize = GetDlgItem(hDlg, IDC_CLUSTER_SIZE);
1705 hLabel = GetDlgItem(hDlg, IDC_LABEL);
1706 hProgress = GetDlgItem(hDlg, IDC_PROGRESS);
1707 hBootType = GetDlgItem(hDlg, IDC_BOOT_SELECTION);
1708 hImageOption = GetDlgItem(hDlg, IDC_IMAGE_OPTION);
1709 hSelectImage = GetDlgItem(hDlg, IDC_SELECT);
1710 hNBPasses = GetDlgItem(hDlg, IDC_NB_PASSES);
1711 hDiskID = GetDlgItem(hDlg, IDC_DISK_ID);
1712 hStart = GetDlgItem(hDlg, IDC_START);
1713
1714 // Convert the main button labels to uppercase
1715 GetWindowTextU(hStart, uppercase_start, sizeof(uppercase_start));
1716 CharUpperBuffU(uppercase_start, sizeof(uppercase_start));
1717 SetWindowTextU(hStart, uppercase_start);
1718 GetWindowTextU(GetDlgItem(hDlg, IDCANCEL), uppercase_close, sizeof(uppercase_close));
1719 CharUpperBuffU(uppercase_close, sizeof(uppercase_close));
1720 // Hardcoded exception for German
1721 if (strcmp("SCHLIEßEN", uppercase_close) == 0)
1722 strcpy(uppercase_close, "SCHLIESSEN");
1723 SetWindowTextU(GetDlgItem(hDlg, IDCANCEL), uppercase_close);
1724 GetWindowTextU(GetDlgItem(hDlg, IDC_SELECT), uppercase_select[0], sizeof(uppercase_select[0]));
1725 static_strcpy(uppercase_select[1], lmprintf(MSG_040));
1726 CharUpperBuffU(uppercase_select[0], sizeof(uppercase_select[0]));
1727 CharUpperBuffU(uppercase_select[1], sizeof(uppercase_select[1]));
1728 SetWindowTextU(GetDlgItem(hDlg, IDC_SELECT), uppercase_select[0]);
1729 static_strcpy(uppercase_cancel, lmprintf(MSG_007));
1730 CharUpperBuffU(uppercase_cancel, sizeof(uppercase_cancel));
1731
1732 CreateSmallButtons(hDlg);
1733 GetBasicControlsWidth(hDlg);
1734 GetMainButtonsWidth(hDlg);
1735 GetHalfDropwdownWidth(hDlg);
1736 GetFullWidth(hDlg);
1737
1738 // Set some missing labels
1739 SetAccessibleName(hNBPasses, lmprintf(MSG_316));
1740 SetAccessibleName(hDiskID, lmprintf(MSG_317));
1741
1742 // Create the font and brush for the progress messages
1743 hInfoFont = CreateFontA(lfHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
1744 0, 0, PROOF_QUALITY, 0, "Segoe UI");
1745
1746 // Create the title bar icon
1747 SetTitleBarIcon(hDlg);
1748 GetWindowTextA(hDlg, tmp, sizeof(tmp));
1749 // Count on Microsoft for making it more attractive to read a
1750 // version using strtok() than using GetFileVersionInfo()
1751 token = strtok(tmp, " ");
1752 for (i = 0; (i < 3) && ((token = strtok(NULL, ".")) != NULL); i++)
1753 rufus_version[i] = (uint16_t)atoi(token);
1754
1755 // Redefine the title to be able to add "Alpha" or "Beta"
1756 static_sprintf(tmp, APPLICATION_NAME " %d.%d.%d%s%s", rufus_version[0], rufus_version[1], rufus_version[2],
1757 IsAlphaOrBeta(), (ini_file != NULL)?"(Portable)":"");
1758 SetWindowTextU(hDlg, tmp);
1759 // Now that we have a title, we can find the handle of our Dialog
1760 dialog_handle = FindWindowA(NULL, tmp);
1761 uprintf(APPLICATION_NAME " " APPLICATION_ARCH " v%d.%d.%d%s%s", rufus_version[0], rufus_version[1], rufus_version[2],
1762 IsAlphaOrBeta(), (ini_file != NULL)?"(Portable)":"");
1763 for (i = 0; i < ARRAYSIZE(resource); i++) {
1764 len = 0;
1765 buf = (char*)GetResource(hMainInstance, resource[i], _RT_RCDATA, "ldlinux_sys", &len, TRUE);
1766 if (buf == NULL) {
1767 uprintf("Warning: could not read embedded Syslinux v%d version", i+4);
1768 } else {
1769 embedded_sl_version[i] = GetSyslinuxVersion(buf, len, &ext);
1770 static_sprintf(embedded_sl_version_str[i], "%d.%02d", SL_MAJOR(embedded_sl_version[i]), SL_MINOR(embedded_sl_version[i]));
1771 static_strcpy(embedded_sl_version_ext[i], ext);
1772 free(buf);
1773 }
1774 }
1775 uprintf("Windows version: %s", WindowsVersionStr);
1776 uprintf("Syslinux versions: %s%s, %s%s", embedded_sl_version_str[0], embedded_sl_version_ext[0],
1777 embedded_sl_version_str[1], embedded_sl_version_ext[1]);
1778 uprintf("Grub versions: %s, %s", GRUB4DOS_VERSION, GRUB2_PACKAGE_VERSION);
1779 uprintf("System locale ID: 0x%04X (%s)", GetUserDefaultUILanguage(), GetCurrentMUI());
1780 ubflush();
1781 if (selected_locale->ctrl_id & LOC_NEEDS_UPDATE) {
1782 uprintf("NOTE: The %s translation requires an update, but the current translator hasn't submitted "
1783 "one. Because of this, some messages will only be displayed in English.", selected_locale->txt[1]);
1784 uprintf("If you think you can help update this translation, please e-mail the author of this application");
1785 }
1786
1787 CreateTaskbarList();
1788 SetTaskbarProgressState(TASKBAR_NORMAL);
1789
1790 // Use maximum granularity for the progress bar
1791 SendMessage(hProgress, PBM_SETRANGE, 0, (MAX_PROGRESS<<16) & 0xFFFF0000);
1792
1793 // Fill up the passes
1794 for (i = 1; i <= 5; i++) {
1795 msg = (i == 1) ? lmprintf(MSG_034, 1) : lmprintf(MSG_035, (i == 2) ? 2 : 4, (i == 2) ? "" : lmprintf(MSG_087, flash_type[i - 3]));
1796 IGNORE_RETVAL(ComboBox_AddStringU(hNBPasses, msg));
1797 }
1798 IGNORE_RETVAL(ComboBox_SetCurSel(hNBPasses, 0));
1799 SetPassesTooltip();
1800
1801 // Fill up the boot options dropdown
1802 SetBootOptions();
1803
1804 // Fill up the MBR masqueraded disk IDs ("8 disks should be enough for anybody")
1805 IGNORE_RETVAL(ComboBox_SetItemData(hDiskID, ComboBox_AddStringU(hDiskID, lmprintf(MSG_030, LEFT_TO_RIGHT_EMBEDDING "0x80" POP_DIRECTIONAL_FORMATTING)), 0x80));
1806 for (i=1; i<=7; i++) {
1807 IGNORE_RETVAL(ComboBox_SetItemData(hDiskID, ComboBox_AddStringU(hDiskID, lmprintf(MSG_109, 0x80+i, i+1)), 0x80+i));
1808 }
1809 IGNORE_RETVAL(ComboBox_SetCurSel(hDiskID, 0));
1810
1811 // Create the string arrays
1812 StrArrayCreate(&DriveId, MAX_DRIVES);
1813 StrArrayCreate(&DriveName, MAX_DRIVES);
1814 StrArrayCreate(&DriveLabel, MAX_DRIVES);
1815 StrArrayCreate(&DriveHub, MAX_DRIVES);
1816 StrArrayCreate(&BlockingProcess, 16);
1817 StrArrayCreate(&ImageList, 16);
1818 // Set various checkboxes
1819 CheckDlgButton(hDlg, IDC_QUICK_FORMAT, BST_CHECKED);
1820 CheckDlgButton(hDlg, IDC_EXTENDED_LABEL, BST_CHECKED);
1821
1822 CreateAdditionalControls(hDlg);
1823 SetSectionHeaders(hDlg);
1824 PositionMainControls(hDlg);
1825 AdjustForLowDPI(hDlg);
1826 // Because we created the log dialog before we computed our sizes, we need to send a custom message
1827 SendMessage(hLogDialog, UM_RESIZE_BUTTONS, 0, 0);
1828 // Limit the amount of characters for the Persistence size field
1829 SendMessage(GetDlgItem(hDlg, IDC_PERSISTENCE_SIZE), EM_LIMITTEXT, 7, 0);
1830 // Create the status line and initialize the taskbar icon for progress overlay
1831 CreateStatusBar();
1832
1833 // Set the various tooltips
1834 CreateTooltip(hFileSystem, lmprintf(MSG_157), -1);
1835 CreateTooltip(hClusterSize, lmprintf(MSG_158), -1);
1836 CreateTooltip(hLabel, lmprintf(MSG_159), -1);
1837 CreateTooltip(hAdvancedDeviceToolbar, lmprintf(MSG_160), -1);
1838 CreateTooltip(hAdvancedFormatToolbar, lmprintf(MSG_160), -1);
1839 CreateTooltip(GetDlgItem(hDlg, IDC_BAD_BLOCKS), lmprintf(MSG_161), -1);
1840 CreateTooltip(GetDlgItem(hDlg, IDC_QUICK_FORMAT), lmprintf(MSG_162), -1);
1841 CreateTooltip(hBootType, lmprintf(MSG_164), -1);
1842 CreateTooltip(hSelectImage, lmprintf(MSG_165), -1);
1843 CreateTooltip(GetDlgItem(hDlg, IDC_EXTENDED_LABEL), lmprintf(MSG_166), 10000);
1844 CreateTooltip(GetDlgItem(hDlg, IDC_RUFUS_MBR), lmprintf(MSG_167), 10000);
1845 CreateTooltip(hDiskID, lmprintf(MSG_168), 10000);
1846 CreateTooltip(GetDlgItem(hDlg, IDC_OLD_BIOS_FIXES), lmprintf(MSG_169), -1);
1847 CreateTooltip(GetDlgItem(hDlg, IDC_LIST_USB_HDD), lmprintf(MSG_170), -1);
1848 CreateTooltip(hStart, lmprintf(MSG_171), -1);
1849 CreateTooltip(hPartitionScheme, lmprintf(MSG_163), -1);
1850 CreateTooltip(hTargetSystem, lmprintf(MSG_150), 30000);
1851 CreateTooltip(GetDlgItem(hDlg, IDS_CSM_HELP_TXT), lmprintf(MSG_151), 30000);
1852 CreateTooltip(hImageOption, lmprintf(MSG_305), 30000);
1853 CreateTooltip(GetDlgItem(hDlg, IDC_PERSISTENCE_SLIDER), lmprintf(MSG_125), 30000);
1854 CreateTooltip(GetDlgItem(hDlg, IDC_PERSISTENCE_SIZE), lmprintf(MSG_125), 30000);
1855 CreateTooltip(GetDlgItem(hDlg, IDC_PERSISTENCE_UNITS), lmprintf(MSG_126), 30000);
1856
1857 if (!advanced_mode_device) // Hide as needed, since we display the advanced controls by default
1858 ToggleAdvancedDeviceOptions(FALSE);
1859 if (!advanced_mode_format)
1860 ToggleAdvancedFormatOptions(FALSE);
1861 ToggleImageOptions();
1862
1863 // Process commandline parameters
1864 if (img_provided) {
1865 // Simulate a button click for image selection
1866 PostMessage(hDlg, WM_COMMAND, IDC_SELECT, 0);
1867 }
1868 SetBootTypeDropdownWidth();
1869
1870 CheckDlgButton(hMainDialog, IDC_LIST_USB_HDD, enable_HDDs ? BST_CHECKED : BST_UNCHECKED);
1871
1872 PrintInfo(0, MSG_210);
1873 }
1874
1875 static void PrintStatusTimeout(const char* str, BOOL val)
1876 {
1877 PrintStatus(STATUS_MSG_TIMEOUT, (val)?MSG_250:MSG_251, str);
1878 }
1879
1880 static void SaveVHD(void)
1881 {
1882 static IMG_SAVE img_save = { 0 };
1883 char filename[128];
1884 char path[MAX_PATH];
1885 int DriveIndex = ComboBox_GetCurSel(hDeviceList);
1886 EXT_DECL(img_ext, filename, __VA_GROUP__("*.vhd"), __VA_GROUP__(lmprintf(MSG_095)));
1887 ULARGE_INTEGER free_space;
1888
1889 if ((DriveIndex < 0) || (format_thread != NULL))
1890 return;
1891
1892 static_sprintf(filename, "%s.vhd", DriveLabel.String[DriveIndex]);
1893 img_save.Type = IMG_SAVE_TYPE_VHD;
1894 img_save.DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, DriveIndex);
1895 img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, 0);
1896 img_save.BufSize = DD_BUFFER_SIZE;
1897 img_save.DeviceSize = SelectedDrive.DiskSize;
1898 if (img_save.ImagePath != NULL) {
1899 // Reset all progress bars
1900 SendMessage(hMainDialog, UM_PROGRESS_INIT, 0, 0);
1901 FormatStatus = 0;
1902 free_space.QuadPart = 0;
1903 if ((GetVolumePathNameA(img_save.ImagePath, path, sizeof(path)))
1904 && (GetDiskFreeSpaceExA(path, &free_space, NULL, NULL))
1905 && ((LONGLONG)free_space.QuadPart > (SelectedDrive.DiskSize + 512))) {
1906 // Disable all controls except cancel
1907 EnableControls(FALSE, FALSE);
1908 FormatStatus = 0;
1909 InitProgress(TRUE);
1910 format_thread = CreateThread(NULL, 0, SaveImageThread, &img_save, 0, NULL);
1911 if (format_thread != NULL) {
1912 uprintf("\r\nSave to VHD operation started");
1913 PrintInfo(0, -1);
1914 SendMessage(hMainDialog, UM_TIMER_START, 0, 0);
1915 } else {
1916 uprintf("Unable to start VHD save thread");
1917 FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_START_THREAD);
1918 safe_free(img_save.ImagePath);
1919 PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
1920 }
1921 } else {
1922 if (free_space.QuadPart == 0) {
1923 uprintf("Unable to isolate drive name for VHD save");
1924 FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_PATH_NOT_FOUND;
1925 } else {
1926 uprintf("The VHD size is too large for the target drive");
1927 FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_FILE_TOO_LARGE;
1928 }
1929 safe_free(img_save.ImagePath);
1930 PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
1931 }
1932 }
1933 }
1934
1935 static void SaveISO(void)
1936 {
1937 static IMG_SAVE img_save = { 0 };
1938 char filename[33] = "disc_image.iso";
1939 EXT_DECL(img_ext, filename, __VA_GROUP__("*.iso"), __VA_GROUP__(lmprintf(MSG_036)));
1940
1941 if (op_in_progress || (format_thread != NULL))
1942 return;
1943
1944 img_save.Type = IMG_SAVE_TYPE_ISO;
1945 if (!GetOpticalMedia(&img_save)) {
1946 uprintf("No dumpable optical media found.");
1947 return;
1948 }
1949 // Adjust the buffer size according to the disc size so that we get a decent speed.
1950 for (img_save.BufSize = 32 * MB;
1951 (img_save.BufSize > 8 * MB) && (img_save.DeviceSize <= img_save.BufSize * 64);
1952 img_save.BufSize /= 2);
1953 if ((img_save.Label != NULL) && (img_save.Label[0] != 0))
1954 static_sprintf(filename, "%s.iso", img_save.Label);
1955 uprintf("ISO media size %s", SizeToHumanReadable(img_save.DeviceSize, FALSE, FALSE));
1956
1957 img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, 0);
1958 if (img_save.ImagePath == NULL)
1959 return;
1960 SendMessage(hMainDialog, UM_PROGRESS_INIT, 0, 0);
1961 FormatStatus = 0;
1962 // Disable all controls except cancel
1963 EnableControls(FALSE, FALSE);
1964 InitProgress(TRUE);
1965 format_thread = CreateThread(NULL, 0, SaveImageThread, &img_save, 0, NULL);
1966 if (format_thread != NULL) {
1967 uprintf("\r\nSave to ISO operation started");
1968 PrintInfo(0, -1);
1969 SendMessage(hMainDialog, UM_TIMER_START, 0, 0);
1970 } else {
1971 uprintf("Unable to start ISO save thread");
1972 FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_START_THREAD);
1973 safe_free(img_save.ImagePath);
1974 PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
1975 }
1976 }
1977
1978 // Check for conflicting processes accessing the drive.
1979 // If bPrompt is true, ask the user whether they want to proceed.
1980 // dwTimeOut is the maximum amount of time we allow for this call to execute (in ms)
1981 // If bPrompt is false, the return value is the amount of time remaining before
1982 // dwTimeOut would expire (or zero if we spent more than dwTimeout in this procedure).
1983 // If bPrompt is true, the return value is 0 on error, dwTimeOut on success.
1984 DWORD CheckDriveAccess(DWORD dwTimeOut, BOOL bPrompt)
1985 {
1986 uint32_t i, j;
1987 DWORD ret = 0, proceed = TRUE;
1988 BYTE access_mask;
1989 char *PhysicalPath = NULL, DevPath[MAX_PATH];
1990 char drive_letter[27], drive_name[] = "?:";
1991 char title[128];
1992 uint64_t start_time = GetTickCount64(), cur_time, end_time = start_time + dwTimeOut;
1993
1994 // Get the current selected device
1995 DWORD DeviceNum = (DWORD)ComboBox_GetCurItemData(hDeviceList);
1996 if ((DeviceNum < 0x80) || (DeviceNum == (DWORD)-1))
1997 return FALSE;
1998
1999 // "Checking for conflicting processes..."
2000 if (bPrompt)
2001 PrintInfo(0, MSG_278);
2002
2003 // Search for any blocking processes against the physical drive
2004 PhysicalPath = GetPhysicalName(DeviceNum);
2005 if (QueryDosDeviceA(&PhysicalPath[4], DevPath, sizeof(DevPath)) != 0) {
2006 access_mask = SearchProcess(DevPath, dwTimeOut, TRUE, TRUE, TRUE);
2007 CHECK_FOR_USER_CANCEL;
2008 if (access_mask != 0) {
2009 proceed = FALSE;
2010 uprintf("Found potentially blocking process(es) against %s:", &PhysicalPath[4]);
2011 for (j = 0; j < BlockingProcess.Index; j++)
2012 uprintf(BlockingProcess.String[j]);
2013 }
2014 }
2015
2016 // Search for any blocking processes against the logical volume(s)
2017 GetDriveLetters(DeviceNum, drive_letter);
2018 for (i = 0; drive_letter[i]; i++) {
2019 drive_name[0] = drive_letter[i];
2020 if (QueryDosDeviceA(drive_name, DevPath, sizeof(DevPath)) != 0) {
2021 StrArrayClear(&BlockingProcess);
2022 cur_time = GetTickCount64();
2023 if (cur_time >= end_time)
2024 break;
2025 access_mask = SearchProcess(DevPath, (DWORD)(end_time - cur_time), TRUE, TRUE, TRUE);
2026 CHECK_FOR_USER_CANCEL;
2027 // Ignore if all we have is read-only
2028 if ((access_mask & 0x06) || (access_mask == 0x80)) {
2029 proceed = FALSE;
2030 uprintf("Found potentially blocking process(es) against %s", drive_name);
2031 for (j = 0; j < BlockingProcess.Index; j++)
2032 uprintf(BlockingProcess.String[j]);
2033 }
2034 }
2035 }
2036
2037 // Prompt the user if we detected blocking processes
2038 if (bPrompt && !proceed) {
2039 ComboBox_GetTextU(hDeviceList, title, sizeof(title));
2040 proceed = Notification(MSG_WARNING_QUESTION, NULL, NULL, title, lmprintf(MSG_132));
2041 }
2042 if (bPrompt) {
2043 ret = proceed ? dwTimeOut : 0;
2044 } else {
2045 ret = (DWORD)(GetTickCount64() - start_time);
2046 ret = (dwTimeOut > ret) ? (dwTimeOut - ret) : 0;
2047 }
2048
2049 out:
2050 PrintInfo(0, MSG_210);
2051 free(PhysicalPath);
2052 return ret;
2053 }
2054
2055 /*
2056 * Main dialog callback
2057 */
2058 static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
2059 {
2060 static DWORD DeviceNum = 0;
2061 static uint64_t LastRefresh = 0;
2062 static BOOL first_log_display = TRUE, isMarquee = FALSE, queued_hotplug_event = FALSE;
2063 static ULONG ulRegister = 0;
2064 static LPITEMIDLIST pidlDesktop = NULL;
2065 static SHChangeNotifyEntry NotifyEntry;
2066 static DWORD_PTR thread_affinity[CHECKSUM_MAX + 1];
2067 static HFONT hyperlink_font = NULL;
2068 LONG lPos;
2069 BOOL set_selected_fs;
2070 DRAWITEMSTRUCT* pDI;
2071 LPTOOLTIPTEXT lpttt;
2072 NMBCDROPDOWN* pDropDown;
2073 HDROP droppedFileInfo;
2074 HMENU hMenu;
2075 POINT Point;
2076 RECT rc, DialogRect, DesktopRect;
2077 HDC hDC;
2078 PAINTSTRUCT ps;
2079 int nDeviceIndex, i, nWidth, nHeight, nb_devices, selected_language, offset, tb_state, tb_flags;
2080 char tmp[128];
2081 wchar_t* wbuffer = NULL;
2082 loc_cmd* lcmd = NULL;
2083 wchar_t wtooltip[128];
2084
2085 switch (message) {
2086
2087 case WM_COMMAND:
2088 #ifdef RUFUS_TEST
2089 if (LOWORD(wParam) == IDC_TEST) {
2090 DWORD DriveIndex = (DWORD)ComboBox_GetItemData(hDeviceList, ComboBox_GetCurSel(hDeviceList));
2091 uprintf("label = '%s'", GetExtFsLabel(DriveIndex, 1));
2092 break;
2093 }
2094 #endif
2095
2096 if ((LOWORD(wParam) >= UM_LANGUAGE_MENU) && (LOWORD(wParam) < UM_LANGUAGE_MENU_MAX)) {
2097 selected_language = LOWORD(wParam) - UM_LANGUAGE_MENU;
2098 i = 0;
2099 list_for_each_entry(lcmd, &locale_list, loc_cmd, list) {
2100 if (i++ == selected_language) {
2101 if (selected_locale != lcmd) {
2102 selected_locale = lcmd;
2103 selected_langid = get_language_id(lcmd);
2104 // Avoid the FS being reset on language change
2105 selected_fs = (int)ComboBox_GetCurItemData(hFileSystem);
2106 relaunch = TRUE;
2107 PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0);
2108 }
2109 break;
2110 }
2111 }
2112 }
2113 switch(LOWORD(wParam)) {
2114 case IDOK: // close application
2115 case IDCANCEL:
2116 EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
2117 if (format_thread != NULL) {
2118 if ((no_confirmation_on_cancel) || (MessageBoxExU(hMainDialog, lmprintf(MSG_105), lmprintf(MSG_049),
2119 MB_YESNO|MB_ICONWARNING|MB_IS_RTL, selected_langid) == IDYES)) {
2120 // Operation may have completed in the meantime
2121 if (format_thread != NULL) {
2122 FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED;
2123 PrintInfo(0, MSG_201);
2124 uprintf("Cancelling");
2125 // Start a timer to detect blocking operations during ISO file extraction
2126 if (iso_blocking_status >= 0) {
2127 last_iso_blocking_status = iso_blocking_status;
2128 SetTimer(hMainDialog, TID_BLOCKING_TIMER, 3000, BlockingTimer);
2129 }
2130 }
2131 } else {
2132 EnableWindow(GetDlgItem(hDlg, IDCANCEL), TRUE);
2133 }
2134 no_confirmation_on_cancel = FALSE;
2135 return (INT_PTR)TRUE;
2136 } else if (op_in_progress) {
2137 // User might be trying to cancel during preliminary checks
2138 FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED;
2139 PrintInfo(0, MSG_201);
2140 EnableWindow(GetDlgItem(hDlg, IDCANCEL), TRUE);
2141 return (INT_PTR)TRUE;
2142 }
2143 if (ulRegister != 0)
2144 SHChangeNotifyDeregister(ulRegister);
2145 PostQuitMessage(0);
2146 StrArrayDestroy(&DriveId);
2147 StrArrayDestroy(&DriveName);
2148 StrArrayDestroy(&DriveLabel);
2149 StrArrayDestroy(&DriveHub);
2150 StrArrayDestroy(&BlockingProcess);
2151 StrArrayDestroy(&ImageList);
2152 DestroyAllTooltips();
2153 DestroyWindow(hLogDialog);
2154 GetWindowRect(hDlg, &relaunch_rc);
2155 EndDialog(hDlg, 0);
2156 break;
2157 case IDC_ABOUT:
2158 CreateAboutBox();
2159 break;
2160 case IDC_LOG:
2161 // Place the log Window to the right (or left for RTL) of our dialog on first display
2162 if (first_log_display) {
2163 // Can't link to dwmapi.lib since it sideloads dwapi.dll *before* we get a chance
2164 // to prevent local directory lookup (Sideloading mitigation).
2165 PF_TYPE_DECL(WINAPI, HRESULT, DwmGetWindowAttribute, (HWND, DWORD, PVOID, DWORD));
2166 GetClientRect(GetDesktopWindow(), &DesktopRect);
2167 GetWindowRect(hLogDialog, &DialogRect);
2168 nWidth = DialogRect.right - DialogRect.left;
2169 nHeight = DialogRect.bottom - DialogRect.top;
2170 GetWindowRect(hDlg, &DialogRect);
2171 offset = GetSystemMetrics(SM_CXBORDER);
2172 if (nWindowsVersion >= WINDOWS_10) {
2173 PF_INIT(DwmGetWindowAttribute, Dwmapi);
2174 // See https://stackoverflow.com/a/42491227/1069307
2175 // I agree with Stephen Hazel: Whoever at Microsoft thought it would be a great idea to
2176 // add a *FRIGGING INVISIBLE BORDER* in Windows 10 should face the harshest punishment!
2177 if (pfDwmGetWindowAttribute != NULL) {
2178 pfDwmGetWindowAttribute(hDlg, DWMWA_EXTENDED_FRAME_BOUNDS, &rc, sizeof(RECT));
2179 offset += 2 * (DialogRect.left - rc.left);
2180 }
2181 }
2182 if (right_to_left_mode)
2183 Point.x = max(DialogRect.left - offset - nWidth, 0);
2184 else
2185 Point.x = min(DialogRect.right + offset, DesktopRect.right - nWidth);
2186
2187 Point.y = max(DialogRect.top, DesktopRect.top - nHeight);
2188 MoveWindow(hLogDialog, Point.x, Point.y, nWidth, nHeight, FALSE);
2189 // The log may have been recentered to fit the screen, in which case, try to shift our main dialog left (or right for RTL)
2190 nWidth = DialogRect.right - DialogRect.left;
2191 nHeight = DialogRect.bottom - DialogRect.top;
2192 if (right_to_left_mode) {
2193 Point.x = DialogRect.left;
2194 GetWindowRect(hLogDialog, &DialogRect);
2195 Point.x = max(Point.x, DialogRect.right - DialogRect.left + offset);
2196 } else {
2197 Point.x = max((DialogRect.left<0)?DialogRect.left:0, Point.x - offset - nWidth);
2198 }
2199 MoveWindow(hDlg, Point.x, Point.y, nWidth, nHeight, TRUE);
2200 first_log_display = FALSE;
2201 }
2202 // Display the log Window
2203 log_displayed = !log_displayed;
2204 // Set focus on the start button
2205 SendMessage(hMainDialog, WM_NEXTDLGCTL, (WPARAM)FALSE, 0);
2206 SendMessage(hMainDialog, WM_NEXTDLGCTL, (WPARAM)hStart, TRUE);
2207 // Must come last for the log window to get focus
2208 ShowWindow(hLogDialog, log_displayed?SW_SHOW:SW_HIDE);
2209 break;
2210 case IDC_ADVANCED_DRIVE_PROPERTIES:
2211 advanced_mode_device = !advanced_mode_device;
2212 WriteSettingBool(SETTING_ADVANCED_MODE_DEVICE, advanced_mode_device);
2213 ToggleAdvancedDeviceOptions(advanced_mode_device);
2214 SetBootOptions();
2215 boot_type = (int)ComboBox_GetCurItemData(hBootType);
2216 EnableControls(TRUE, FALSE);
2217 SetFileSystemAndClusterSize(NULL);
2218 SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE_INTERNAL<<16) | IDC_FILE_SYSTEM,
2219 ComboBox_GetCurSel(hFileSystem));
2220 break;
2221 case IDC_ADVANCED_FORMAT_OPTIONS:
2222 advanced_mode_format = !advanced_mode_format;
2223 WriteSettingBool(SETTING_ADVANCED_MODE_FORMAT, advanced_mode_format);
2224 ToggleAdvancedFormatOptions(advanced_mode_format);
2225 if (selected_fs == FS_UNKNOWN)
2226 selected_fs = (int)ComboBox_GetCurItemData(hFileSystem);
2227 SetFileSystemAndClusterSize(NULL);
2228 SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE_INTERNAL << 16) | IDC_FILE_SYSTEM,
2229 ComboBox_GetCurSel(hFileSystem));
2230 break;
2231 case IDC_LABEL:
2232 if (HIWORD(wParam) == EN_CHANGE) {
2233 // We will get EN_CHANGE when we change the label automatically, so we need to detect that
2234 if (!app_changed_label)
2235 user_changed_label = TRUE;
2236 app_changed_label = FALSE;
2237 }
2238 break;
2239 case IDC_DEVICE:
2240 if (HIWORD(wParam) != CBN_SELCHANGE)
2241 break;
2242 nb_devices = ComboBox_GetCount(hDeviceList);
2243 PrintStatusDebug(0, (nb_devices==1)?MSG_208:MSG_209, nb_devices);
2244 PopulateProperties();
2245 nDeviceIndex = ComboBox_GetCurSel(hDeviceList);
2246 DeviceNum = (nDeviceIndex == CB_ERR) ? 0 : (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex);
2247 SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE_INTERNAL << 16) | IDC_FILE_SYSTEM,
2248 ComboBox_GetCurSel(hFileSystem));
2249 break;
2250 case IDC_IMAGE_OPTION:
2251 if (HIWORD(wParam) != CBN_SELCHANGE)
2252 break;
2253 SetFileSystemAndClusterSize(NULL);
2254 windows_to_go_selected = (BOOL)ComboBox_GetCurItemData(hImageOption);
2255 break;
2256 case IDC_PERSISTENCE_SIZE:
2257 if (HIWORD(wParam) == EN_CHANGE) {
2258 uint64_t pos;
2259 // We get EN_CHANGE when we change the size automatically, so we need to detect that
2260 if (app_changed_size) {
2261 app_changed_size = FALSE;
2262 break;
2263 }
2264 GetWindowTextA(GetDlgItem(hDlg, IDC_PERSISTENCE_SIZE), tmp, sizeof(tmp));
2265 lPos = atol(tmp);
2266 persistence_unit_selection = ComboBox_GetCurSel(GetDlgItem(hDlg, IDC_PERSISTENCE_UNITS));
2267 persistence_size = lPos * MB;
2268 for (i = 0; i < persistence_unit_selection; i++)
2269 persistence_size *= 1024;
2270 if (persistence_size > SelectedDrive.DiskSize - img_report.projected_size)
2271 persistence_size = SelectedDrive.DiskSize - img_report.projected_size;
2272 pos = persistence_size / MB;
2273 for (i = 0; i < persistence_unit_selection; i++)
2274 pos /= 1024;
2275 lPos = (LONG)pos;
2276 SendMessage(GetDlgItem(hMainDialog, IDC_PERSISTENCE_SLIDER), TBM_SETPOS, TRUE, lPos);
2277 if (persistence_size >= (SelectedDrive.DiskSize - img_report.projected_size)) {
2278 static_sprintf(tmp, "%ld", lPos);
2279 app_changed_size = TRUE;
2280 SetWindowTextU(GetDlgItem(hMainDialog, IDC_PERSISTENCE_SIZE), tmp);
2281 }
2282 } else if (HIWORD(wParam) == EN_KILLFOCUS) {
2283 if (persistence_size == 0) {
2284 TogglePersistenceControls(FALSE);
2285 static_sprintf(tmp, "0 (%s)", lmprintf(MSG_124));
2286 app_changed_size = TRUE;
2287 SetWindowTextU(GetDlgItem(hMainDialog, IDC_PERSISTENCE_SIZE), tmp);
2288 } else if (persistence_size < MIN_EXT_SIZE) {
2289 persistence_size = MIN_EXT_SIZE;
2290 uint64_t pos = persistence_size / MB;
2291 for (i = 0; i < persistence_unit_selection; i++)
2292 pos /= 1024;
2293 lPos = (LONG)pos;
2294 SendMessage(GetDlgItem(hMainDialog, IDC_PERSISTENCE_SLIDER), TBM_SETPOS, TRUE, lPos);
2295 static_sprintf(tmp, "%ld", lPos);
2296 app_changed_size = TRUE;
2297 SetWindowTextU(GetDlgItem(hMainDialog, IDC_PERSISTENCE_SIZE), tmp);
2298 }
2299 }
2300 break;
2301 case IDC_PERSISTENCE_UNITS:
2302 if (HIWORD(wParam) != CBN_SELCHANGE)
2303 break;
2304 if (ComboBox_GetCurSel(GetDlgItem(hDlg, IDC_PERSISTENCE_UNITS)) == persistence_unit_selection)
2305 break;
2306 GetWindowTextA(GetDlgItem(hMainDialog, IDC_PERSISTENCE_SIZE), tmp, sizeof(tmp));
2307 persistence_size = atol(tmp) * MB;
2308 for (i = 0; i < persistence_unit_selection; i++)
2309 persistence_size *= 1024;
2310 persistence_unit_selection = ComboBox_GetCurSel(GetDlgItem(hDlg, IDC_PERSISTENCE_UNITS));
2311 SetPersistenceSize();
2312 break;
2313 case IDC_NB_PASSES:
2314 if (HIWORD(wParam) != CBN_SELCHANGE)
2315 break;
2316 SetPassesTooltip();
2317 break;
2318 case IDC_TARGET_SYSTEM:
2319 if (HIWORD(wParam) != CBN_SELCHANGE)
2320 break;
2321 target_type = (int)ComboBox_GetCurItemData(hTargetSystem);
2322 SendMessage(hMainDialog, UM_UPDATE_CSM_TOOLTIP, 0, 0);
2323 SetFileSystemAndClusterSize(NULL);
2324 break;
2325 case IDC_PARTITION_TYPE:
2326 if (HIWORD(wParam) != CBN_SELCHANGE)
2327 break;
2328 partition_type = (int)ComboBox_GetCurItemData(hPartitionScheme);
2329 SetPartitionSchemeAndTargetSystem(TRUE);
2330 SetFileSystemAndClusterSize(NULL);
2331 EnableMBRBootOptions(TRUE, TRUE);
2332 selected_pt = partition_type;
2333 break;
2334 case IDC_FILE_SYSTEM:
2335 if ((HIWORD(wParam) != CBN_SELCHANGE) && (HIWORD(wParam) != CBN_SELCHANGE_INTERNAL))
2336 break;
2337 set_selected_fs = (HIWORD(wParam) == CBN_SELCHANGE);
2338 fs_type = (int)ComboBox_GetCurItemData(hFileSystem);
2339 SetClusterSizes(fs_type);
2340 if (set_selected_fs && (fs_type > 0))
2341 selected_fs = fs_type;
2342 // Some FS's (such as ReFS or Large FAT32) only have QuickFormat so make sure we reflect that
2343 EnableQuickFormat(TRUE, TRUE);
2344 EnableMBRBootOptions(TRUE, TRUE);
2345 SetMBRProps();
2346 EnableExtendedLabel(TRUE, TRUE);
2347 break;
2348 case IDC_BOOT_SELECTION:
2349 if (HIWORD(wParam) != CBN_SELCHANGE)
2350 break;
2351 boot_type = (int)ComboBox_GetCurItemData(hBootType);
2352 if ((HIWORD(wParam) != CBN_SELCHANGE) || (boot_type == selection_default))
2353 break;
2354 selection_default = boot_type;
2355 SetPartitionSchemeAndTargetSystem(FALSE);
2356 // Try to reselect current FS from the drive for non-bootable
2357 tmp[0] = 0;
2358 if ((selected_fs == FS_UNKNOWN) && (SelectedDrive.DeviceNumber != 0))
2359 GetDrivePartitionData(SelectedDrive.DeviceNumber, tmp, sizeof(tmp), !usb_debug);
2360 SetFileSystemAndClusterSize(tmp);
2361 ToggleImageOptions();
2362 SetProposedLabel(ComboBox_GetCurSel(hDeviceList));
2363 EnableControls(TRUE, TRUE);
2364 target_type = (int)ComboBox_GetCurItemData(hPartitionScheme);
2365 partition_type = (int)ComboBox_GetCurItemData(hTargetSystem);
2366 return (INT_PTR)TRUE;
2367 case IDC_SELECT:
2368 // Ctrl-SELECT is used to select an additional archive of files to extract
2369 // For now only zip archives are supported.
2370 if (GetKeyState(VK_CONTROL) & 0x8000) {
2371 EXT_DECL(arch_ext, NULL, __VA_GROUP__("*.zip"), __VA_GROUP__(lmprintf(MSG_309)));
2372 if (image_path == NULL)
2373 break;
2374 archive_path = FileDialog(FALSE, NULL, &arch_ext, 0);
2375 if (archive_path != NULL) {
2376 struct __stat64 stat64 = { 0 };
2377 _stat64U(archive_path, &stat64);
2378 img_report.projected_size -= img_report.archive_size;
2379 img_report.archive_size = stat64.st_size;
2380 img_report.projected_size += img_report.archive_size;
2381 uprintf("Using archive: %s (%s)", _filenameU(archive_path),
2382 SizeToHumanReadable(img_report.archive_size, FALSE, FALSE));
2383 }
2384 break;
2385 }
2386 if (select_index == 1) {
2387 EnableControls(FALSE, FALSE);
2388 DownloadISO();
2389 } else {
2390 if (img_provided) {
2391 uprintf("\r\nImage provided: '%s'", image_path);
2392 img_provided = FALSE; // One off thing...
2393 } else {
2394 char* old_image_path = image_path;
2395 // If declared globaly, lmprintf(MSG_036) would be called on each message...
2396 EXT_DECL(img_ext, NULL, __VA_GROUP__("*.iso;*.img;*.vhd;*.usb;*.bz2;*.bzip2;*.gz;*.lzma;*.xz;*.Z;*.zip;*.wim;*.esd"),
2397 __VA_GROUP__(lmprintf(MSG_036)));
2398 image_path = FileDialog(FALSE, NULL, &img_ext, 0);
2399 if (image_path == NULL) {
2400 if (old_image_path != NULL) {
2401 // Reselect previous image
2402 image_path = old_image_path;
2403 } else {
2404 CreateTooltip(hSelectImage, lmprintf(MSG_173), -1);
2405 PrintStatus(0, MSG_086);
2406 }
2407 break;
2408 } else {
2409 safe_free(archive_path);
2410 free(old_image_path);
2411 }
2412 }
2413 FormatStatus = 0;
2414 if (CreateThread(NULL, 0, ImageScanThread, NULL, 0, NULL) == NULL) {
2415 uprintf("Unable to start ISO scanning thread");
2416 FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_START_THREAD);
2417 }
2418 }
2419 break;
2420 case IDC_RUFUS_MBR:
2421 if ((HIWORD(wParam)) == BN_CLICKED)
2422 mbr_selected_by_user = IsChecked(IDC_RUFUS_MBR);
2423 break;
2424 case IDC_LIST_USB_HDD:
2425 if ((HIWORD(wParam)) == BN_CLICKED) {
2426 enable_HDDs = !enable_HDDs;
2427 PrintStatusTimeout(lmprintf(MSG_253), enable_HDDs);
2428 GetDevices(0);
2429 }
2430 break;
2431 case IDC_START:
2432 if (format_thread != NULL)
2433 return (INT_PTR)TRUE;
2434 // Just in case
2435 boot_type = (int)ComboBox_GetCurItemData(hBootType);
2436 partition_type = (int)ComboBox_GetCurItemData(hPartitionScheme);
2437 target_type = (int)ComboBox_GetCurItemData(hTargetSystem);
2438 fs_type = (int)ComboBox_GetCurItemData(hFileSystem);
2439 write_as_image = FALSE;
2440 write_as_esp = FALSE;
2441 installed_uefi_ntfs = FALSE;
2442 // Disable all controls except Cancel
2443 EnableControls(FALSE, FALSE);
2444 FormatStatus = 0;
2445 LastWriteError = 0;
2446 StrArrayClear(&BlockingProcess);
2447 no_confirmation_on_cancel = FALSE;
2448 SendMessage(hMainDialog, UM_PROGRESS_INIT, 0, 0);
2449 selection_default = (int)ComboBox_GetCurItemData(hBootType);
2450 // Create a thread to validate options and download files as needed (so that we can update the UI).
2451 // On exit, this thread sends message UM_FORMAT_START back to this dialog.
2452 if (CreateThread(NULL, 0, BootCheckThread, NULL, 0, NULL) == NULL) {
2453 uprintf("Unable to start boot check thread");
2454 FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_START_THREAD);
2455 PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
2456 }
2457 break;
2458 case IDC_LANG:
2459 // Show the language menu such that it doesn't overlap the button
2460 SendMessage(hMultiToolbar, TB_GETRECT, (WPARAM)IDC_ABOUT, (LPARAM)&rc);
2461 MapWindowPoints(hDlg, NULL, (POINT*)&rc, 2);
2462 rc.left += cbw / 2;
2463 ShowLanguageMenu(rc);
2464 break;
2465 case IDC_SETTINGS:
2466 MyDialogBox(hMainInstance, IDD_UPDATE_POLICY, hDlg, UpdateCallback);
2467 break;
2468 case IDC_HASH:
2469 if ((format_thread == NULL) && (image_path != NULL)) {
2470 FormatStatus = 0;
2471 no_confirmation_on_cancel = TRUE;
2472 SendMessage(hMainDialog, UM_PROGRESS_INIT, 0, 0);
2473 // Disable all controls except cancel
2474 EnableControls(FALSE, FALSE);
2475 InitProgress(FALSE);
2476 SetThreadAffinity(thread_affinity, CHECKSUM_MAX + 1);
2477 format_thread = CreateThread(NULL, 0, SumThread, (LPVOID)thread_affinity, 0, NULL);
2478 if (format_thread != NULL) {
2479 SetThreadPriority(format_thread, default_thread_priority);
2480 PrintInfo(0, -1);
2481 SendMessage(hMainDialog, UM_TIMER_START, 0, 0);
2482 } else {
2483 uprintf("Unable to start checksum thread");
2484 FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_START_THREAD);
2485 PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
2486 }
2487 }
2488 break;
2489 case IDC_SAVE:
2490 SaveVHD();
2491 break;
2492 case IDM_SELECT:
2493 case IDM_DOWNLOAD:
2494 select_index = LOWORD(wParam) - IDM_SELECT;
2495 SetWindowTextU(GetDlgItem(hDlg, IDC_SELECT), uppercase_select[select_index]);
2496 break;
2497 default:
2498 return (INT_PTR)FALSE;
2499 }
2500 return (INT_PTR)TRUE;
2501
2502 case UM_UPDATE_CSM_TOOLTIP:
2503 ShowWindow(GetDlgItem(hMainDialog, IDS_CSM_HELP_TXT), ((target_type == TT_UEFI) || has_uefi_csm) ? SW_SHOW : SW_HIDE);
2504 CreateTooltip(GetDlgItem(hMainDialog, IDS_CSM_HELP_TXT), lmprintf((target_type == TT_UEFI) ? MSG_152 : MSG_151), 30000);
2505 break;
2506 case UM_ENABLE_CONTROLS:
2507 KillTimer(hMainDialog, TID_APP_TIMER);
2508 if (!IS_ERROR(FormatStatus))
2509 PrintInfo(0, MSG_210);
2510 else switch (SCODE_CODE(FormatStatus)) {
2511 case ERROR_CANCELLED:
2512 PrintInfo(0, MSG_211);
2513 break;
2514 case ERROR_BAD_SIGNATURE:
2515 PrintInfo(0, MSG_283);
2516 break;
2517 default:
2518 PrintInfo(0, MSG_212);
2519 break;
2520 }
2521 EnableControls(TRUE, FALSE);
2522 break;
2523 case UM_TIMER_START:
2524 PrintInfo(0, -1);
2525 timer = 0;
2526 static_sprintf(szTimer, "00:00:00");
2527 SendMessageA(hStatus, SB_SETTEXTA, SBT_OWNERDRAW | SB_SECTION_RIGHT, (LPARAM)szTimer);
2528 SetTimer(hMainDialog, TID_APP_TIMER, 1000, ClockTimer);
2529 break;
2530 case UM_SELECT_ISO:
2531 select_index = 0;
2532 img_provided = TRUE;
2533 SetWindowTextU(GetDlgItem(hDlg, IDC_SELECT), uppercase_select[0]);
2534 SendMessage(hDlg, WM_COMMAND, IDC_SELECT, 0);
2535 break;
2536 case UM_MEDIA_CHANGE:
2537 wParam = DBT_CUSTOMEVENT;
2538 // Fall through
2539 case WM_DEVICECHANGE:
2540 // The Windows hotplug subsystem sucks. Among other things, if you insert a GPT partitioned
2541 // USB drive with zero partitions, the only device messages you will get are a stream of
2542 // DBT_DEVNODES_CHANGED and that's it. But those messages are also issued when you get a
2543 // DBT_DEVICEARRIVAL and DBT_DEVICEREMOVECOMPLETE, and there's a whole slew of them so we
2544 // can't really issue a refresh for each one we receive
2545 // What we do then is arm a timer on DBT_DEVNODES_CHANGED, if it's been more than 1 second
2546 // since last refresh/arm timer, and have that timer send DBT_CUSTOMEVENT when it expires.
2547 // DO *NOT* USE WM_DEVICECHANGE AS THE MESSAGE FROM THE TIMER PROC, as it may be filtered!
2548 // For instance filtering will occur when (un)plugging in a FreeBSD UFD on Windows 8.
2549 // Instead, use a custom user message, such as UM_MEDIA_CHANGE, to set DBT_CUSTOMEVENT.
2550 if (format_thread == NULL) {
2551 switch (wParam) {
2552 case DBT_DEVICEARRIVAL:
2553 case DBT_DEVICEREMOVECOMPLETE:
2554 case DBT_CUSTOMEVENT: // Sent by our timer refresh function or for card reader media change
2555 LastRefresh = GetTickCount64();
2556 KillTimer(hMainDialog, TID_REFRESH_TIMER);
2557 if (!op_in_progress) {
2558 queued_hotplug_event = FALSE;
2559 GetDevices((DWORD)ComboBox_GetCurItemData(hDeviceList));
2560 user_changed_label = FALSE;
2561 EnableControls(TRUE, FALSE);
2562 if (ComboBox_GetCurSel(hDeviceList) < 0) {
2563 SetPartitionSchemeAndTargetSystem(FALSE);
2564 SetFileSystemAndClusterSize(NULL);
2565 ShowWindow(GetDlgItem(hDlg, IDS_CSM_HELP_TXT), SW_HIDE);
2566 persistence_unit_selection = -1;
2567 }
2568 } else {
2569 queued_hotplug_event = TRUE;
2570 }
2571 return (INT_PTR)TRUE;
2572 case DBT_DEVNODES_CHANGED:
2573 // If it's been more than a second since last device refresh, arm a refresh timer
2574 if (GetTickCount64() > LastRefresh + 1000) {
2575 LastRefresh = GetTickCount64();
2576 SetTimer(hMainDialog, TID_REFRESH_TIMER, 1000, RefreshTimer);
2577 }
2578 break;
2579 default:
2580 break;
2581 }
2582 }
2583 break;
2584
2585 case WM_INITDIALOG:
2586 // Make sure fScale is set before the first call to apply localization, so that move/resize scale appropriately
2587 hDC = GetDC(hDlg);
2588 fScale = GetDeviceCaps(hDC, LOGPIXELSX) / 96.0f;
2589 safe_release_dc(hDlg, hDC);
2590 apply_localization(IDD_DIALOG, hDlg);
2591 SetUpdateCheck();
2592 first_log_display = TRUE;
2593 log_displayed = FALSE;
2594 hLogDialog = MyCreateDialog(hMainInstance, IDD_LOG, hDlg, (DLGPROC)LogCallback);
2595 InitDialog(hDlg);
2596 GetDevices(0);
2597 EnableControls(TRUE, FALSE);
2598 CheckForUpdates(FALSE);
2599 // Register MEDIA_INSERTED/MEDIA_REMOVED notifications for card readers
2600 if (SUCCEEDED(SHGetSpecialFolderLocation(0, CSIDL_DESKTOP, &pidlDesktop))) {
2601 NotifyEntry.pidl = pidlDesktop;
2602 NotifyEntry.fRecursive = TRUE;
2603 // NB: The following only works if the media is already formatted.
2604 // If you insert a blank card, notifications will not be sent... :(
2605 ulRegister = SHChangeNotifyRegister(hDlg, 0x0001 | 0x0002 | 0x8000,
2606 SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED, UM_MEDIA_CHANGE, 1, &NotifyEntry);
2607 }
2608 // Bring our Window on top. We have to go through all *THREE* of these, or Far Manager hides our window :(
2609 SetWindowPos(hMainDialog, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
2610 SetWindowPos(hMainDialog, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
2611 SetWindowPos(hMainDialog, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
2612
2613 // Set 'START' as the selected button if it's enabled, otherwise use 'SELECT', instead
2614 SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)(IsWindowEnabled(hStart) ? hStart : hSelectImage), TRUE);
2615
2616 #if defined(ALPHA)
2617 // Add a VERY ANNOYING popup for Alpha releases, so that people don't start redistributing them
2618 MessageBoxA(NULL, "This is an Alpha version of " APPLICATION_NAME " - It is meant to be used for "
2619 "testing ONLY and should NOT be distributed as a release.", "ALPHA VERSION", MSG_INFO);
2620 #elif defined(TEST)
2621 // Same thing for Test releases
2622 MessageBoxA(NULL, "This is a Test version of " APPLICATION_NAME " - It is meant to be used for "
2623 "testing ONLY and should NOT be distributed as a release.", "TEST VERSION", MSG_INFO);
2624 #endif
2625 // Let's not take any risk: Ask Windows to redraw the whole dialog before we exit init
2626 RedrawWindow(hMainDialog, NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW);
2627 InvalidateRect(hMainDialog, NULL, TRUE);
2628
2629 return (INT_PTR)FALSE;
2630
2631 case WM_DRAWITEM:
2632 // The things one must do to get an ellipsis and text alignment on the status bar...
2633 if (wParam == IDC_STATUS) {
2634 pDI = (DRAWITEMSTRUCT*)lParam;
2635 if (nWindowsVersion >= WINDOWS_10)
2636 pDI->rcItem.top += (int)(1.0f * fScale);
2637 else if (fScale >= 1.49f)
2638 pDI->rcItem.top -= (int)(1.5f * fScale);
2639 pDI->rcItem.left += (int)(4.0f * fScale);
2640 SetBkMode(pDI->hDC, TRANSPARENT);
2641 switch (pDI->itemID) {
2642 case SB_SECTION_LEFT:
2643 SetTextColor(pDI->hDC, GetSysColor(COLOR_BTNTEXT));
2644 DrawTextExU(pDI->hDC, szStatusMessage, -1, &pDI->rcItem,
2645 DT_LEFT | DT_END_ELLIPSIS | DT_PATH_ELLIPSIS, NULL);
2646 return (INT_PTR)TRUE;
2647 case SB_SECTION_RIGHT:
2648 SetTextColor(pDI->hDC, GetSysColor(COLOR_3DSHADOW));
2649 DrawTextExA(pDI->hDC, szTimer, -1, &pDI->rcItem, DT_LEFT, NULL);
2650 return (INT_PTR)TRUE;
2651 }
2652 }
2653 break;
2654
2655 case WM_PAINT:
2656 hDC = BeginPaint(hDlg, &ps);
2657 OnPaint(hDC);
2658 EndPaint(hDlg, &ps);
2659 break;
2660
2661 case WM_CTLCOLORSTATIC:
2662 if ((HWND)lParam != GetDlgItem(hDlg, IDS_CSM_HELP_TXT))
2663 return FALSE;
2664 SetBkMode((HDC)wParam, TRANSPARENT);
2665 CreateStaticFont((HDC)wParam, &hyperlink_font, FALSE);
2666 SelectObject((HDC)wParam, hyperlink_font);
2667 SetTextColor((HDC)wParam, TOOLBAR_ICON_COLOR);
2668 return (INT_PTR)CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
2669
2670 case WM_NOTIFY:
2671 switch (((LPNMHDR)lParam)->code) {
2672 case TTN_GETDISPINFO:
2673 lpttt = (LPTOOLTIPTEXT)lParam;
2674 switch (lpttt->hdr.idFrom) {
2675 case IDC_ABOUT:
2676 utf8_to_wchar_no_alloc(lmprintf(MSG_302), wtooltip, ARRAYSIZE(wtooltip));
2677 lpttt->lpszText = wtooltip;
2678 break;
2679 case IDC_SETTINGS:
2680 utf8_to_wchar_no_alloc(lmprintf(MSG_301), wtooltip, ARRAYSIZE(wtooltip));
2681 lpttt->lpszText = wtooltip;
2682 break;
2683 case IDC_LANG:
2684 utf8_to_wchar_no_alloc(lmprintf(MSG_273), wtooltip, ARRAYSIZE(wtooltip));
2685 lpttt->lpszText = wtooltip;
2686 break;
2687 case IDC_LOG:
2688 utf8_to_wchar_no_alloc(lmprintf(MSG_303), wtooltip, ARRAYSIZE(wtooltip));
2689 lpttt->lpszText = wtooltip;
2690 break;
2691 case IDC_SAVE:
2692 utf8_to_wchar_no_alloc(lmprintf(MSG_304), wtooltip, ARRAYSIZE(wtooltip));
2693 lpttt->lpszText = wtooltip;
2694 break;
2695 case IDC_HASH:
2696 utf8_to_wchar_no_alloc(lmprintf(MSG_272), wtooltip, ARRAYSIZE(wtooltip));
2697 lpttt->lpszText = wtooltip;
2698 break;
2699 }
2700 break;
2701 case BCN_DROPDOWN:
2702 pDropDown = (LPNMBCDROPDOWN)lParam;
2703 Point.x = pDropDown->rcButton.left;
2704 Point.y = pDropDown->rcButton.bottom;
2705 ClientToScreen(pDropDown->hdr.hwndFrom, &Point);
2706 hMenu = CreatePopupMenu();
2707 InsertMenuU(hMenu, -1, MF_BYPOSITION | ((select_index == 0) ? MF_CHECKED : 0), IDM_SELECT, uppercase_select[0]);
2708 InsertMenuU(hMenu, -1, MF_BYPOSITION | ((select_index == 1) ? MF_CHECKED : 0), IDM_DOWNLOAD, uppercase_select[1]);
2709 TrackPopupMenuEx(hMenu, TPM_LEFTALIGN | TPM_TOPALIGN, Point.x, Point.y, hMainDialog, NULL);
2710 DestroyMenu(hMenu);
2711 break;
2712 }
2713 break;
2714
2715 case WM_HSCROLL:
2716 lPos = (LONG)SendMessage(GetDlgItem(hMainDialog, IDC_PERSISTENCE_SLIDER), TBM_GETPOS, 0, 0);
2717 SetPersistencePos(lPos);
2718 persistence_size = lPos * MB;
2719 for (i = 0; i < persistence_unit_selection; i++)
2720 persistence_size *= 1024;
2721 break;
2722
2723 case WM_DROPFILES:
2724 droppedFileInfo = (HDROP)wParam;
2725 wbuffer = calloc(MAX_PATH, sizeof(wchar_t));
2726 if (wbuffer == NULL) {
2727 uprintf("Failed to alloc buffer for drag-n-drop");
2728 break;
2729 }
2730 DragQueryFileW(droppedFileInfo, 0, wbuffer, MAX_PATH);
2731 safe_free(image_path);
2732 image_path = wchar_to_utf8(wbuffer);
2733 safe_free(wbuffer);
2734
2735 if (image_path != NULL) {
2736 img_provided = TRUE;
2737 // Simulate image selection click
2738 SendMessage(hDlg, WM_COMMAND, IDC_SELECT, 0);
2739 }
2740 break;
2741
2742 // This is >>>SUPER WEIRD<<<. After a successful ISO or DD write (e.g. Arch 2016.01)
2743 // we no longer receive WM_QUERYENDSESSION messages, only WM_ENDSESSION.
2744 // But if we do a FreeDOS format, WM_QUERYENDSESSION is still sent to us alright.
2745 // What the heck is going on here?!?
2746 // Also, even as we try to work around this, WM_ENDSESSION comes too late in the game
2747 // to prevent shutdown block. So we need to handle the _undocumented_ WM_CLIENTSHUTDOWN.
2748 case WM_CLOSE:
2749 case WM_CLIENTSHUTDOWN:
2750 case WM_QUERYENDSESSION:
2751 case WM_ENDSESSION:
2752 if (op_in_progress) {
2753 return (INT_PTR)TRUE;
2754 }
2755 if (message == WM_CLOSE) {
2756 // We must use PostQuitMessage() on WM_CLOSE, to prevent notification sound...
2757 PostQuitMessage(0);
2758 } else {
2759 // ...but we must simulate Cancel on shutdown requests, else the app freezes.
2760 SendMessage(hDlg, WM_COMMAND, (WPARAM)IDCANCEL, (LPARAM)0);
2761 }
2762 break;
2763
2764 case UM_PROGRESS_INIT:
2765 isMarquee = (wParam == PBS_MARQUEE);
2766 SendMessage(hProgress, PBM_SETSTATE, (WPARAM)PBST_NORMAL, 0);
2767 if (isMarquee) {
2768 SendMessage(hProgress, PBM_SETMARQUEE, TRUE, 0);
2769 SetTaskbarProgressState(TASKBAR_INDETERMINATE);
2770 } else {
2771 SendMessage(hProgress, PBM_SETPOS, 0, 0);
2772 SetTaskbarProgressState(TASKBAR_NORMAL);
2773 SetTaskbarProgressValue(0, MAX_PROGRESS);
2774 }
2775 break;
2776
2777 case UM_PROGRESS_EXIT:
2778 tb_state = PBST_NORMAL;
2779 tb_flags = TASKBAR_NORMAL;
2780 if (isMarquee) {
2781 SendMessage(hProgress, PBM_SETMARQUEE, FALSE, 0);
2782 SetTaskbarProgressValue(0, MAX_PROGRESS);
2783 } else if (!IS_ERROR(FormatStatus)) {
2784 SetTaskbarProgressValue(MAX_PROGRESS, MAX_PROGRESS);
2785 } else if (SCODE_CODE(FormatStatus) == ERROR_CANCELLED) {
2786 tb_state = PBST_PAUSED;
2787 tb_flags = TASKBAR_PAUSED;
2788 } else {
2789 tb_state = PBST_ERROR;
2790 tb_flags = TASKBAR_ERROR;
2791 MessageBeep(MB_ICONERROR);
2792 FlashTaskbar(dialog_handle);
2793 }
2794 SendMessage(hProgress, PBM_SETSTATE, (WPARAM)tb_state, 0);
2795 SetTaskbarProgressState(tb_flags);
2796 break;
2797
2798 case UM_NO_UPDATE:
2799 Notification(MSG_INFO, NULL, NULL, lmprintf(MSG_243), lmprintf(MSG_247));
2800 // Need to manually set focus back to "Check Now" for tabbing to work
2801 SendMessage(hUpdatesDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hUpdatesDlg, IDC_CHECK_NOW), TRUE);
2802 break;
2803
2804 case UM_FORMAT_START:
2805 if (wParam != BOOTCHECK_PROCEED)
2806 goto aborted_start;
2807 // All subsequent aborts below translate to a user cancellation
2808 wParam = BOOTCHECK_CANCEL;
2809
2810 if ((partition_type == PARTITION_STYLE_MBR) && (SelectedDrive.DiskSize > 2 * TB)) {
2811 if (MessageBoxExU(hMainDialog, lmprintf(MSG_134, SizeToHumanReadable(SelectedDrive.DiskSize - 2 * TB, FALSE, FALSE)),
2812 lmprintf(MSG_128, "MBR"), MB_YESNO | MB_ICONWARNING | MB_IS_RTL, selected_langid) != IDYES)
2813 goto aborted_start;
2814 }
2815
2816 if (!zero_drive) {
2817 // Display a warning about UDF formatting times
2818 if (fs_type == FS_UDF) {
2819 dur_secs = (uint32_t)(((double)SelectedDrive.DiskSize) / 1073741824.0f / UDF_FORMAT_SPEED);
2820 if (dur_secs > UDF_FORMAT_WARN) {
2821 dur_mins = dur_secs / 60;
2822 dur_secs -= dur_mins * 60;
2823 MessageBoxExU(hMainDialog, lmprintf(MSG_112, dur_mins, dur_secs), lmprintf(MSG_113),
2824 MB_OK | MB_ICONASTERISK | MB_IS_RTL, selected_langid);
2825 } else {
2826 dur_secs = 0;
2827 dur_mins = 0;
2828 }
2829 }
2830
2831 if ((boot_type == BT_IMAGE) && IS_DD_BOOTABLE(img_report)) {
2832 if (img_report.is_iso) {
2833 // Ask users how they want to write ISOHybrid images,
2834 // but only do so if persistence has not been selected.
2835 if (persistence_size == 0) {
2836 char* iso_image = lmprintf(MSG_036);
2837 char* dd_image = lmprintf(MSG_095);
2838 // If the ISO is small enough to be written as an ESP and we are using GPT add the ISO → ESP option
2839 if ((img_report.projected_size < MAX_ISO_TO_ESP_SIZE * MB) && HAS_REGULAR_EFI(img_report) &&
2840 (partition_type == PARTITION_STYLE_GPT) && IS_FAT(fs_type)) {
2841 char* choices[3] = { lmprintf(MSG_276, iso_image), lmprintf(MSG_277, "ISO → ESP"), lmprintf(MSG_277, dd_image) };
2842 i = SelectionDialog(lmprintf(MSG_274), lmprintf(MSG_275, iso_image, dd_image, iso_image, dd_image),
2843 choices, 3);
2844 if (i < 0) // Cancel
2845 goto aborted_start;
2846 else if (i == 2)
2847 write_as_esp = TRUE;
2848 else if (i == 3)
2849 write_as_image = TRUE;
2850 } else {
2851 char* choices[2] = { lmprintf(MSG_276, iso_image), lmprintf(MSG_277, dd_image) };
2852 i = SelectionDialog(lmprintf(MSG_274), lmprintf(MSG_275, iso_image, dd_image, iso_image, dd_image),
2853 choices, 2);
2854 if (i < 0) // Cancel
2855 goto aborted_start;
2856 else if (i == 2)
2857 write_as_image = TRUE;
2858 }
2859 }
2860 } else {
2861 write_as_image = TRUE;
2862 }
2863 } else if ((img_report.projected_size < MAX_ISO_TO_ESP_SIZE * MB) && HAS_REGULAR_EFI(img_report) &&
2864 (partition_type == PARTITION_STYLE_GPT) && IS_FAT(fs_type)) {
2865 // The ISO is small enough to be written as an ESP and we are using GPT
2866 // so ask the users if they want to write it as an ESP.
2867 char* iso_image = lmprintf(MSG_036);
2868 char* choices[2] = { lmprintf(MSG_276, iso_image), lmprintf(MSG_277, "ISO → ESP") };
2869 i = SelectionDialog(lmprintf(MSG_274), lmprintf(MSG_310), choices, 2);
2870 if (i < 0) // Cancel
2871 goto aborted_start;
2872 else if (i == 2)
2873 write_as_esp = TRUE;
2874 }
2875 }
2876
2877 if (!CheckDriveAccess(SEARCH_PROCESS_TIMEOUT, TRUE))
2878 goto aborted_start;
2879
2880 GetWindowTextU(hDeviceList, tmp, ARRAYSIZE(tmp));
2881 if (MessageBoxExU(hMainDialog, lmprintf(MSG_003, tmp),
2882 APPLICATION_NAME, MB_OKCANCEL | MB_ICONWARNING | MB_IS_RTL, selected_langid) == IDCANCEL)
2883 goto aborted_start;
2884 if ((SelectedDrive.nPartitions > 1) && (MessageBoxExU(hMainDialog, lmprintf(MSG_093),
2885 lmprintf(MSG_094), MB_OKCANCEL | MB_ICONWARNING | MB_IS_RTL, selected_langid) == IDCANCEL))
2886 goto aborted_start;
2887 if ((!zero_drive) && (boot_type != BT_NON_BOOTABLE) && (SelectedDrive.SectorSize != 512) &&
2888 (MessageBoxExU(hMainDialog, lmprintf(MSG_196, SelectedDrive.SectorSize),
2889 lmprintf(MSG_197), MB_OKCANCEL | MB_ICONWARNING | MB_IS_RTL, selected_langid) == IDCANCEL))
2890 goto aborted_start;
2891
2892 nDeviceIndex = ComboBox_GetCurSel(hDeviceList);
2893 DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex);
2894 InitProgress(zero_drive || write_as_image);
2895 format_thread = CreateThread(NULL, 0, FormatThread, (LPVOID)(uintptr_t)DeviceNum, 0, NULL);
2896 if (format_thread == NULL) {
2897 uprintf("Unable to start formatting thread");
2898 FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_START_THREAD);
2899 PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
2900 } else {
2901 SetThreadPriority(format_thread, default_thread_priority);
2902 uprintf("\r\nFormat operation started");
2903 SendMessage(hMainDialog, UM_TIMER_START, 0, 0);
2904 // Set focus to the Cancel button
2905 SendMessage(hMainDialog, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hMainDialog, IDCANCEL), TRUE);
2906 }
2907 if (format_thread != NULL)
2908 break;
2909 aborted_start:
2910 zero_drive = FALSE;
2911 if (queued_hotplug_event)
2912 SendMessage(hDlg, UM_MEDIA_CHANGE, 0, 0);
2913 if (wParam == BOOTCHECK_CANCEL) {
2914 EnableControls(TRUE, FALSE);
2915 break;
2916 }
2917 FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) |
2918 ((wParam == BOOTCHECK_DOWNLOAD_ERROR) ? APPERR(ERROR_CANT_DOWNLOAD) : ERROR_GEN_FAILURE);
2919 // Fall through
2920
2921 case UM_FORMAT_COMPLETED:
2922 zero_drive = FALSE;
2923 format_thread = NULL;
2924 // Stop the timer
2925 KillTimer(hMainDialog, TID_APP_TIMER);
2926 // Close the cancel MessageBox and Blocking notification if active
2927 SendMessage(FindWindowA(MAKEINTRESOURCEA(32770), lmprintf(MSG_049)), WM_COMMAND, IDNO, 0);
2928 SendMessage(FindWindowA(MAKEINTRESOURCEA(32770), lmprintf(MSG_049)), WM_COMMAND, IDYES, 0);
2929 EnableWindow(GetDlgItem(hMainDialog, IDCANCEL), TRUE);
2930 EnableControls(TRUE, FALSE);
2931 if (wParam) {
2932 uprintf("\r\n");
2933 GetDevices(DeviceNum);
2934 }
2935 if (!IS_ERROR(FormatStatus)) {
2936 SendMessage(hProgress, PBM_SETPOS, MAX_PROGRESS, 0);
2937 SetTaskbarProgressState(TASKBAR_NOPROGRESS);
2938 PrintInfo(0, MSG_210);
2939 MessageBeep(MB_OK);
2940 FlashTaskbar(dialog_handle);
2941 if (installed_uefi_ntfs && (!ReadSettingBool(SETTING_DISABLE_SECURE_BOOT_NOTICE))) {
2942 notification_info more_info;
2943 more_info.id = MORE_INFO_URL;
2944 more_info.url = SECURE_BOOT_MORE_INFO_URL;
2945 Notification(MSG_INFO, SETTING_DISABLE_SECURE_BOOT_NOTICE, &more_info, lmprintf(MSG_128, "Secure Boot"), lmprintf(MSG_129));
2946 }
2947 } else if (SCODE_CODE(FormatStatus) == ERROR_CANCELLED) {
2948 SendMessage(hProgress, PBM_SETSTATE, (WPARAM)PBST_PAUSED, 0);
2949 SetTaskbarProgressState(TASKBAR_PAUSED);
2950 PrintInfo(0, MSG_211);
2951 Notification(MSG_INFO, NULL, NULL, lmprintf(MSG_211), lmprintf(MSG_041));
2952 } else {
2953 SendMessage(hProgress, PBM_SETSTATE, (WPARAM)PBST_ERROR, 0);
2954 SetTaskbarProgressState(TASKBAR_ERROR);
2955 PrintInfo(0, MSG_212);
2956 MessageBeep(MB_ICONERROR);
2957 FlashTaskbar(dialog_handle);
2958 if (BlockingProcess.Index > 0) {
2959 ListDialog(lmprintf(MSG_042), lmprintf(MSG_055), BlockingProcess.String, BlockingProcess.Index);
2960 } else {
2961 if (nWindowsVersion >= WINDOWS_10) {
2962 // Try to detect if 'Controlled Folder Access' is enabled on Windows 10 or later. See also:
2963 // http://www.winhelponline.com/blog/use-controlled-folder-access-windows-10-windows-defender
2964 char cmdline[256];
2965 static const char* ps_cmd[2] = {
2966 // Return 1 if the 'Get-MpPreference' PowerShell cmdlet exists
2967 "If (Get-Command -Commandtype Function Get-MpPreference -ErrorAction SilentlyContinue) { Exit 1 } Else { Exit 0 }",
2968 // Return 1 if Controlled Folder Access is enabled
2969 "Exit (Get-MpPreference).EnableControlledFolderAccess" };
2970 switch (SCODE_CODE(FormatStatus)) {
2971 case ERROR_PARTITION_FAILURE:
2972 case ERROR_WRITE_FAULT:
2973 // Find if PowerShell is available at its expected location
2974 static_sprintf(tmp, "%s\\WindowsPowerShell\\v1.0\\powershell.exe", system_dir);
2975 if (PathFileExistsU(tmp)) {
2976 for (i = 0; i < ARRAYSIZE(ps_cmd); i++) {
2977 // Run the PowerShell commands
2978 static_sprintf(cmdline, "%s -NonInteractive -NoProfile -Command %s", tmp, ps_cmd[i]);
2979 if (RunCommand(cmdline, app_dir, TRUE) != 1)
2980 break;
2981 }
2982 if (i == ARRAYSIZE(ps_cmd)) {
2983 uprintf("\r\nWARNING: 'Controlled Folder Access' appears to be enabled on this system");
2984 uprintf("You may need to disable this feature, or add an exception, for Rufus to to work...\n");
2985 }
2986 }
2987 break;
2988 }
2989 }
2990 if (SCODE_CODE(FormatStatus) == ERROR_NOT_READY) {
2991 // A port cycle usually helps with a device not ready
2992 int index = ComboBox_GetCurSel(hDeviceList);
2993 if (index >= 0) {
2994 uprintf("Device not ready → Trying to cycle port...");
2995 CyclePort(index);
2996 }
2997 }
2998 Notification(MSG_ERROR, NULL, NULL, lmprintf(MSG_042), lmprintf(MSG_043, StrError(FormatStatus, FALSE)));
2999 }
3000 }
3001 FormatStatus = 0;
3002 LastWriteError = 0;
3003 return (INT_PTR)TRUE;
3004
3005 }
3006 return (INT_PTR)FALSE;
3007 }
3008
3009 static void PrintUsage(char* appname)
3010 {
3011 char fname[_MAX_FNAME];
3012
3013 _splitpath(appname, NULL, NULL, fname, NULL);
3014 printf("\nUsage: %s [-x] [-g] [-h] [-f FILESYSTEM] [-i PATH] [-l LOCALE] [-w TIMEOUT]\n", fname);
3015 printf(" -x, --extra-devs\n");
3016 printf(" List extra devices, such as USB HDDs\n");
3017 printf(" -g, --gui\n");
3018 printf(" Start in GUI mode (disable the 'rufus.com' commandline hogger)\n");
3019 printf(" -i PATH, --iso=PATH\n");
3020 printf(" Select the ISO image pointed by PATH to be used on startup\n");
3021 printf(" -l LOCALE, --locale=LOCALE\n");
3022 printf(" Select the locale to be used on startup\n");
3023 printf(" -f FILESYSTEM, --filesystem=FILESYSTEM\n");
3024 printf(" Preselect the file system to be preferred when formatting\n");
3025 printf(" -w TIMEOUT, --wait=TIMEOUT\n");
3026 printf(" Wait TIMEOUT tens of seconds for the global application mutex to be released.\n");
3027 printf(" Used when launching a newer version of " APPLICATION_NAME " from a running application.\n");
3028 printf(" -h, --help\n");
3029 printf(" This usage guide.\n");
3030 }
3031
3032 static HANDLE SetHogger(void)
3033 {
3034 INPUT* input;
3035 BYTE* hog_data;
3036 DWORD hog_size, Size;
3037 HANDLE hogmutex = NULL, hFile = NULL;
3038 int i;
3039
3040 hog_data = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_XT_HOGGER),
3041 _RT_RCDATA, cmdline_hogger, &hog_size, FALSE);
3042 if (hog_data != NULL) {
3043 // Create our synchronisation mutex
3044 hogmutex = CreateMutexA(NULL, TRUE, "Global/Rufus_CmdLine");
3045
3046 // Extract the hogger resource
3047 hFile = CreateFileA(cmdline_hogger, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ,
3048 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3049 if (hFile != INVALID_HANDLE_VALUE) {
3050 // coverity[check_return]
3051 WriteFile(hFile, hog_data, hog_size, &Size, NULL);
3052 }
3053 safe_closehandle(hFile);
3054
3055 // Now launch the file from the commandline, by simulating keypresses
3056 input = (INPUT*)calloc(strlen(cmdline_hogger)+1, sizeof(INPUT));
3057 if (input != NULL) {
3058 for (i = 0; i < (int)strlen(cmdline_hogger); i++) {
3059 input[i].type = INPUT_KEYBOARD;
3060 input[i].ki.dwFlags = KEYEVENTF_UNICODE;
3061 input[i].ki.wScan = (wchar_t)cmdline_hogger[i];
3062 }
3063 input[i].type = INPUT_KEYBOARD;
3064 input[i].ki.wVk = VK_RETURN;
3065 SendInput(i + 1, input, sizeof(INPUT));
3066 free(input);
3067 }
3068 }
3069 if (hogmutex != NULL)
3070 Sleep(200); // Need to add a delay, otherwise we may get some printout before the hogger
3071 return hogmutex;
3072 }
3073
3074
3075 /*
3076 * Application Entrypoint
3077 */
3078 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
3079 int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
3080 #else
3081 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
3082 #endif
3083 {
3084 const char* rufus_loc = "rufus.loc";
3085 wchar_t kernel32_path[MAX_PATH];
3086 int i, opt, option_index = 0, argc = 0, si = 0, lcid = GetUserDefaultUILanguage();
3087 int wait_for_mutex = 0;
3088 FILE* fd;
3089 BOOL attached_console = FALSE, external_loc_file = FALSE, lgp_set = FALSE, automount = TRUE;
3090 BOOL disable_hogger = FALSE, previous_enable_HDDs = FALSE, vc = IsRegistryNode(REGKEY_HKCU, vs_reg);
3091 BOOL alt_pressed = FALSE, alt_command = FALSE;
3092 BYTE *loc_data;
3093 DWORD loc_size, u, size = sizeof(u);
3094 char tmp_path[MAX_PATH] = "", loc_file[MAX_PATH] = "", ini_path[MAX_PATH] = "", ini_flags[] = "rb";
3095 char *tmp, *locale_name = NULL, **argv = NULL;
3096 wchar_t **wenv, **wargv;
3097 PF_TYPE_DECL(CDECL, int, __wgetmainargs, (int*, wchar_t***, wchar_t***, int, int*));
3098 PF_TYPE_DECL(WINAPI, BOOL, SetDefaultDllDirectories, (DWORD));
3099 HANDLE mutex = NULL, hogmutex = NULL, hFile = NULL;
3100 HWND hDlg = NULL;
3101 HDC hDC;
3102 MSG msg;
3103 struct option long_options[] = {
3104 {"extra-devs", no_argument, NULL, 'x'},
3105 {"gui", no_argument, NULL, 'g'},
3106 {"help", no_argument, NULL, 'h'},
3107 {"iso", required_argument, NULL, 'i'},
3108 {"locale", required_argument, NULL, 'l'},
3109 {"filesystem", required_argument, NULL, 'f'},
3110 {"wait", required_argument, NULL, 'w'},
3111 {0, 0, NULL, 0}
3112 };
3113
3114 // Disable loading system DLLs from the current directory (sideloading mitigation)
3115 // PS: You know that official MSDN documentation for SetDllDirectory() that explicitly
3116 // indicates that "If the parameter is an empty string (""), the call removes the current
3117 // directory from the default DLL search order"? Yeah, that doesn't work. At all.
3118 // Still, we invoke it, for platforms where the following call might actually work...
3119 SetDllDirectoryA("");
3120
3121 // Also, even if you use SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32), you're
3122 // still going to be brought down if you link to wininet.lib or dwmapi.lib, as these two
3123 // perform their DLL invocations before you've had a chance to execute anything.
3124 // Of course, this is not something that security "researchers" will bother looking into
3125 // to try to help fellow developers, when they can get an ego fix by simply throwing
3126 // generic URLs around and deliberately refusing to practice *responsible disclosure*...
3127 // Finally, we need to perform the whole gymkhana below, where we can't call on
3128 // SetDefaultDllDirectories() directly, because Windows 7 doesn't have the API exposed.
3129 GetSystemDirectoryW(kernel32_path, ARRAYSIZE(kernel32_path));
3130 wcsncat(kernel32_path, L"\\kernel32.dll", ARRAYSIZE(kernel32_path) - wcslen(kernel32_path) - 1);
3131 // NB: Because kernel32 should already be loaded, what we do above to ensure that we
3132 // (re)pick the system one is mostly unnecessary. But since for a hammer everything is a
3133 // nail... Also, no, Coverity, we never need to care about freeing kernel32 as a library.
3134 // coverity[leaked_storage]
3135 pfSetDefaultDllDirectories = (SetDefaultDllDirectories_t)
3136 GetProcAddress(LoadLibraryW(kernel32_path), "SetDefaultDllDirectories");
3137 if (pfSetDefaultDllDirectories != NULL)
3138 pfSetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32);
3139
3140 uprintf("*** " APPLICATION_NAME " init ***\n");
3141 its_a_me_mario = GetUserNameA((char*)(uintptr_t)&u, &size) && (u == 7104878);
3142 // coverity[pointless_string_compare]
3143 is_x86_32 = (strcmp(APPLICATION_ARCH, "x86") == 0);
3144
3145 // We have to process the arguments before we acquire the lock and process the locale
3146 PF_INIT(__wgetmainargs, Msvcrt);
3147 if (pf__wgetmainargs != NULL) {
3148 pf__wgetmainargs(&argc, &wargv, &wenv, 1, &si);
3149 argv = (char**)calloc(argc, sizeof(char*));
3150 if (argv != NULL) {
3151 // Non getopt parameter check
3152 for (i = 0; i < argc; i++) {
3153 argv[i] = wchar_to_utf8(wargv[i]);
3154 // Check for " /W" (wait for mutex release for pre 1.3.3 versions)
3155 if (strcmp(argv[i], "/W") == 0)
3156 wait_for_mutex = 150; // Try to acquire the mutex for 15 seconds
3157 // We need to find if we need to disable the hogger BEFORE we start
3158 // processing arguments with getopt, as we may want to print messages
3159 // on the commandline then, which the hogger makes more intuitive.
3160 if ((strcmp(argv[i], "-g") == 0) || (strcmp(argv[i], "--gui") == 0))
3161 disable_hogger = TRUE;
3162 }
3163 // If our application name contains a 'p' (for "portable") create a 'rufus.ini'
3164 // NB: argv[0] is populated in the previous loop
3165 tmp = &argv[0][strlen(argv[0]) - 1];
3166 while ((((uintptr_t)tmp) > ((uintptr_t)argv[0])) && (*tmp != '\\'))
3167 tmp--;
3168 // Need to take 'ALPHA' into account
3169 if ((strchr(tmp, 'p') != NULL) || ((strchr(tmp, 'P') != NULL) && (strchr(tmp, 'P')[1] != 'H')))
3170 ini_flags[0] = 'a';
3171
3172 // Now enable the hogger before processing the rest of the arguments
3173 if (!disable_hogger) {
3174 // Reattach the console, if we were started from commandline
3175 if (AttachConsole(ATTACH_PARENT_PROCESS) != 0) {
3176 attached_console = TRUE;
3177 IGNORE_RETVAL(freopen("CONIN$", "r", stdin));
3178 IGNORE_RETVAL(freopen("CONOUT$", "w", stdout));
3179 IGNORE_RETVAL(freopen("CONOUT$", "w", stderr));
3180 _flushall();
3181 hogmutex = SetHogger();
3182 }
3183 }
3184
3185 while ((opt = getopt_long(argc, argv, "?xghf:i:w:l:", long_options, &option_index)) != EOF) {
3186 switch (opt) {
3187 case 'x':
3188 enable_HDDs = TRUE;
3189 break;
3190 case 'g':
3191 // No need to reprocess that option
3192 break;
3193 case 'i':
3194 if (_access(optarg, 0) != -1) {
3195 safe_free(image_path);
3196 image_path = safe_strdup(optarg);
3197 img_provided = TRUE;
3198 }
3199 else {
3200 printf("Could not find ISO image '%s'\n", optarg);
3201 }
3202 break;
3203 case 'l':
3204 if (isdigitU(optarg[0])) {
3205 lcid = (int)strtol(optarg, NULL, 0);
3206 }
3207 else {
3208 safe_free(locale_name);
3209 locale_name = safe_strdup(optarg);
3210 }
3211 break;
3212 case 'f':
3213 if (isdigitU(optarg[0])) {
3214 preselected_fs = (int)strtol(optarg, NULL, 0);
3215 } else {
3216 for (i = 0; i < ARRAYSIZE(FileSystemLabel); i++) {
3217 if (safe_stricmp(optarg, FileSystemLabel[i]) == 0) {
3218 preselected_fs = i;
3219 break;
3220 }
3221 }
3222 }
3223 if ((preselected_fs < FS_UNKNOWN) || (preselected_fs >= FS_MAX))
3224 preselected_fs = FS_UNKNOWN;
3225 selected_fs = preselected_fs;
3226 break;
3227 case 'w':
3228 wait_for_mutex = atoi(optarg);
3229 break;
3230 case '?':
3231 case 'h':
3232 default:
3233 PrintUsage(argv[0]);
3234 goto out;
3235 }
3236 }
3237 }
3238 } else {
3239 uprintf("Could not access UTF-16 args");
3240 }
3241
3242 // Retrieve various app & system directories
3243 if (GetCurrentDirectoryU(sizeof(app_dir), app_dir) == 0) {
3244 uprintf("Could not get current directory: %s", WindowsErrorString());
3245 app_dir[0] = 0;
3246 }
3247 if (GetSystemDirectoryU(system_dir, sizeof(system_dir)) == 0) {
3248 uprintf("Could not get system directory: %s", WindowsErrorString());
3249 static_strcpy(system_dir, "C:\\Windows\\System32");
3250 }
3251 if (GetTempPathU(sizeof(temp_dir), temp_dir) == 0) {
3252 uprintf("Could not get temp directory: %s", WindowsErrorString());
3253 static_strcpy(temp_dir, ".\\");
3254 }
3255 // Construct Sysnative ourselves as there is no GetSysnativeDirectory() call
3256 // By default (64bit app running on 64 bit OS or 32 bit app running on 32 bit OS)
3257 // Sysnative and System32 are the same
3258 static_strcpy(sysnative_dir, system_dir);
3259 // But if the app is 32 bit and the OS is 64 bit, Sysnative must differ from System32
3260 #if (!defined(_WIN64) && !defined(BUILD64))
3261 if (is_x64()) {
3262 if (GetSystemWindowsDirectoryU(sysnative_dir, sizeof(sysnative_dir)) == 0) {
3263 uprintf("Could not get Windows directory: %s", WindowsErrorString());
3264 static_strcpy(sysnative_dir, "C:\\Windows");
3265 }
3266 static_strcat(sysnative_dir, "\\Sysnative");
3267 }
3268 #endif
3269
3270 // Look for a .ini file in the current app directory
3271 static_sprintf(ini_path, "%s\\rufus.ini", app_dir);
3272 fd = fopenU(ini_path, ini_flags); // Will create the file if portable mode is requested
3273 vc |= (safe_strcmp(GetSignatureName(NULL, NULL), cert_name[0]) == 0);
3274 if (fd != NULL) {
3275 ini_file = ini_path;
3276 fclose(fd);
3277 }
3278 uprintf("Will use settings from %s", (ini_file != NULL)?"INI file":"registry");
3279
3280 // Use the locale specified by the settings, if any
3281 tmp = ReadSettingStr(SETTING_LOCALE);
3282 if (tmp[0] != 0) {
3283 locale_name = safe_strdup(tmp);
3284 uprintf("found locale '%s'", locale_name);
3285 }
3286
3287 // Restore user-saved settings
3288 advanced_mode_device = ReadSettingBool(SETTING_ADVANCED_MODE_DEVICE);
3289 advanced_mode_format = ReadSettingBool(SETTING_ADVANCED_MODE_FORMAT);
3290 preserve_timestamps = ReadSettingBool(SETTING_PRESERVE_TIMESTAMPS);
3291 use_fake_units = !ReadSettingBool(SETTING_USE_PROPER_SIZE_UNITS);
3292 use_vds = ReadSettingBool(SETTING_USE_VDS);
3293 usb_debug = ReadSettingBool(SETTING_ENABLE_USB_DEBUG);
3294 cdio_loglevel_default = usb_debug ? CDIO_LOG_DEBUG : CDIO_LOG_WARN;
3295 detect_fakes = !ReadSettingBool(SETTING_DISABLE_FAKE_DRIVES_CHECK);
3296 allow_dual_uefi_bios = ReadSettingBool(SETTING_ENABLE_WIN_DUAL_EFI_BIOS);
3297 force_large_fat32 = ReadSettingBool(SETTING_FORCE_LARGE_FAT32_FORMAT);
3298 enable_vmdk = ReadSettingBool(SETTING_ENABLE_VMDK_DETECTION);
3299 enable_file_indexing = ReadSettingBool(SETTING_ENABLE_FILE_INDEXING);
3300 enable_VHDs = !ReadSettingBool(SETTING_DISABLE_VHDS);
3301 enable_extra_hashes = ReadSettingBool(SETTING_ENABLE_EXTRA_HASHES);
3302 ignore_boot_marker = ReadSettingBool(SETTING_IGNORE_BOOT_MARKER);
3303 // We want above normal priority by default, so we offset the value.
3304 default_thread_priority = ReadSetting32(SETTING_DEFAULT_THREAD_PRIORITY) + THREAD_PRIORITY_ABOVE_NORMAL;
3305
3306 // Initialize the global scaling, in case we need it before we initialize the dialog
3307 hDC = GetDC(NULL);
3308 fScale = GetDeviceCaps(hDC, LOGPIXELSX) / 96.0f;
3309 safe_release_dc(NULL, hDC);
3310
3311 // Init localization
3312 init_localization();
3313
3314 // Seek for a loc file in the current directory
3315 if (GetFileAttributesU(rufus_loc) == INVALID_FILE_ATTRIBUTES) {
3316 uprintf("loc file not found in current directory - embedded one will be used");
3317
3318 loc_data = (BYTE*)GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_LC_RUFUS_LOC), _RT_RCDATA, "embedded.loc", &loc_size, FALSE);
3319 if ( (GetTempFileNameU(temp_dir, APPLICATION_NAME, 0, loc_file) == 0) || (loc_file[0] == 0) ) {
3320 // Last ditch effort to get a loc file - just extract it to the current directory
3321 static_strcpy(loc_file, rufus_loc);
3322 }
3323
3324 hFile = CreateFileU(loc_file, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ,
3325 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3326 if ((hFile == INVALID_HANDLE_VALUE) || (!WriteFileWithRetry(hFile, loc_data, loc_size, &size, WRITE_RETRIES))) {
3327 uprintf("localization: unable to extract '%s': %s", loc_file, WindowsErrorString());
3328 safe_closehandle(hFile);
3329 goto out;
3330 }
3331 uprintf("localization: extracted data to '%s'", loc_file);
3332 safe_closehandle(hFile);
3333 } else {
3334 static_sprintf(loc_file, "%s\\%s", app_dir, rufus_loc);
3335 external_loc_file = TRUE;
3336 uprintf("using external loc file '%s'", loc_file);
3337 }
3338
3339 if ( (!get_supported_locales(loc_file))
3340 || ((selected_locale = ((locale_name == NULL)?get_locale_from_lcid(lcid, TRUE):get_locale_from_name(locale_name, TRUE))) == NULL) ) {
3341 uprintf("FATAL: Could not access locale!");
3342 MessageBoxA(NULL, "The locale data is missing or invalid. This application will now exit.",
3343 "Fatal error", MB_ICONSTOP|MB_SYSTEMMODAL);
3344 goto out;
3345 }
3346 selected_langid = get_language_id(selected_locale);
3347
3348 // Set the Windows version
3349 GetWindowsVersion();
3350
3351 // ...and nothing of value was lost
3352 if (nWindowsVersion < WINDOWS_7) {
3353 // Load the translation before we print the error
3354 get_loc_data_file(loc_file, selected_locale);
3355 right_to_left_mode = ((selected_locale->ctrl_id) & LOC_RIGHT_TO_LEFT);
3356 // Set MB_SYSTEMMODAL to prevent Far Manager from stealing focus...
3357 MessageBoxExU(NULL, lmprintf(MSG_294), lmprintf(MSG_293), MB_ICONSTOP | MB_IS_RTL | MB_SYSTEMMODAL, selected_langid);
3358 goto out;
3359 }
3360
3361 // This is needed as there appears to be a *FLAW* in Windows allowing the app to run unelevated with some
3362 // weirdly configured user accounts, even as we explicitly set 'requireAdministrator' in the manifest...
3363 if (!IsCurrentProcessElevated()) {
3364 uprintf("FATAL: No administrative privileges!");
3365 // Load the translation before we print the error
3366 get_loc_data_file(loc_file, selected_locale);
3367 right_to_left_mode = ((selected_locale->ctrl_id) & LOC_RIGHT_TO_LEFT);
3368 MessageBoxExU(NULL, lmprintf(MSG_289), lmprintf(MSG_288), MB_ICONSTOP | MB_IS_RTL | MB_SYSTEMMODAL, selected_langid);
3369 goto out;
3370 }
3371
3372 // Prevent 2 applications from running at the same time, unless "/W" is passed as an option
3373 // in which case we wait for the mutex to be relinquished
3374 if ((safe_strlen(lpCmdLine)==2) && (lpCmdLine[0] == '/') && (lpCmdLine[1] == 'W'))
3375 wait_for_mutex = 150; // Try to acquire the mutex for 15 seconds
3376 mutex = CreateMutexA(NULL, TRUE, "Global/" APPLICATION_NAME);
3377 for (;(wait_for_mutex>0) && (mutex != NULL) && (GetLastError() == ERROR_ALREADY_EXISTS); wait_for_mutex--) {
3378 CloseHandle(mutex);
3379 Sleep(100);
3380 mutex = CreateMutexA(NULL, TRUE, "Global/" APPLICATION_NAME);
3381 }
3382 if ((mutex == NULL) || (GetLastError() == ERROR_ALREADY_EXISTS)) {
3383 // Load the translation before we print the error
3384 get_loc_data_file(loc_file, selected_locale);
3385 right_to_left_mode = ((selected_locale->ctrl_id) & LOC_RIGHT_TO_LEFT);
3386 // Set MB_SYSTEMMODAL to prevent Far Manager from stealing focus...
3387 MessageBoxExU(NULL, lmprintf(MSG_002), lmprintf(MSG_001), MB_ICONSTOP|MB_IS_RTL|MB_SYSTEMMODAL, selected_langid);
3388 goto out;
3389 }
3390
3391 // Save instance of the application for further reference
3392 hMainInstance = hInstance;
3393
3394 // Initialize COM for folder selection
3395 IGNORE_RETVAL(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));
3396
3397 // Some dialogs have Rich Edit controls and won't display without this
3398 if (GetLibraryHandle("Riched20") == NULL) {
3399 uprintf("Could not load RichEdit library - some dialogs may not display: %s\n", WindowsErrorString());
3400 }
3401
3402 // Increase the application privileges (SE_DEBUG_PRIVILEGE), so that we can report
3403 // the Windows Services preventing access to the disk or volume we want to format.
3404 EnablePrivileges();
3405
3406 // We use local group policies rather than direct registry manipulation
3407 // 0x9e disables removable and fixed drive notifications
3408 lgp_set = SetLGP(FALSE, &existing_key, ep_reg, "NoDriveTypeAutorun", 0x9e);
3409
3410 // Re-enable AutoMount if needed
3411 if (!GetAutoMount(&automount)) {
3412 uprintf("Could not get AutoMount status");
3413 automount = TRUE; // So that we don't try to change its status on exit
3414 } else if (!automount) {
3415 uprintf("AutoMount was detected as disabled - temporarily re-enabling it");
3416 if (!SetAutoMount(TRUE))
3417 uprintf("Failed to enable AutoMount");
3418 }
3419
3420 relaunch:
3421 ubprintf("Localization set to '%s'", selected_locale->txt[0]);
3422 right_to_left_mode = ((selected_locale->ctrl_id) & LOC_RIGHT_TO_LEFT);
3423 // We always launch with the image options displaying
3424 image_options = IMOP_WINTOGO;
3425 image_option_txt[0] = 0;
3426 select_index = 0;
3427 safe_free(fido_url);
3428 SetProcessDefaultLayout(right_to_left_mode ? LAYOUT_RTL : 0);
3429 if (get_loc_data_file(loc_file, selected_locale))
3430 WriteSettingStr(SETTING_LOCALE, selected_locale->txt[0]);
3431
3432 if (!vc) {
3433 if (MessageBoxExU(NULL, lmprintf(MSG_296), lmprintf(MSG_295),
3434 MB_YESNO | MB_ICONWARNING | MB_IS_RTL | MB_SYSTEMMODAL, selected_langid) != IDYES)
3435 goto out;
3436 vc = TRUE;
3437 }
3438
3439 /*
3440 * Create the main Window
3441 */
3442 if (hDlg != NULL)
3443 // Make sure any previous dialog is destroyed (e.g. when switching languages)
3444 DestroyWindow(hDlg);
3445 hDlg = MyCreateDialog(hInstance, IDD_DIALOG, NULL, MainCallback);
3446 if (hDlg == NULL) {
3447 MessageBoxExU(NULL, "Could not create Window", "DialogBox failure",
3448 MB_ICONSTOP|MB_IS_RTL|MB_SYSTEMMODAL, selected_langid);
3449 goto out;
3450 }
3451 if ((relaunch_rc.left > -65536) && (relaunch_rc.top > -65536))
3452 SetWindowPos(hDlg, HWND_TOP, relaunch_rc.left, relaunch_rc.top, 0, 0, SWP_NOSIZE);
3453
3454 // Enable drag-n-drop through the message filter
3455 ChangeWindowMessageFilterEx(hDlg, WM_DROPFILES, MSGFLT_ADD, NULL);
3456 ChangeWindowMessageFilterEx(hDlg, WM_COPYDATA, MSGFLT_ADD, NULL);
3457 // CopyGlobalData is needed since we are running elevated
3458 ChangeWindowMessageFilterEx(hDlg, WM_COPYGLOBALDATA, MSGFLT_ADD, NULL);
3459
3460 // Set the hook to automatically close Windows' "You need to format the disk in drive..." prompt
3461 SetAlertPromptMessages();
3462 if (!SetAlertPromptHook())
3463 uprintf("Warning: Could not set alert prompt hook");
3464
3465 ShowWindow(hDlg, SW_SHOWNORMAL);
3466 UpdateWindow(hDlg);
3467
3468 // Do our own event processing and process "magic" commands
3469 while(GetMessage(&msg, NULL, 0, 0)) {
3470 static BOOL ctrl_without_focus = FALSE;
3471 BOOL no_focus = (msg.message == WM_SYSKEYDOWN) && !(msg.lParam & 0x20000000);
3472 // ** ***************************
3473 // .,ABCDEFGHIJKLMNOPQRSTUVWXYZ+-
3474
3475 // Sigh... The things one need to do to detect standalone use of the 'Alt' key.
3476 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam != VK_MENU))
3477 alt_command = TRUE;
3478 else if (GetKeyState(VK_MENU) & 0x8000)
3479 alt_pressed = TRUE;
3480
3481 // Ctrl-A => Select the log data
3482 if ((IsWindowVisible(hLogDialog)) && (GetKeyState(VK_CONTROL) & 0x8000) &&
3483 (msg.message == WM_KEYDOWN) && (msg.wParam == 'A')) {
3484 // Might also need ES_NOHIDESEL property if you want to select when not active
3485 Edit_SetSel(hLog, 0, -1);
3486 continue;
3487 }
3488
3489 // Detecting Ctrl combination keypress while an operation is in progress is a super-mess
3490 // because Windows considers that our dialog doesn't have keyboard focus (WHYYYYYY?!?!?)
3491 // and therefore first sends a WM_SYSKEYDOWN (i.e. the message that is supposed to tell
3492 // you that Alt is being pressed, because why not also use it for a COMPLETELY DIFFERENT
3493 // FRIGGING KEY!!!) with bit 29 of msg.lParam cleared, along with the code for the Ctrl
3494 // key and *THEN* a subsequent message (still using WM_SYSKEYDOWN without Alt) with the
3495 // other key. So we need to detect both the messages in sequence...
3496 if (no_focus && (msg.wParam == VK_CONTROL))
3497 ctrl_without_focus = op_in_progress;
3498
3499 // Ctrl-L => Open/Close the log
3500 if ((ctrl_without_focus || ((GetKeyState(VK_CONTROL) & 0x8000) && (msg.message == WM_KEYDOWN)))
3501 && (msg.wParam == 'L')) {
3502 ctrl_without_focus = FALSE;
3503 SendMessage(hMainDialog, WM_COMMAND, IDC_LOG, 0);
3504 continue;
3505 }
3506 #if defined(_DEBUG) || defined(TEST)
3507 // Ctrl-T => Alternate Test mode that doesn't require a full rebuild
3508 if ((ctrl_without_focus || ((GetKeyState(VK_CONTROL) & 0x8000) && (msg.message == WM_KEYDOWN)))
3509 && (msg.wParam == 'T')) {
3510 //extern int TestChecksum(void);
3511 //TestChecksum();
3512 ListVdsVolumes(FALSE);
3513 continue;
3514 }
3515 #endif
3516
3517 if (no_focus && (msg.wParam != VK_CONTROL))
3518 ctrl_without_focus = FALSE;
3519
3520 if (no_focus)
3521 continue;
3522
3523 // Alt +/- => Increase or decrease thread priority for format/file-copy/wim-apply operations
3524 if ((msg.message == WM_SYSKEYDOWN) && ((msg.wParam == VK_OEM_PLUS) || (msg.wParam == VK_OEM_MINUS) ||
3525 (msg.wParam == VK_ADD) || (msg.wParam == VK_SUBTRACT))) {
3526 int delta = ((msg.wParam == VK_OEM_PLUS) || (msg.wParam == VK_ADD)) ? +1 : -1;
3527 if (((delta == +1) && (default_thread_priority < THREAD_PRIORITY_HIGHEST)) ||
3528 ((delta == -1) && (default_thread_priority > THREAD_PRIORITY_LOWEST))) {
3529 default_thread_priority += delta;
3530 WriteSetting32(SETTING_DEFAULT_THREAD_PRIORITY, default_thread_priority - THREAD_PRIORITY_ABOVE_NORMAL);
3531 if (format_thread != NULL)
3532 SetThreadPriority(format_thread, default_thread_priority);
3533 if (apply_wim_thread != NULL)
3534 SetThreadPriority(apply_wim_thread, default_thread_priority);
3535 }
3536 PrintStatus(STATUS_MSG_TIMEOUT, MSG_318, default_thread_priority);
3537 continue;
3538 }
3539
3540 // The following cheat modes should not be enacted when an operation is in progress
3541 if (!op_in_progress) {
3542 // Alt-. => Enable USB enumeration debug
3543 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == VK_OEM_PERIOD)) {
3544 usb_debug = !usb_debug;
3545 cdio_loglevel_default = usb_debug ? CDIO_LOG_DEBUG : CDIO_LOG_WARN;
3546 WriteSettingBool(SETTING_ENABLE_USB_DEBUG, usb_debug);
3547 PrintStatusTimeout(lmprintf(MSG_270), usb_debug);
3548 GetDevices(0);
3549 continue;
3550 }
3551 // Alt-, => Disable physical drive locking
3552 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == VK_OEM_COMMA)) {
3553 lock_drive = !lock_drive;
3554 PrintStatusTimeout(lmprintf(MSG_282), lock_drive);
3555 continue;
3556 }
3557 // Alt-B => Toggle fake drive detection during bad blocks check
3558 // By default, Rufus will check for fake USB flash drives that mistakenly present
3559 // more capacity than they already have by looping over the flash. This check which
3560 // is enabled by default is performed by writing the block number sequence and reading
3561 // it back during the bad block check.
3562 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'B')) {
3563 detect_fakes = !detect_fakes;
3564 WriteSettingBool(SETTING_DISABLE_FAKE_DRIVES_CHECK, !detect_fakes);
3565 PrintStatusTimeout(lmprintf(MSG_256), detect_fakes);
3566 continue;
3567 }
3568 // Alt-C => Cycle USB port for currently selected device
3569 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'C')) {
3570 int index = ComboBox_GetCurSel(hDeviceList);
3571 if (index >= 0)
3572 CyclePort(index);
3573 continue;
3574 }
3575 // Alt-D => Delete the 'rufus_files' subdirectory
3576 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'D')) {
3577 static_sprintf(tmp_path, "%s\\%s", app_dir, FILES_DIR);
3578 PrintStatus(STATUS_MSG_TIMEOUT, MSG_264, tmp_path);
3579 SHDeleteDirectoryExU(NULL, tmp_path, FOF_SILENT | FOF_NOERRORUI | FOF_NOCONFIRMATION);
3580 continue;
3581 }
3582 // Alt-E => Enhanced installation mode (allow dual UEFI/BIOS mode and FAT32 for Windows)
3583 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'E')) {
3584 allow_dual_uefi_bios = !allow_dual_uefi_bios;
3585 WriteSettingBool(SETTING_ENABLE_WIN_DUAL_EFI_BIOS, allow_dual_uefi_bios);
3586 PrintStatusTimeout(lmprintf(MSG_266), allow_dual_uefi_bios);
3587 SetPartitionSchemeAndTargetSystem(FALSE);
3588 continue;
3589 }
3590 // Alt-F => Toggle detection of USB HDDs
3591 // By default Rufus does not list USB HDDs. This is a safety feature aimed at avoiding
3592 // unintentional formatting of backup drives instead of USB keys.
3593 // When enabled, Rufus will list and allow the formatting of USB HDDs.
3594 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'F')) {
3595 enable_HDDs = !enable_HDDs;
3596 PrintStatusTimeout(lmprintf(MSG_253), enable_HDDs);
3597 GetDevices(0);
3598 CheckDlgButton(hMainDialog, IDC_LIST_USB_HDD, enable_HDDs ? BST_CHECKED : BST_UNCHECKED);
3599 continue;
3600 }
3601 // Alt-G => Toggle detection of Virtual Disks
3602 // By default Rufus list Virtual Disks but some people use them for backup.
3603 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'G')) {
3604 enable_VHDs = !enable_VHDs;
3605 WriteSettingBool(SETTING_DISABLE_VHDS, !enable_VHDs);
3606 PrintStatusTimeout(lmprintf(MSG_308), enable_VHDs);
3607 GetDevices(0);
3608 continue;
3609 }
3610 // Alt-H => Toggle computation of SHA512 digest
3611 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'H')) {
3612 enable_extra_hashes = !enable_extra_hashes;
3613 WriteSettingBool(SETTING_ENABLE_EXTRA_HASHES, enable_extra_hashes);
3614 PrintStatusTimeout(lmprintf(MSG_312), enable_extra_hashes);
3615 continue;
3616 }
3617 // Alt-I => Toggle ISO support
3618 // This is useful if you have an ISOHybrid image and you want to force Rufus to use
3619 // DD-mode when writing the data.
3620 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'I')) {
3621 enable_iso = !enable_iso;
3622 PrintStatusTimeout(lmprintf(MSG_262), enable_iso);
3623 if (image_path != NULL) {
3624 img_provided = TRUE;
3625 dont_display_image_name = TRUE;
3626 SendMessage(hDlg, WM_COMMAND, IDC_SELECT, 0);
3627 }
3628 continue;
3629 }
3630 // Alt J => Toggle Joliet support for ISO9660 images
3631 // Some ISOs (Ubuntu) have Joliet extensions but expect applications not to use them,
3632 // due to their reliance on filenames that are > 64 chars (the Joliet max length for
3633 // a file name). This option allows users to ignore Joliet when using such images.
3634 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'J')) {
3635 enable_joliet = !enable_joliet;
3636 PrintStatusTimeout(lmprintf(MSG_257), enable_joliet);
3637 continue;
3638 }
3639 // Alt K => Toggle Rock Ridge support for ISO9660 images
3640 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'K')) {
3641 enable_rockridge = !enable_rockridge;
3642 PrintStatusTimeout(lmprintf(MSG_258), enable_rockridge);
3643 continue;
3644 }
3645 // Alt-L => Force Large FAT32 format to be used on < 32 GB drives
3646 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'L')) {
3647 force_large_fat32 = !force_large_fat32;
3648 WriteSettingBool(SETTING_FORCE_LARGE_FAT32_FORMAT, force_large_fat32);
3649 PrintStatusTimeout(lmprintf(MSG_254), force_large_fat32);
3650 GetDevices(0);
3651 continue;
3652 }
3653 // Alt-M => Toggle the check for the 0x55 0xAA boot marker at offset 0x1fe.
3654 // This means that Rufus treats anything selected as a writeable DD image.
3655 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'M')) {
3656 ignore_boot_marker = !ignore_boot_marker;
3657 WriteSettingBool(SETTING_IGNORE_BOOT_MARKER, ignore_boot_marker);
3658 PrintStatusTimeout(lmprintf(MSG_319), ignore_boot_marker);
3659 continue;
3660 }
3661 // Alt N => Enable NTFS compression
3662 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'N')) {
3663 enable_ntfs_compression = !enable_ntfs_compression;
3664 PrintStatusTimeout(lmprintf(MSG_260), enable_ntfs_compression);
3665 continue;
3666 }
3667 // Alt-O => Save from Optical drive to ISO
3668 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'O')) {
3669 SaveISO();
3670 continue;
3671 }
3672 // Alt-P => Toggle GPT ESP to and from Basic Data type (Windows 10 or later)
3673 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'P')) {
3674 int index = ComboBox_GetCurSel(hDeviceList);
3675 DWORD DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, index);
3676 if (ToggleEsp(DeviceNum, 0))
3677 CyclePort(index);
3678 continue;
3679 }
3680 // Alt-Q => Enable file indexing (for file systems that support it)
3681 // For multiple reasons, file indexing is disabled by default
3682 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'Q')) {
3683 enable_file_indexing = !enable_file_indexing;
3684 WriteSettingBool(SETTING_ENABLE_FILE_INDEXING, enable_file_indexing);
3685 PrintStatusTimeout(lmprintf(MSG_290), !enable_file_indexing);
3686 continue;
3687 }
3688 // Alt-R => Remove all the registry keys that may have been created by Rufus
3689 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'R')) {
3690 PrintStatus(STATUS_MSG_TIMEOUT, DeleteRegistryKey(REGKEY_HKCU, COMPANY_NAME "\\" APPLICATION_NAME) ? MSG_248 : MSG_249);
3691 // Also try to delete the upper key (company name) if it's empty (don't care about the result)
3692 DeleteRegistryKey(REGKEY_HKCU, COMPANY_NAME);
3693 continue;
3694 }
3695 // Alt-S => Disable size limit for ISOs
3696 // By default, Rufus will not copy ISOs that are larger than in size than
3697 // the target USB drive. If this is enabled, the size check is disabled.
3698 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'S')) {
3699 size_check = !size_check;
3700 PrintStatusTimeout(lmprintf(MSG_252), size_check);
3701 GetDevices(0);
3702 continue;
3703 }
3704 // Alt-T => Preserve timestamps when extracting ISO files
3705 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'T')) {
3706 preserve_timestamps = !preserve_timestamps;
3707 WriteSettingBool(SETTING_PRESERVE_TIMESTAMPS, preserve_timestamps);
3708 PrintStatusTimeout(lmprintf(MSG_269), preserve_timestamps);
3709 continue;
3710 }
3711 // Alt-U => Use PROPER size units, instead of this whole Kibi/Gibi nonsense
3712 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'U')) {
3713 use_fake_units = !use_fake_units;
3714 WriteSettingBool(SETTING_USE_PROPER_SIZE_UNITS, !use_fake_units);
3715 PrintStatusTimeout(lmprintf(MSG_263), !use_fake_units);
3716 GetDevices(0);
3717 continue;
3718 }
3719 // Alt-V => Use VDS facilities for formatting
3720 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'V')) {
3721 use_vds = !use_vds;
3722 WriteSettingBool(SETTING_USE_VDS, use_vds);
3723 PrintStatusTimeout("VDS", use_vds);
3724 continue;
3725 }
3726 // Alt-W => Enable VMWare disk detection
3727 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'W')) {
3728 enable_vmdk = !enable_vmdk;
3729 WriteSettingBool(SETTING_ENABLE_VMDK_DETECTION, enable_vmdk);
3730 PrintStatusTimeout(lmprintf(MSG_265), enable_vmdk);
3731 GetDevices(0);
3732 continue;
3733 }
3734 // Alt-X => Delete the NoDriveTypeAutorun key on exit (useful if the app crashed)
3735 // This key is used to disable Windows popup messages when an USB drive is plugged in.
3736 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'X')) {
3737 PrintStatus(2000, MSG_255);
3738 existing_key = FALSE;
3739 continue;
3740 }
3741 // Alt Y => Force the update check to be successful
3742 // This will set the reported current version of Rufus to 0.0.0.0 when performing an update
3743 // check, so that it always succeeds. This is useful for translators.
3744 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'Y')) {
3745 force_update = (force_update > 0) ? 0 : 1;
3746 PrintStatusTimeout(lmprintf(MSG_259), force_update);
3747 continue;
3748 }
3749 // Alt-Z => Zero the drive
3750 if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'Z')) {
3751 zero_drive = TRUE;
3752 fast_zeroing = FALSE;
3753 // Simulate a button click for Start
3754 PostMessage(hDlg, WM_COMMAND, (WPARAM)IDC_START, 0);
3755 continue;
3756 }
3757 // Ctrl-Alt-Z => Zero the drive while trying to skip empty blocks
3758 if ((msg.message == WM_KEYDOWN) && (msg.wParam == 'Z') &&
3759 (GetKeyState(VK_CONTROL) & 0x8000) && (GetKeyState(VK_MENU) & 0x8000)) {
3760 zero_drive = TRUE;
3761 fast_zeroing = TRUE;
3762 // Simulate a button click for Start
3763 PostMessage(hDlg, WM_COMMAND, (WPARAM)IDC_START, 0);
3764 continue;
3765 }
3766
3767 // Other hazardous cheat modes require Ctrl + Alt
3768 // Ctrl-Alt-F => List non USB removable drives such as eSATA, etc - CAUTION!!!
3769 if ((msg.message == WM_KEYDOWN) && (msg.wParam == 'F') &&
3770 (GetKeyState(VK_CONTROL) & 0x8000) && (GetKeyState(VK_MENU) & 0x8000)) {
3771 list_non_usb_removable_drives = !list_non_usb_removable_drives;
3772 if (list_non_usb_removable_drives) {
3773 previous_enable_HDDs = enable_HDDs;
3774 enable_HDDs = TRUE;
3775 } else {
3776 enable_HDDs = previous_enable_HDDs;
3777 }
3778 CheckDlgButton(hMainDialog, IDC_LIST_USB_HDD, enable_HDDs ? BST_CHECKED : BST_UNCHECKED);
3779 PrintStatusTimeout(lmprintf(MSG_287), list_non_usb_removable_drives);
3780 uprintf("%sListing of non-USB removable drives %s",
3781 (list_non_usb_removable_drives) ? "CAUTION: " : "", (list_non_usb_removable_drives) ? "enabled" : "disabled");
3782 if (list_non_usb_removable_drives)
3783 uprintf("By using this unofficial cheat mode you forfeit ANY RIGHT to complain if you lose valuable data!");
3784 GetDevices(0);
3785 continue;
3786 }
3787
3788 // Ctrl-Alt-Y => Force update check to be successful and ignore timestamp errors
3789 if ((msg.message == WM_KEYDOWN) && (msg.wParam == 'Y') &&
3790 (GetKeyState(VK_CONTROL) & 0x8000) && (GetKeyState(VK_MENU) & 0x8000)) {
3791 force_update = (force_update > 0) ? 0 : 2;
3792 PrintStatusTimeout(lmprintf(MSG_259), force_update);
3793 continue;
3794 }
3795 }
3796
3797 // Standalone 'Alt' key toggles progress report between percent, rate (if available)
3798 // and remaining time (if availabe)
3799 if (alt_pressed && !(GetKeyState(VK_MENU) & 0x8000)) {
3800 alt_pressed = FALSE;
3801 if (!alt_command)
3802 update_progress_type = (update_progress_type + 1) % UPT_MAX;
3803 alt_command = FALSE;
3804 }
3805
3806 // Let the system handle dialog messages (e.g. those from the tab key)
3807 if (!IsDialogMessage(hDlg, &msg) && !IsDialogMessage(hLogDialog, &msg)) {
3808 TranslateMessage(&msg);
3809 DispatchMessage(&msg);
3810 }
3811 }
3812 if (hFidoDlg != NULL)
3813 SendMessage(hFidoDlg, WM_CLOSE, 0, 0);
3814 if (relaunch) {
3815 relaunch = FALSE;
3816 reinit_localization();
3817 goto relaunch;
3818 }
3819
3820 out:
3821 // Destroy the hogger mutex first, so that the cmdline app can exit and we can delete it
3822 if (attached_console && !disable_hogger) {
3823 ReleaseMutex(hogmutex);
3824 safe_closehandle(hogmutex);
3825 }
3826 // Kill the update check thread if running
3827 if (update_check_thread != NULL)
3828 TerminateThread(update_check_thread, 1);
3829 if ((!external_loc_file) && (loc_file[0] != 0))
3830 DeleteFileU(loc_file);
3831 DestroyAllTooltips();
3832 ClrAlertPromptHook();
3833 exit_localization();
3834 safe_free(image_path);
3835 safe_free(archive_path);
3836 safe_free(locale_name);
3837 safe_free(update.download_url);
3838 safe_free(update.release_notes);
3839 safe_free(grub2_buf);
3840 safe_free(fido_url);
3841 safe_free(fido_script);
3842 if (argv != NULL) {
3843 for (i=0; i<argc; i++) safe_free(argv[i]);
3844 safe_free(argv);
3845 }
3846 if (lgp_set)
3847 SetLGP(TRUE, &existing_key, ep_reg, "NoDriveTypeAutorun", 0);
3848 if ((!automount) && (!SetAutoMount(FALSE)))
3849 uprintf("Failed to restore AutoMount to disabled");
3850 ubflush();
3851 // Unconditional delete with retry, just in case...
3852 for (i = 0; (!DeleteFileA(cmdline_hogger)) && (i <= 10); i++)
3853 Sleep(200);
3854 CloseHandle(mutex);
3855 CLOSE_OPENED_LIBRARIES;
3856 if (attached_console) {
3857 SetWindowPos(GetConsoleWindow(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
3858 FreeConsole();
3859 }
3860 uprintf("*** " APPLICATION_NAME " exit ***\n");
3861 #ifdef _CRTDBG_MAP_ALLOC
3862 _CrtDumpMemoryLeaks();
3863 #endif
3864
3865 return 0;
3866 }