"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 }