2011-11-13 20:53:23 +00:00
|
|
|
/*
|
2011-12-05 11:36:02 +00:00
|
|
|
* Rufus: The Reliable USB Formatting Utility
|
2011-11-13 20:53:23 +00:00
|
|
|
* Copyright (c) 2011 Pete Batard <pete@akeo.ie>
|
2011-11-18 01:58:08 +00:00
|
|
|
*
|
2011-11-13 20:53:23 +00:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2011-11-21 20:12:23 +00:00
|
|
|
/* Memory leaks detection - define _CRTDBG_MAP_ALLOC as preprocessor macro */
|
|
|
|
#ifdef _CRTDBG_MAP_ALLOC
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <crtdbg.h>
|
|
|
|
#endif
|
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
#include <windows.h>
|
|
|
|
#include <windowsx.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2011-11-24 02:24:50 +00:00
|
|
|
#include <math.h>
|
2011-11-13 20:53:23 +00:00
|
|
|
#include <commctrl.h>
|
2011-11-17 01:43:06 +00:00
|
|
|
#include <setupapi.h>
|
2011-11-20 02:34:15 +00:00
|
|
|
#include <winioctl.h>
|
2011-11-27 23:40:28 +00:00
|
|
|
#include <process.h>
|
2011-11-26 00:25:04 +00:00
|
|
|
#include <dbt.h>
|
2011-11-20 22:49:55 +00:00
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
#include "msapi_utf8.h"
|
|
|
|
#include "resource.h"
|
2011-11-19 19:08:23 +00:00
|
|
|
#include "rufus.h"
|
2011-11-25 13:29:35 +00:00
|
|
|
#include "sys_types.h"
|
2011-11-13 20:53:23 +00:00
|
|
|
|
2011-12-01 17:20:52 +00:00
|
|
|
static const char* FileSystemLabel[FS_MAX] = { "FAT", "FAT32", "NTFS", "exFAT" };
|
2011-12-01 02:56:44 +00:00
|
|
|
// Don't ask me - just following the MS standard here
|
2011-12-01 17:20:52 +00:00
|
|
|
static const char* ClusterSizeLabel[] = { "512 bytes", "1024 bytes","2048 bytes","4096 bytes","8192 bytes",
|
2011-12-01 02:56:44 +00:00
|
|
|
"16 kilobytes", "32 kilobytes", "64 kilobytes", "128 kilobytes", "256 kilobytes", "512 kilobytes",
|
2011-12-01 15:01:10 +00:00
|
|
|
"1024 kilobytes","2048 kilobytes","4096 kilobytes","8192 kilobytes","16 megabytes","32 megabytes" };
|
2011-12-01 02:56:44 +00:00
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
/*
|
|
|
|
* Globals
|
|
|
|
*/
|
2011-11-21 17:06:17 +00:00
|
|
|
HINSTANCE hMainInstance;
|
|
|
|
HWND hMainDialog;
|
|
|
|
char szFolderPath[MAX_PATH];
|
|
|
|
float fScale = 1.0f;
|
2011-12-01 15:01:10 +00:00
|
|
|
int default_fs;
|
2011-12-01 17:20:52 +00:00
|
|
|
HWND hDeviceList, hCapacity, hFileSystem, hClusterSize, hLabel;
|
2011-11-17 01:43:06 +00:00
|
|
|
|
2011-12-09 01:39:13 +00:00
|
|
|
static HWND hDeviceTooltip = NULL, hFSTooltip = NULL, hProgress = NULL;
|
2011-12-01 17:20:52 +00:00
|
|
|
static StrArray DriveID, DriveLabel;
|
2011-12-08 12:14:21 +00:00
|
|
|
static char szTimer[10] = "00:00:00";
|
|
|
|
static unsigned int timer;
|
2011-11-23 12:27:51 +00:00
|
|
|
|
2011-12-09 01:39:13 +00:00
|
|
|
/*
|
|
|
|
* The following is used to allocate slots within the progress bar
|
|
|
|
* 0 means unused (no operation or no progress allocated to it)
|
|
|
|
* +n means allocate exactly n bars (n percents of the progress bar)
|
|
|
|
* -n means allocate a weighted slot of n from all remaining
|
|
|
|
* bars. Eg if 80 slots remain and the sum of all negative entries
|
|
|
|
* is 10, -4 will allocate 4/10*80 = 32 bars (32%) for OP progress
|
|
|
|
*/
|
|
|
|
static int nb_slots[OP_MAX];
|
|
|
|
static float slot_end[OP_MAX+1]; // shifted +1 so that we can substract 1 to OP indexes
|
|
|
|
static float previous_end = 0.0f;
|
|
|
|
|
2011-11-17 01:43:06 +00:00
|
|
|
/*
|
2011-11-25 13:29:35 +00:00
|
|
|
* Convert a partition type to its human readable form using
|
|
|
|
* (slightly modified) entries from GNU fdisk
|
2011-11-17 01:43:06 +00:00
|
|
|
*/
|
2011-11-21 17:06:17 +00:00
|
|
|
static const char* GetPartitionType(BYTE Type)
|
2011-11-17 01:43:06 +00:00
|
|
|
{
|
2011-11-25 13:29:35 +00:00
|
|
|
int i;
|
|
|
|
for (i=0; i<ARRAYSIZE(msdos_systypes); i++) {
|
|
|
|
if (msdos_systypes[i].type == Type)
|
|
|
|
return msdos_systypes[i].name;
|
2011-11-17 01:43:06 +00:00
|
|
|
}
|
2011-11-25 13:29:35 +00:00
|
|
|
return "Unknown";
|
2011-11-17 01:43:06 +00:00
|
|
|
}
|
|
|
|
|
2011-11-18 21:46:34 +00:00
|
|
|
|
2011-12-01 02:56:44 +00:00
|
|
|
#define KB 1024LL
|
|
|
|
#define MB 1048576LL
|
|
|
|
#define GB 1073741824LL
|
|
|
|
#define TB 1099511627776LL
|
2011-12-01 15:01:10 +00:00
|
|
|
/*
|
|
|
|
* Set cluster size values according to http://support.microsoft.com/kb/140365
|
|
|
|
* this call will return FALSE if we can't find a supportable FS for the drive
|
|
|
|
*/
|
2011-12-01 02:56:44 +00:00
|
|
|
static BOOL DefineClusterSizes(void)
|
|
|
|
{
|
|
|
|
LONGLONG i;
|
2011-12-01 15:01:10 +00:00
|
|
|
int fs;
|
|
|
|
BOOL r = FALSE;
|
|
|
|
char tmp[64] = "";
|
|
|
|
|
|
|
|
default_fs = FS_UNKNOWN;
|
2011-12-01 02:56:44 +00:00
|
|
|
memset(&SelectedDrive.ClusterSize, 0, sizeof(SelectedDrive.ClusterSize));
|
|
|
|
if (SelectedDrive.DiskSize < 8*MB) {
|
|
|
|
// TODO: muck with FAT12 and Small FAT16 like Microsoft does
|
|
|
|
uprintf("This application does not support volumes smaller than 8 MB yet\n");
|
2011-12-01 15:01:10 +00:00
|
|
|
goto out;
|
2011-12-01 02:56:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// FAT 16
|
|
|
|
if (SelectedDrive.DiskSize < 4*GB) {
|
|
|
|
// TODO: Refine the following according to size
|
|
|
|
SelectedDrive.ClusterSize[FS_FAT16].Allowed = 0x0001FE00;
|
|
|
|
for (i=32; i<=4096; i<<=1) { // 8 MB -> 4 GB
|
|
|
|
if (SelectedDrive.DiskSize < i*MB) {
|
|
|
|
SelectedDrive.ClusterSize[FS_FAT16].Default = 16*(ULONG)i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FAT 32
|
|
|
|
if (SelectedDrive.DiskSize < 256*MB) {
|
|
|
|
// TODO: Refine the following according to size
|
|
|
|
SelectedDrive.ClusterSize[FS_FAT32].Allowed = 0x0001FE00;
|
|
|
|
for (i=64; i<=256; i<<=1) { // 8 MB -> 256 MB
|
|
|
|
if (SelectedDrive.DiskSize < i*MB) {
|
|
|
|
SelectedDrive.ClusterSize[FS_FAT32].Default = 8*(ULONG)i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (SelectedDrive.DiskSize < 32*GB) {
|
|
|
|
SelectedDrive.ClusterSize[FS_FAT32].Allowed = 0x0001FE00;
|
|
|
|
for (i=8; i<=32; i<<=1) { // 256 MB -> 32 GB
|
|
|
|
if (SelectedDrive.DiskSize < i*GB) {
|
|
|
|
SelectedDrive.ClusterSize[FS_FAT32].Default = ((ULONG)i/2)*1024;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NTFS
|
|
|
|
if (SelectedDrive.DiskSize < 256*TB) {
|
|
|
|
SelectedDrive.ClusterSize[FS_NTFS].Allowed = 0x0001FE00;
|
|
|
|
for (i=16; i<=256; i<<=1) { // 7 MB -> 256 TB
|
|
|
|
if (SelectedDrive.DiskSize < i*TB) {
|
|
|
|
SelectedDrive.ClusterSize[FS_NTFS].Default = ((ULONG)i/4)*1024;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// exFAT
|
|
|
|
if (SelectedDrive.DiskSize < 256*TB) {
|
|
|
|
SelectedDrive.ClusterSize[FS_EXFAT].Allowed = 0x03FFFE00;
|
|
|
|
if (SelectedDrive.DiskSize < 256*MB) // < 256 MB
|
|
|
|
SelectedDrive.ClusterSize[FS_EXFAT].Default = 4*1024;
|
|
|
|
else if (SelectedDrive.DiskSize < 32*GB) // < 32 GB
|
|
|
|
SelectedDrive.ClusterSize[FS_EXFAT].Default = 32*1024;
|
|
|
|
else
|
|
|
|
SelectedDrive.ClusterSize[FS_EXFAT].Default = 28*1024;
|
|
|
|
}
|
|
|
|
|
2011-12-01 15:01:10 +00:00
|
|
|
out:
|
|
|
|
// Only add the filesystems we can service
|
|
|
|
for (fs=0; fs<FS_MAX; fs++) {
|
|
|
|
if (SelectedDrive.ClusterSize[fs].Allowed != 0) {
|
|
|
|
safe_sprintf(tmp, sizeof(tmp), FileSystemLabel[fs]);
|
|
|
|
if (default_fs == FS_UNKNOWN) {
|
|
|
|
safe_strcat(tmp, sizeof(tmp), " (Default)");
|
|
|
|
default_fs = fs;
|
|
|
|
}
|
|
|
|
IGNORE_RETVAL(ComboBox_SetItemData(hFileSystem,
|
|
|
|
ComboBox_AddStringU(hFileSystem, tmp), fs));
|
|
|
|
r = TRUE;
|
|
|
|
}
|
|
|
|
}
|
2011-12-01 02:56:44 +00:00
|
|
|
|
2011-12-01 15:01:10 +00:00
|
|
|
return r;
|
2011-12-01 02:56:44 +00:00
|
|
|
}
|
|
|
|
#undef KB
|
|
|
|
#undef MB
|
|
|
|
#undef GB
|
|
|
|
#undef TB
|
|
|
|
|
2011-12-01 17:54:35 +00:00
|
|
|
/*
|
|
|
|
* Populate the Allocation unit size field
|
|
|
|
*/
|
2011-12-01 15:01:10 +00:00
|
|
|
static BOOL SetClusterSizes(int FSType)
|
2011-11-28 20:05:34 +00:00
|
|
|
{
|
2011-12-04 20:13:51 +00:00
|
|
|
char szClustSize[64];
|
|
|
|
int i, default_index = 0;
|
2011-12-01 02:56:44 +00:00
|
|
|
ULONG j;
|
|
|
|
|
2011-11-28 20:05:34 +00:00
|
|
|
IGNORE_RETVAL(ComboBox_ResetContent(hClusterSize));
|
2011-12-01 02:56:44 +00:00
|
|
|
|
2011-12-01 15:01:10 +00:00
|
|
|
if ((FSType < 0) || (FSType >= FS_MAX)) {
|
|
|
|
uprintf("Invalid FS value passed to SetClusterSizes\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2011-12-01 02:56:44 +00:00
|
|
|
if ( (SelectedDrive.ClusterSize[FSType].Allowed == 0)
|
|
|
|
|| (SelectedDrive.ClusterSize[FSType].Default == 0) ) {
|
|
|
|
uprintf("The drive is incompatible with FS type #%d\n", FSType);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i=0,j=0x200;j<0x10000000;i++,j<<=1) {
|
|
|
|
if (j & SelectedDrive.ClusterSize[FSType].Allowed) {
|
2011-12-04 20:13:51 +00:00
|
|
|
safe_sprintf(szClustSize, sizeof(szClustSize), "%s", ClusterSizeLabel[i]);
|
|
|
|
if (j == SelectedDrive.ClusterSize[FSType].Default) {
|
|
|
|
safe_strcat(szClustSize, sizeof(szClustSize), " (Default)");
|
|
|
|
default_index = i;
|
|
|
|
}
|
|
|
|
IGNORE_RETVAL(ComboBox_SetItemData(hClusterSize, ComboBox_AddStringU(hClusterSize, szClustSize), j));
|
2011-12-01 02:56:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-04 20:13:51 +00:00
|
|
|
IGNORE_RETVAL(ComboBox_SetCurSel(hClusterSize, default_index));
|
2011-12-01 02:56:44 +00:00
|
|
|
return TRUE;
|
2011-11-28 20:05:34 +00:00
|
|
|
}
|
|
|
|
|
2011-11-18 21:46:34 +00:00
|
|
|
/*
|
2011-11-24 02:24:50 +00:00
|
|
|
* Fill the drive properties (size, FS, etc)
|
2011-11-18 21:46:34 +00:00
|
|
|
*/
|
2011-11-24 02:24:50 +00:00
|
|
|
static BOOL GetDriveInfo(void)
|
2011-11-18 21:46:34 +00:00
|
|
|
{
|
|
|
|
BOOL r;
|
|
|
|
HANDLE hDrive;
|
|
|
|
DWORD size;
|
2011-11-21 17:06:17 +00:00
|
|
|
BYTE geometry[128], layout[1024];
|
2011-11-20 03:29:08 +00:00
|
|
|
void* disk_geometry = (void*)geometry;
|
2011-11-21 17:06:17 +00:00
|
|
|
void* drive_layout = (void*)layout;
|
|
|
|
PDISK_GEOMETRY_EX DiskGeometry = (PDISK_GEOMETRY_EX)disk_geometry;
|
|
|
|
PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)drive_layout;
|
2011-11-25 01:30:41 +00:00
|
|
|
char DrivePath[] = "#:\\", tmp[128], fs_type[32];
|
2011-11-21 17:06:17 +00:00
|
|
|
DWORD i, nb_partitions = 0;
|
2011-11-18 21:46:34 +00:00
|
|
|
|
2011-11-24 02:24:50 +00:00
|
|
|
SelectedDrive.DiskSize = 0;
|
2011-11-18 21:46:34 +00:00
|
|
|
|
2011-11-29 20:25:29 +00:00
|
|
|
hDrive = GetDriveHandle(SelectedDrive.DeviceNumber, DrivePath, FALSE, FALSE);
|
|
|
|
if (hDrive == INVALID_HANDLE_VALUE)
|
2011-11-18 21:46:34 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
r = DeviceIoControl(hDrive, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
|
|
|
|
NULL, 0, geometry, sizeof(geometry), &size, NULL );
|
|
|
|
if (!r || size <= 0) {
|
2011-11-21 17:06:17 +00:00
|
|
|
uprintf("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX failed: %s\n", WindowsErrorString());
|
2011-11-18 21:46:34 +00:00
|
|
|
safe_closehandle(hDrive);
|
|
|
|
return FALSE;
|
2011-11-17 01:43:06 +00:00
|
|
|
}
|
2011-11-24 02:24:50 +00:00
|
|
|
SelectedDrive.DiskSize = DiskGeometry->DiskSize.QuadPart;
|
2011-11-25 01:30:41 +00:00
|
|
|
memcpy(&SelectedDrive.Geometry, &DiskGeometry->Geometry, sizeof(DISK_GEOMETRY));
|
2011-11-23 12:27:51 +00:00
|
|
|
uprintf("Cylinders: %lld, TracksPerCylinder: %d, SectorsPerTrack: %d, BytesPerSector: %d\n",
|
|
|
|
DiskGeometry->Geometry.Cylinders, DiskGeometry->Geometry.TracksPerCylinder,
|
|
|
|
DiskGeometry->Geometry.SectorsPerTrack, DiskGeometry->Geometry.BytesPerSector);
|
2011-11-21 17:06:17 +00:00
|
|
|
|
|
|
|
r = DeviceIoControl(hDrive, IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
|
|
|
|
NULL, 0, layout, sizeof(layout), &size, NULL );
|
|
|
|
if (!r || size <= 0) {
|
|
|
|
uprintf("IOCTL_DISK_GET_DRIVE_LAYOUT_EX failed: %s\n", WindowsErrorString());
|
|
|
|
} else {
|
2011-11-24 23:49:42 +00:00
|
|
|
DestroyTooltip(hFSTooltip);
|
|
|
|
hFSTooltip = NULL;
|
2011-11-21 17:06:17 +00:00
|
|
|
switch (DriveLayout->PartitionStyle) {
|
|
|
|
case PARTITION_STYLE_MBR:
|
|
|
|
for (i=0; i<DriveLayout->PartitionCount; i++) {
|
|
|
|
if (DriveLayout->PartitionEntry[i].Mbr.PartitionType != PARTITION_ENTRY_UNUSED) {
|
|
|
|
uprintf("Partition #%d:\n", ++nb_partitions);
|
2011-11-24 23:49:42 +00:00
|
|
|
if (hFSTooltip == NULL) {
|
2011-11-28 12:37:58 +00:00
|
|
|
// TODO: provide all partitions FS on tooltip, not just the one
|
2011-11-26 00:25:04 +00:00
|
|
|
safe_sprintf(tmp, sizeof(tmp), "Current file system: %s (0x%02x)",
|
2011-11-24 23:49:42 +00:00
|
|
|
GetPartitionType(DriveLayout->PartitionEntry[i].Mbr.PartitionType),
|
|
|
|
DriveLayout->PartitionEntry[i].Mbr.PartitionType);
|
|
|
|
hFSTooltip = CreateTooltip(hFileSystem, tmp, -1);
|
|
|
|
}
|
2011-11-26 00:25:04 +00:00
|
|
|
uprintf(" Type: %s (0x%02x)\n Boot: %s\n Recognized: %s\n Hidden Sectors: %d\n",
|
2011-11-21 17:06:17 +00:00
|
|
|
GetPartitionType(DriveLayout->PartitionEntry[i].Mbr.PartitionType),
|
|
|
|
DriveLayout->PartitionEntry[i].Mbr.PartitionType,
|
|
|
|
DriveLayout->PartitionEntry[i].Mbr.BootIndicator?"Yes":"No",
|
|
|
|
DriveLayout->PartitionEntry[i].Mbr.RecognizedPartition?"Yes":"No",
|
|
|
|
DriveLayout->PartitionEntry[i].Mbr.HiddenSectors);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
uprintf("Partition type: MBR, NB Partitions: %d\n", nb_partitions);
|
|
|
|
break;
|
|
|
|
case PARTITION_STYLE_GPT:
|
|
|
|
uprintf("Partition type: GPT, NB Partitions: %d\n", DriveLayout->PartitionCount);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
uprintf("Partition type: RAW\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-11-18 21:46:34 +00:00
|
|
|
|
|
|
|
safe_closehandle(hDrive);
|
|
|
|
|
2011-12-01 15:01:10 +00:00
|
|
|
if (!DefineClusterSizes()) {
|
|
|
|
uprintf("no file system is selectable for this drive\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2011-11-25 01:30:41 +00:00
|
|
|
|
2011-12-01 15:01:10 +00:00
|
|
|
// re-select existing FS if it's one we know
|
2011-11-24 23:49:42 +00:00
|
|
|
if (GetVolumeInformationA(DrivePath, NULL, 0, NULL, NULL, NULL,
|
2011-11-25 01:30:41 +00:00
|
|
|
fs_type, sizeof(fs_type))) {
|
2011-12-01 15:01:10 +00:00
|
|
|
for (SelectedDrive.FSType=FS_MAX-1; SelectedDrive.FSType>=0; SelectedDrive.FSType--) {
|
|
|
|
if (safe_strcmp(fs_type, FileSystemLabel[SelectedDrive.FSType]) == 0) {
|
2011-11-24 23:49:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-12-01 15:01:10 +00:00
|
|
|
} else {
|
|
|
|
SelectedDrive.FSType = FS_UNKNOWN;
|
2011-11-19 01:30:20 +00:00
|
|
|
}
|
|
|
|
|
2011-12-01 15:01:10 +00:00
|
|
|
for (i=0; i<ComboBox_GetCount(hFileSystem); i++) {
|
|
|
|
if (ComboBox_GetItemData(hFileSystem, i) == SelectedDrive.FSType) {
|
|
|
|
IGNORE_RETVAL(ComboBox_SetCurSel(hFileSystem, i));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == ComboBox_GetCount(hFileSystem)) {
|
|
|
|
// failed to reselect => pick default
|
|
|
|
for (i=0; i<ComboBox_GetCount(hFileSystem); i++) {
|
|
|
|
if (ComboBox_GetItemData(hFileSystem, i) == default_fs) {
|
|
|
|
IGNORE_RETVAL(ComboBox_SetCurSel(hFileSystem, i));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// At least one filesystem is go => enable formatting
|
|
|
|
EnableWindow(GetDlgItem(hMainDialog, IDC_START), TRUE);
|
|
|
|
|
|
|
|
return SetClusterSizes((int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem)));
|
2011-11-18 21:46:34 +00:00
|
|
|
}
|
|
|
|
|
2011-11-21 17:06:17 +00:00
|
|
|
/*
|
|
|
|
* Populate the UI properties
|
|
|
|
*/
|
2011-11-24 02:24:50 +00:00
|
|
|
static BOOL PopulateProperties(int ComboIndex)
|
2011-11-18 21:46:34 +00:00
|
|
|
{
|
|
|
|
double HumanReadableSize;
|
2011-11-24 02:24:50 +00:00
|
|
|
char capacity[64];
|
2011-12-01 19:43:45 +00:00
|
|
|
static char *suffix[] = { "KB", "MB", "GB", "TB", "PB"};
|
2011-11-24 02:24:50 +00:00
|
|
|
char proposed_label[16], no_label[] = STR_NO_LABEL;
|
2011-11-18 21:46:34 +00:00
|
|
|
int i;
|
|
|
|
|
2011-11-18 23:41:28 +00:00
|
|
|
IGNORE_RETVAL(ComboBox_ResetContent(hCapacity));
|
2011-11-19 01:30:20 +00:00
|
|
|
IGNORE_RETVAL(ComboBox_ResetContent(hFileSystem));
|
2011-11-28 20:05:34 +00:00
|
|
|
IGNORE_RETVAL(ComboBox_ResetContent(hClusterSize));
|
2011-12-01 15:01:10 +00:00
|
|
|
EnableWindow(GetDlgItem(hMainDialog, IDC_START), FALSE);
|
2011-11-24 02:24:50 +00:00
|
|
|
SetWindowTextA(hLabel, "");
|
2011-11-24 23:49:42 +00:00
|
|
|
DestroyTooltip(hDeviceTooltip);
|
2011-11-25 13:29:35 +00:00
|
|
|
DestroyTooltip(hFSTooltip);
|
2011-11-24 23:49:42 +00:00
|
|
|
hDeviceTooltip = NULL;
|
2011-11-25 13:29:35 +00:00
|
|
|
hFSTooltip = NULL;
|
2011-11-24 02:24:50 +00:00
|
|
|
memset(&SelectedDrive, 0, sizeof(SelectedDrive));
|
|
|
|
|
|
|
|
if (ComboIndex < 0) {
|
2011-11-18 23:41:28 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-11-24 02:24:50 +00:00
|
|
|
SelectedDrive.DeviceNumber = (DWORD)ComboBox_GetItemData(hDeviceList, ComboIndex);
|
|
|
|
if (!GetDriveInfo())
|
2011-11-18 21:46:34 +00:00
|
|
|
return FALSE;
|
2011-11-17 01:43:06 +00:00
|
|
|
|
2011-11-24 02:24:50 +00:00
|
|
|
HumanReadableSize = (double)SelectedDrive.DiskSize;
|
2011-11-18 21:46:34 +00:00
|
|
|
for (i=0; i<ARRAYSIZE(suffix); i++) {
|
|
|
|
HumanReadableSize /= 1024.0;
|
|
|
|
if (HumanReadableSize < 512.0) {
|
|
|
|
safe_sprintf(capacity, sizeof(capacity), "%0.2f %s", HumanReadableSize, suffix[i]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
IGNORE_RETVAL(ComboBox_AddStringU(hCapacity, capacity));
|
|
|
|
IGNORE_RETVAL(ComboBox_SetCurSel(hCapacity, 0));
|
2011-11-24 23:49:42 +00:00
|
|
|
hDeviceTooltip = CreateTooltip(hDeviceList, DriveID.Table[ComboIndex], -1);
|
2011-11-24 20:02:14 +00:00
|
|
|
|
2011-11-24 02:24:50 +00:00
|
|
|
// If no existing label is available, propose one according to the size (eg: "256MB", "8GB")
|
|
|
|
if (safe_strcmp(no_label, DriveLabel.Table[ComboIndex]) == 0) {
|
2011-11-24 20:02:14 +00:00
|
|
|
if (HumanReadableSize < 1.0) {
|
|
|
|
HumanReadableSize *= 1024.0;
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
// If we're beneath the tolerance, round proposed label to an integer, if not, show one decimal point
|
|
|
|
if (fabs(HumanReadableSize / ceil(HumanReadableSize) - 1.0) < PROPOSEDLABEL_TOLERANCE) {
|
|
|
|
safe_sprintf(proposed_label, sizeof(proposed_label), "%0.0f%s", ceil(HumanReadableSize), suffix[i]);
|
|
|
|
} else {
|
|
|
|
safe_sprintf(proposed_label, sizeof(proposed_label), "%0.1f%s", HumanReadableSize, suffix[i]);
|
2011-11-24 02:24:50 +00:00
|
|
|
}
|
2011-11-24 20:02:14 +00:00
|
|
|
SetWindowTextA(hLabel, proposed_label);
|
2011-11-24 02:24:50 +00:00
|
|
|
} else {
|
|
|
|
SetWindowTextA(hLabel, DriveLabel.Table[ComboIndex]);
|
|
|
|
}
|
|
|
|
|
2011-11-18 21:46:34 +00:00
|
|
|
return TRUE;
|
2011-11-17 01:43:06 +00:00
|
|
|
}
|
2011-11-13 20:53:23 +00:00
|
|
|
|
2011-11-23 12:27:51 +00:00
|
|
|
/*
|
|
|
|
* Create a partition table
|
|
|
|
*/
|
2011-12-01 17:20:52 +00:00
|
|
|
BOOL CreatePartition(HANDLE hDrive)
|
2011-11-23 12:27:51 +00:00
|
|
|
{
|
|
|
|
BYTE layout[sizeof(DRIVE_LAYOUT_INFORMATION_EX) + 3*sizeof(PARTITION_INFORMATION_EX)] = {0};
|
|
|
|
PDRIVE_LAYOUT_INFORMATION_EX DriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX)layout;
|
|
|
|
BOOL r;
|
|
|
|
DWORD size;
|
|
|
|
|
2011-12-08 00:22:13 +00:00
|
|
|
PrintStatus(0, "Partitioning...");
|
2011-11-23 12:27:51 +00:00
|
|
|
DriveLayoutEx->PartitionStyle = PARTITION_STYLE_MBR;
|
|
|
|
DriveLayoutEx->PartitionCount = 4; // Must be multiple of 4 for MBR
|
|
|
|
DriveLayoutEx->Mbr.Signature = GetTickCount();
|
|
|
|
DriveLayoutEx->PartitionEntry[0].PartitionStyle = PARTITION_STYLE_MBR;
|
2011-11-25 01:30:41 +00:00
|
|
|
DriveLayoutEx->PartitionEntry[0].StartingOffset.QuadPart =
|
|
|
|
SelectedDrive.Geometry.BytesPerSector * SelectedDrive.Geometry.SectorsPerTrack;
|
|
|
|
DriveLayoutEx->PartitionEntry[0].PartitionLength.QuadPart = SelectedDrive.DiskSize -
|
|
|
|
DriveLayoutEx->PartitionEntry[0].StartingOffset.QuadPart;
|
2011-11-23 12:27:51 +00:00
|
|
|
DriveLayoutEx->PartitionEntry[0].PartitionNumber = 1;
|
|
|
|
DriveLayoutEx->PartitionEntry[0].RewritePartition = TRUE;
|
2011-11-25 01:30:41 +00:00
|
|
|
DriveLayoutEx->PartitionEntry[0].Mbr.HiddenSectors = SelectedDrive.Geometry.SectorsPerTrack;
|
2011-12-09 01:39:13 +00:00
|
|
|
switch (ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))) {
|
2011-11-25 01:30:41 +00:00
|
|
|
case FS_FAT16:
|
2011-11-29 20:25:29 +00:00
|
|
|
DriveLayoutEx->PartitionEntry[0].Mbr.PartitionType = 0x0e; // FAT16 LBA
|
2011-11-25 01:30:41 +00:00
|
|
|
break;
|
|
|
|
case FS_NTFS:
|
2011-12-01 02:56:44 +00:00
|
|
|
case FS_EXFAT:
|
|
|
|
// TODO: but how do we set this thing up afterwards?
|
2011-11-29 20:25:29 +00:00
|
|
|
DriveLayoutEx->PartitionEntry[0].Mbr.PartitionType = 0x07; // NTFS
|
2011-11-25 01:30:41 +00:00
|
|
|
break;
|
|
|
|
default:
|
2011-11-29 20:25:29 +00:00
|
|
|
DriveLayoutEx->PartitionEntry[0].Mbr.PartitionType = 0x0c; // FAT32 LBA
|
2011-11-25 01:30:41 +00:00
|
|
|
break;
|
|
|
|
}
|
2011-11-24 20:26:20 +00:00
|
|
|
// For the remaining partitions, PartitionStyle & PartitionType have already
|
|
|
|
// been zeroed => set to MBR/unused
|
2011-11-23 12:27:51 +00:00
|
|
|
|
|
|
|
r = DeviceIoControl(hDrive, IOCTL_DISK_SET_DRIVE_LAYOUT_EX,
|
|
|
|
layout, sizeof(layout), NULL, 0, &size, NULL );
|
|
|
|
if (!r) {
|
|
|
|
uprintf("IOCTL_DISK_SET_DRIVE_LAYOUT_EX failed: %s\n", WindowsErrorString());
|
|
|
|
safe_closehandle(hDrive);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
/*
|
2011-11-21 17:06:17 +00:00
|
|
|
* Refresh the list of USB devices
|
2011-11-13 20:53:23 +00:00
|
|
|
*/
|
2011-11-17 01:43:06 +00:00
|
|
|
static BOOL GetUSBDevices(void)
|
|
|
|
{
|
|
|
|
BOOL r;
|
|
|
|
HDEVINFO dev_info = NULL;
|
|
|
|
SP_DEVINFO_DATA dev_info_data;
|
|
|
|
SP_DEVICE_INTERFACE_DATA devint_data;
|
|
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA_A devint_detail_data;
|
2011-11-20 22:49:55 +00:00
|
|
|
STORAGE_DEVICE_NUMBER_REDEF device_number;
|
2011-11-17 01:43:06 +00:00
|
|
|
DWORD size, i, j, datatype;
|
|
|
|
HANDLE hDrive;
|
|
|
|
char drive_letter;
|
2011-11-18 02:00:19 +00:00
|
|
|
char *label, entry[MAX_PATH], buffer[MAX_PATH];
|
2011-11-20 02:34:15 +00:00
|
|
|
const char* usbstor_name = "USBSTOR";
|
2011-12-02 00:14:09 +00:00
|
|
|
GUID _GUID_DEVINTERFACE_DISK = // only known to some...
|
|
|
|
{ 0x53f56307L, 0xb6bf, 0x11d0, {0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b} };
|
2011-11-17 01:43:06 +00:00
|
|
|
|
|
|
|
IGNORE_RETVAL(ComboBox_ResetContent(hDeviceList));
|
2011-11-21 20:12:23 +00:00
|
|
|
StrArrayClear(&DriveID);
|
2011-11-24 02:24:50 +00:00
|
|
|
StrArrayClear(&DriveLabel);
|
2011-11-17 01:43:06 +00:00
|
|
|
|
2011-12-02 00:14:09 +00:00
|
|
|
dev_info = SetupDiGetClassDevsA(&_GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
|
2011-11-17 01:43:06 +00:00
|
|
|
if (dev_info == INVALID_HANDLE_VALUE) {
|
2011-11-21 17:06:17 +00:00
|
|
|
uprintf("SetupDiGetClassDevs (Interface) failed: %d\n", WindowsErrorString());
|
2011-11-17 01:43:06 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev_info_data.cbSize = sizeof(dev_info_data);
|
|
|
|
for (i=0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
|
|
|
|
memset(buffer, 0, sizeof(buffer));
|
|
|
|
if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_ENUMERATOR_NAME,
|
|
|
|
&datatype, (LPBYTE)buffer, sizeof(buffer), &size)) {
|
2011-11-21 17:06:17 +00:00
|
|
|
uprintf("SetupDiGetDeviceRegistryProperty (Enumerator Name) failed: %d\n", WindowsErrorString());
|
2011-11-17 01:43:06 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-11-20 02:34:15 +00:00
|
|
|
if (safe_strcmp(buffer, usbstor_name) != 0)
|
2011-11-17 01:43:06 +00:00
|
|
|
continue;
|
|
|
|
memset(buffer, 0, sizeof(buffer));
|
|
|
|
if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_FRIENDLYNAME,
|
|
|
|
&datatype, (LPBYTE)buffer, sizeof(buffer), &size)) {
|
2011-11-21 17:06:17 +00:00
|
|
|
uprintf("SetupDiGetDeviceRegistryProperty (Friendly Name) failed: %d\n", WindowsErrorString());
|
2011-11-17 01:43:06 +00:00
|
|
|
continue;
|
|
|
|
}
|
2011-11-23 12:27:51 +00:00
|
|
|
uprintf("Found drive '%s'\n", buffer);
|
2011-11-17 01:43:06 +00:00
|
|
|
|
|
|
|
devint_data.cbSize = sizeof(devint_data);
|
2011-11-18 01:58:08 +00:00
|
|
|
hDrive = INVALID_HANDLE_VALUE;
|
2011-11-17 01:43:06 +00:00
|
|
|
devint_detail_data = NULL;
|
2011-11-18 01:58:08 +00:00
|
|
|
for (j=0; ;j++) {
|
|
|
|
safe_closehandle(hDrive);
|
|
|
|
safe_free(devint_detail_data);
|
|
|
|
|
2011-12-02 00:14:09 +00:00
|
|
|
if (!SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data, &_GUID_DEVINTERFACE_DISK, j, &devint_data)) {
|
2011-11-17 01:43:06 +00:00
|
|
|
if(GetLastError() != ERROR_NO_MORE_ITEMS) {
|
2011-11-21 17:06:17 +00:00
|
|
|
uprintf("SetupDiEnumDeviceInterfaces failed: %s\n", WindowsErrorString());
|
2011-11-17 01:43:06 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, NULL, 0, &size, NULL)) {
|
|
|
|
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
|
|
|
devint_detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)calloc(1, size);
|
|
|
|
if (devint_detail_data == NULL) {
|
|
|
|
uprintf("unable to allocate data for SP_DEVICE_INTERFACE_DETAIL_DATA\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
devint_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
|
|
|
|
} else {
|
2011-11-21 17:06:17 +00:00
|
|
|
uprintf("SetupDiGetDeviceInterfaceDetail (dummy) failed: %s\n", WindowsErrorString());
|
2011-11-17 01:43:06 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, devint_detail_data, size, &size, NULL)) {
|
2011-11-21 17:06:17 +00:00
|
|
|
uprintf("SetupDiGetDeviceInterfaceDetail (actual) failed: %s\n", WindowsErrorString());
|
2011-11-17 01:43:06 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
hDrive = CreateFileA(devint_detail_data->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
|
|
|
if(hDrive == INVALID_HANDLE_VALUE) {
|
2011-11-21 17:06:17 +00:00
|
|
|
uprintf("could not open '%s': %s\n", devint_detail_data->DevicePath, WindowsErrorString());
|
2011-11-17 01:43:06 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-11-18 21:46:34 +00:00
|
|
|
memset(&device_number, 0, sizeof(device_number));
|
2011-11-17 01:43:06 +00:00
|
|
|
r = DeviceIoControl(hDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER,
|
2011-11-18 21:46:34 +00:00
|
|
|
NULL, 0, &device_number, sizeof(device_number), &size, NULL );
|
2011-11-18 01:58:08 +00:00
|
|
|
if (!r || size <= 0) {
|
2011-11-21 17:06:17 +00:00
|
|
|
uprintf("IOCTL_STORAGE_GET_DEVICE_NUMBER (GetUSBDevices) failed: %s\n", WindowsErrorString());
|
2011-11-18 01:58:08 +00:00
|
|
|
continue;
|
|
|
|
}
|
2011-11-17 01:43:06 +00:00
|
|
|
|
2011-11-23 12:27:51 +00:00
|
|
|
if (GetDriveLabel(device_number.DeviceNumber + DRIVE_INDEX_MIN, &drive_letter, &label)) {
|
2011-11-24 02:24:50 +00:00
|
|
|
// Must ensure that the combo box is UNSORTED for indexes to be the same
|
|
|
|
StrArrayAdd(&DriveID, buffer);
|
|
|
|
StrArrayAdd(&DriveLabel, label);
|
|
|
|
safe_sprintf(entry, sizeof(entry), "%s (%c:)", label, drive_letter);
|
2011-11-23 12:27:51 +00:00
|
|
|
IGNORE_RETVAL(ComboBox_SetItemData(hDeviceList, ComboBox_AddStringU(hDeviceList, entry),
|
|
|
|
device_number.DeviceNumber + DRIVE_INDEX_MIN));
|
2011-11-24 02:24:50 +00:00
|
|
|
safe_closehandle(hDrive);
|
|
|
|
safe_free(devint_detail_data);
|
|
|
|
break;
|
2011-11-17 01:43:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
IGNORE_RETVAL(ComboBox_SetCurSel(hDeviceList, 0));
|
2011-11-29 20:25:29 +00:00
|
|
|
SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE<<16) | IDC_DEVICE, 0);
|
2011-12-09 12:57:32 +00:00
|
|
|
SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE<<16) | IDC_FILESYSTEM,
|
|
|
|
ComboBox_GetCurSel(hFileSystem));
|
2011-11-17 01:43:06 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-12-09 01:39:13 +00:00
|
|
|
/*
|
|
|
|
* Set up progress bar real estate allocation
|
|
|
|
*/
|
|
|
|
static void InitProgress(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
float last_end = 0.0f, slots_discrete = 0.0f, slots_analog = 0.0f;
|
|
|
|
|
|
|
|
memset(&nb_slots, 0, sizeof(nb_slots));
|
|
|
|
memset(&slot_end, 0, sizeof(slot_end));
|
|
|
|
previous_end = 0.0f;
|
|
|
|
|
|
|
|
nb_slots[OP_ZERO_MBR] = 1;
|
|
|
|
if (IsChecked(IDC_BADBLOCKS)) {
|
|
|
|
nb_slots[OP_BADBLOCKS] = -1;
|
|
|
|
}
|
|
|
|
if (IsChecked(IDC_DOS)) {
|
|
|
|
// TODO: this should reflect the number of files to copy +1 for PBR writing
|
|
|
|
nb_slots[OP_DOS] = 3+1;
|
|
|
|
}
|
|
|
|
nb_slots[OP_PARTITION] = 1;
|
|
|
|
nb_slots[OP_FIX_MBR] = 1;
|
2011-12-09 12:57:32 +00:00
|
|
|
nb_slots[OP_CREATE_FS] =
|
2011-12-09 01:39:13 +00:00
|
|
|
nb_steps[ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))];
|
|
|
|
if (!IsChecked(IDC_QUICKFORMAT)) {
|
2011-12-09 12:57:32 +00:00
|
|
|
nb_slots[OP_FORMAT] = -1;
|
2011-12-09 01:39:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<OP_MAX; i++) {
|
|
|
|
if (nb_slots[i] > 0) {
|
|
|
|
slots_discrete += nb_slots[i]*1.0f;
|
|
|
|
}
|
|
|
|
if (nb_slots[i] < 0) {
|
|
|
|
slots_analog += nb_slots[i]*1.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<OP_MAX; i++) {
|
|
|
|
if (nb_slots[i] == 0) {
|
|
|
|
slot_end[i+1] = last_end;
|
|
|
|
} else if (nb_slots[i] > 0) {
|
|
|
|
slot_end[i+1] = last_end + (1.0f * nb_slots[i]);
|
|
|
|
} else if (nb_slots[i] < 0) {
|
|
|
|
slot_end[i+1] = last_end + (( (100.0f-slots_discrete) * nb_slots[i]) / slots_analog);
|
|
|
|
}
|
|
|
|
last_end = slot_end[i+1];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Is there's no analog, adjust our discrete ends to fill the whole bar */
|
|
|
|
if (slots_analog == 0.0f) {
|
|
|
|
for (i=0; i<OP_MAX; i++) {
|
|
|
|
slot_end[i+1] *= 100.0f / slots_discrete;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Position the progress bar within each operation range
|
|
|
|
*/
|
|
|
|
void UpdateProgress(int op, float percent)
|
|
|
|
{
|
|
|
|
int pos;
|
|
|
|
|
|
|
|
if ((op < 0) || (op > OP_MAX)) {
|
|
|
|
uprintf("UpdateProgress: invalid op %d\n", op);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (percent > 100.1f) {
|
|
|
|
uprintf("UpdateProgress(%d): invalid percentage %0.2f\n", op, percent);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ((percent < 0.0f) && (nb_slots[op] <= 0)) {
|
|
|
|
uprintf("UpdateProgress(%d): error negative percentage sent for negative slot value\n", op);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (nb_slots[op] == 0)
|
|
|
|
return;
|
|
|
|
if (previous_end < slot_end[op]) {
|
|
|
|
previous_end = slot_end[op];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (percent < 0.0f) {
|
|
|
|
// Negative means advance one slot (1.0%) - requires a positive slot allocation
|
|
|
|
previous_end += (slot_end[op+1] - slot_end[op]) / (1.0f * nb_slots[op]);
|
|
|
|
pos = (int)(previous_end / 100.0f * MAX_PROGRESS);
|
|
|
|
} else {
|
|
|
|
pos = (int)((previous_end + ((slot_end[op+1] - previous_end) * (percent / 100.0f))) / 100.0f * MAX_PROGRESS);
|
|
|
|
}
|
|
|
|
if (pos > MAX_PROGRESS) {
|
|
|
|
uprintf("UpdateProgress(%d): rounding error - pos %d is greater than %d\n", op, pos, MAX_PROGRESS);
|
|
|
|
pos = MAX_PROGRESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
SendMessage(hProgress, PBM_SETPOS, (WPARAM)pos, 0);
|
|
|
|
}
|
|
|
|
|
2011-12-01 17:54:35 +00:00
|
|
|
/*
|
|
|
|
* Toggle controls according to operation
|
|
|
|
*/
|
2011-11-28 01:32:18 +00:00
|
|
|
static void EnableControls(BOOL bEnable)
|
|
|
|
{
|
2011-12-02 00:14:09 +00:00
|
|
|
int fs;
|
|
|
|
|
2011-11-28 01:32:18 +00:00
|
|
|
EnableWindow(GetDlgItem(hMainDialog, IDC_DEVICE), bEnable);
|
|
|
|
EnableWindow(GetDlgItem(hMainDialog, IDC_CAPACITY), bEnable);
|
|
|
|
EnableWindow(GetDlgItem(hMainDialog, IDC_FILESYSTEM), bEnable);
|
2011-11-29 20:25:29 +00:00
|
|
|
EnableWindow(GetDlgItem(hMainDialog, IDC_CLUSTERSIZE), bEnable);
|
2011-11-28 01:32:18 +00:00
|
|
|
EnableWindow(GetDlgItem(hMainDialog, IDC_LABEL), bEnable);
|
|
|
|
EnableWindow(GetDlgItem(hMainDialog, IDC_QUICKFORMAT), bEnable);
|
2011-12-02 00:14:09 +00:00
|
|
|
if (bEnable) {
|
|
|
|
fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
|
|
|
|
EnableWindow(GetDlgItem(hMainDialog, IDC_DOS), (fs == FS_FAT16) || (fs == FS_FAT32));
|
|
|
|
} else {
|
|
|
|
EnableWindow(GetDlgItem(hMainDialog, IDC_DOS), FALSE);
|
|
|
|
}
|
2011-12-06 02:23:28 +00:00
|
|
|
EnableWindow(GetDlgItem(hMainDialog, IDC_BADBLOCKS), bEnable);
|
2011-11-28 01:32:18 +00:00
|
|
|
EnableWindow(GetDlgItem(hMainDialog, IDC_ABOUT), bEnable);
|
|
|
|
EnableWindow(GetDlgItem(hMainDialog, IDC_START), bEnable);
|
|
|
|
SetDlgItemTextA(hMainDialog, IDCANCEL, bEnable?"Close":"Cancel");
|
|
|
|
}
|
|
|
|
|
2011-12-08 12:14:21 +00:00
|
|
|
/*
|
|
|
|
* Timer in the right part of the status area
|
|
|
|
*/
|
|
|
|
static void CALLBACK ClockTimer(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
|
|
|
|
{
|
|
|
|
timer++;
|
|
|
|
safe_sprintf(szTimer, sizeof(szTimer), "%02d:%02d:%02d",
|
|
|
|
timer/3600, (timer%3600)/60, timer%60);
|
|
|
|
SendMessageA(GetDlgItem(hWnd, IDC_STATUS), SB_SETTEXTA, SBT_OWNERDRAW | 1, (LPARAM)szTimer);
|
|
|
|
}
|
|
|
|
|
2011-11-17 01:43:06 +00:00
|
|
|
/*
|
2011-11-21 17:06:17 +00:00
|
|
|
* Main dialog callback
|
|
|
|
*/
|
2011-11-18 01:58:08 +00:00
|
|
|
static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
2011-11-13 20:53:23 +00:00
|
|
|
{
|
2011-11-21 17:06:17 +00:00
|
|
|
HDC hDC;
|
2011-12-03 23:51:07 +00:00
|
|
|
HICON hSmallIcon, hBigIcon;
|
2011-12-08 12:14:21 +00:00
|
|
|
DRAWITEMSTRUCT* pDI;
|
2011-12-02 00:14:09 +00:00
|
|
|
int nDeviceIndex, fs;
|
2011-11-27 23:40:28 +00:00
|
|
|
DWORD DeviceNum;
|
2011-11-24 02:24:50 +00:00
|
|
|
char str[MAX_PATH], tmp[128];
|
2011-11-27 23:40:28 +00:00
|
|
|
static uintptr_t format_thid = -1L;
|
2011-12-09 01:39:13 +00:00
|
|
|
static HWND hDOS;
|
2011-12-02 00:14:09 +00:00
|
|
|
static UINT uDOSChecked = BST_CHECKED;
|
2011-11-21 17:06:17 +00:00
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
switch (message) {
|
|
|
|
|
|
|
|
case WM_DEVICECHANGE:
|
2011-11-28 01:32:18 +00:00
|
|
|
if ( (format_thid == -1L) &&
|
|
|
|
((wParam == DBT_DEVICEARRIVAL) || (wParam == DBT_DEVICEREMOVECOMPLETE)) ) {
|
2011-11-26 00:25:04 +00:00
|
|
|
GetUSBDevices();
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
|
|
|
break;
|
2011-11-13 20:53:23 +00:00
|
|
|
|
|
|
|
case WM_INITDIALOG:
|
2011-11-21 17:06:17 +00:00
|
|
|
hMainDialog = hDlg;
|
2011-11-17 01:43:06 +00:00
|
|
|
hDeviceList = GetDlgItem(hDlg, IDC_DEVICE);
|
2011-11-18 21:46:34 +00:00
|
|
|
hCapacity = GetDlgItem(hDlg, IDC_CAPACITY);
|
2011-11-19 01:30:20 +00:00
|
|
|
hFileSystem = GetDlgItem(hDlg, IDC_FILESYSTEM);
|
2011-11-28 20:05:34 +00:00
|
|
|
hClusterSize = GetDlgItem(hDlg, IDC_CLUSTERSIZE);
|
2011-11-24 02:24:50 +00:00
|
|
|
hLabel = GetDlgItem(hDlg, IDC_LABEL);
|
2011-11-27 23:40:28 +00:00
|
|
|
hProgress = GetDlgItem(hDlg, IDC_PROGRESS);
|
2011-12-02 00:14:09 +00:00
|
|
|
hDOS = GetDlgItem(hDlg, IDC_DOS);
|
2011-11-21 17:06:17 +00:00
|
|
|
// High DPI scaling
|
|
|
|
hDC = GetDC(hDlg);
|
|
|
|
fScale = GetDeviceCaps(hDC, LOGPIXELSX) / 96.0f;
|
|
|
|
ReleaseDC(hDlg, hDC);
|
2011-12-03 23:51:07 +00:00
|
|
|
// Create the title bar icon
|
|
|
|
hSmallIcon = (HICON)LoadImage(hMainInstance, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, 0);
|
|
|
|
SendMessage (hDlg, WM_SETICON, ICON_SMALL, (LPARAM)hSmallIcon);
|
|
|
|
hBigIcon = (HICON)LoadImage(hMainInstance, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 32, 32, 0);
|
|
|
|
SendMessage (hDlg, WM_SETICON, ICON_BIG, (LPARAM)hBigIcon);
|
2011-11-21 17:06:17 +00:00
|
|
|
// Create the status line
|
2011-12-08 12:14:21 +00:00
|
|
|
CreateStatusBar();
|
2011-12-09 01:39:13 +00:00
|
|
|
// Use maximum granularity for the progress bar
|
|
|
|
SendMessage(hProgress, PBM_SETRANGE, 0, MAX_PROGRESS<<16);
|
2011-11-26 00:25:04 +00:00
|
|
|
// Create the string array
|
2011-11-24 02:24:50 +00:00
|
|
|
StrArrayCreate(&DriveID, MAX_DRIVES);
|
|
|
|
StrArrayCreate(&DriveLabel, MAX_DRIVES);
|
2011-12-02 00:14:09 +00:00
|
|
|
// Set the quick format & create DOS disk checkboxes
|
2011-11-26 00:25:04 +00:00
|
|
|
CheckDlgButton(hDlg, IDC_QUICKFORMAT, BST_CHECKED);
|
2011-12-02 00:14:09 +00:00
|
|
|
CheckDlgButton(hDlg, IDC_DOS, BST_CHECKED);
|
2011-11-17 01:43:06 +00:00
|
|
|
GetUSBDevices();
|
2011-11-13 20:53:23 +00:00
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
|
2011-12-08 12:14:21 +00:00
|
|
|
// Change the colour of the version text in the status bar
|
|
|
|
case WM_DRAWITEM:
|
|
|
|
if (wParam == IDC_STATUS) {
|
|
|
|
pDI = (DRAWITEMSTRUCT*)lParam;
|
|
|
|
SetBkMode(pDI->hDC, TRANSPARENT);
|
|
|
|
SetTextColor(pDI->hDC, GetSysColor(COLOR_3DSHADOW));
|
|
|
|
pDI->rcItem.top += (int)(2.0f * fScale);
|
|
|
|
pDI->rcItem.left += (int)(4.0f * fScale);
|
|
|
|
DrawTextExA(pDI->hDC, szTimer, -1, &pDI->rcItem, DT_LEFT, NULL);
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
case WM_COMMAND:
|
|
|
|
switch(LOWORD(wParam)) {
|
2011-11-21 20:12:23 +00:00
|
|
|
case IDOK: // close application
|
|
|
|
case IDCANCEL:
|
2011-11-28 01:32:18 +00:00
|
|
|
if (format_thid != -1L) {
|
|
|
|
if (MessageBoxA(hMainDialog, "Cancelling may leave the device in an UNUSABLE state.\r\n"
|
|
|
|
"If you are sure you want to cancel, click YES. Otherwise, click NO.",
|
2011-11-28 12:37:58 +00:00
|
|
|
RUFUS_CANCELBOX_TITLE, MB_YESNO|MB_ICONWARNING) == IDYES) {
|
|
|
|
// Operation may have completed in the meantime
|
2011-11-28 01:32:18 +00:00
|
|
|
if (format_thid != -1L) {
|
2011-11-28 12:37:58 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED;
|
2011-12-08 00:22:13 +00:00
|
|
|
PrintStatus(0, "Cancelling - please wait...");
|
2011-11-28 01:32:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
2011-11-21 20:12:23 +00:00
|
|
|
PostQuitMessage(0);
|
|
|
|
StrArrayDestroy(&DriveID);
|
2011-11-24 02:24:50 +00:00
|
|
|
StrArrayDestroy(&DriveLabel);
|
2011-11-21 20:25:32 +00:00
|
|
|
DestroyAllTooltips();
|
2011-11-21 20:12:23 +00:00
|
|
|
EndDialog(hDlg, 0);
|
|
|
|
break;
|
2011-11-21 17:06:17 +00:00
|
|
|
case IDC_ABOUT:
|
|
|
|
CreateAboutBox();
|
|
|
|
break;
|
2011-11-24 02:24:50 +00:00
|
|
|
case IDC_DEVICE:
|
2011-11-18 23:41:28 +00:00
|
|
|
switch (HIWORD(wParam)) {
|
|
|
|
case CBN_SELCHANGE:
|
2011-12-08 00:22:13 +00:00
|
|
|
PrintStatus(0, "%d device%s found.", ComboBox_GetCount(hDeviceList),
|
2011-11-24 02:24:50 +00:00
|
|
|
(ComboBox_GetCount(hDeviceList)!=1)?"s":"");
|
|
|
|
PopulateProperties(ComboBox_GetCurSel(hDeviceList));
|
2011-11-18 23:41:28 +00:00
|
|
|
break;
|
|
|
|
}
|
2011-11-27 23:40:28 +00:00
|
|
|
break;
|
2011-12-01 02:56:44 +00:00
|
|
|
case IDC_FILESYSTEM:
|
|
|
|
switch (HIWORD(wParam)) {
|
|
|
|
case CBN_SELCHANGE:
|
2011-12-02 00:14:09 +00:00
|
|
|
fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
|
|
|
|
SetClusterSizes(fs);
|
|
|
|
// Disable/Restore the DOS checkbox according to FS
|
|
|
|
if ((fs == FS_FAT16) || (fs == FS_FAT32)) {
|
|
|
|
if (!IsWindowEnabled(hDOS)) {
|
|
|
|
EnableWindow(hDOS, TRUE);
|
|
|
|
CheckDlgButton(hDlg, IDC_DOS, uDOSChecked);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (IsWindowEnabled(hDOS)) {
|
|
|
|
uDOSChecked = IsDlgButtonChecked(hMainDialog, IDC_DOS);
|
|
|
|
CheckDlgButton(hDlg, IDC_DOS, BST_UNCHECKED);
|
|
|
|
EnableWindow(hDOS, FALSE);
|
|
|
|
}
|
|
|
|
}
|
2011-12-01 02:56:44 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2011-11-23 12:27:51 +00:00
|
|
|
case IDC_START:
|
2011-11-27 23:40:28 +00:00
|
|
|
if (format_thid != -1L) {
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
2011-11-23 12:27:51 +00:00
|
|
|
nDeviceIndex = ComboBox_GetCurSel(hDeviceList);
|
|
|
|
if (nDeviceIndex != CB_ERR) {
|
2011-11-24 02:24:50 +00:00
|
|
|
GetWindowTextA(hDeviceList, tmp, sizeof(tmp));
|
2011-11-28 01:32:18 +00:00
|
|
|
safe_sprintf(str, sizeof(str), "WARNING: ALL DATA ON DEVICE %s\r\nWILL BE DESTROYED.\r\n"
|
|
|
|
"To continue with this operation, click OK. To quit click CANCEL.", tmp);
|
2011-11-24 02:24:50 +00:00
|
|
|
if (MessageBoxA(hMainDialog, str, "Rufus", MB_OKCANCEL|MB_ICONWARNING) == IDOK) {
|
2011-11-28 01:32:18 +00:00
|
|
|
// Disable all controls except cancel
|
|
|
|
EnableControls(FALSE);
|
2011-11-27 23:40:28 +00:00
|
|
|
DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex);
|
2011-11-28 12:37:58 +00:00
|
|
|
FormatStatus = 0;
|
2011-12-09 01:39:13 +00:00
|
|
|
InitProgress();
|
2011-11-27 23:40:28 +00:00
|
|
|
format_thid = _beginthread(FormatThread, 0, (void*)(uintptr_t)DeviceNum);
|
|
|
|
if (format_thid == -1L) {
|
|
|
|
uprintf("Unable to start formatting thread");
|
2011-12-04 19:47:27 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_START_THREAD);
|
2011-11-28 12:37:58 +00:00
|
|
|
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0);
|
2011-11-27 23:40:28 +00:00
|
|
|
}
|
2011-12-08 12:14:21 +00:00
|
|
|
timer = 0;
|
|
|
|
safe_sprintf(szTimer, sizeof(szTimer), "00:00:00");
|
|
|
|
SendMessageA(GetDlgItem(hMainDialog, IDC_STATUS), SB_SETTEXTA,
|
|
|
|
SBT_OWNERDRAW | 1, (LPARAM)szTimer);
|
2011-12-09 01:39:13 +00:00
|
|
|
SetTimer(hMainDialog, TID_APP_TIMER, 1000, ClockTimer);
|
2011-11-24 02:24:50 +00:00
|
|
|
}
|
2011-11-23 12:27:51 +00:00
|
|
|
}
|
2011-11-27 23:40:28 +00:00
|
|
|
break;
|
2011-11-13 20:53:23 +00:00
|
|
|
default:
|
|
|
|
return (INT_PTR)FALSE;
|
|
|
|
}
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
|
|
|
|
case WM_CLOSE:
|
2011-11-28 01:32:18 +00:00
|
|
|
if (format_thid != -1L) {
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
2011-11-13 20:53:23 +00:00
|
|
|
PostQuitMessage(0);
|
|
|
|
break;
|
|
|
|
|
2011-11-27 23:40:28 +00:00
|
|
|
case UM_FORMAT_COMPLETED:
|
|
|
|
format_thid = -1L;
|
2011-12-08 12:14:21 +00:00
|
|
|
// Stop the timer
|
2011-12-09 01:39:13 +00:00
|
|
|
KillTimer(hMainDialog, TID_APP_TIMER);
|
2011-11-28 12:37:58 +00:00
|
|
|
// Close the cancel MessageBox if active
|
|
|
|
SendMessage(FindWindowA(MAKEINTRESOURCEA(32770), RUFUS_CANCELBOX_TITLE), WM_COMMAND, IDNO, 0);
|
2011-11-28 01:32:18 +00:00
|
|
|
EnableControls(TRUE);
|
2011-11-29 20:25:29 +00:00
|
|
|
GetUSBDevices();
|
2011-12-04 19:47:27 +00:00
|
|
|
if (!IS_ERROR(FormatStatus)) {
|
2011-12-08 00:22:13 +00:00
|
|
|
PrintStatus(0, "DONE");
|
2011-12-04 19:47:27 +00:00
|
|
|
} else if (SCODE_CODE(FormatStatus) == ERROR_CANCELLED) {
|
2011-12-08 00:22:13 +00:00
|
|
|
PrintStatus(0, "Cancelled");
|
2011-12-04 19:47:27 +00:00
|
|
|
Notification(MSG_INFO, "Cancelled", "Operation cancelled by the user.");
|
|
|
|
} else {
|
2011-12-08 00:22:13 +00:00
|
|
|
PrintStatus(0, "FAILED");
|
2011-12-04 19:47:27 +00:00
|
|
|
Notification(MSG_ERROR, "Error", "Error: %s", StrError(FormatStatus));
|
|
|
|
}
|
2011-12-09 12:57:32 +00:00
|
|
|
if (FormatStatus) {
|
|
|
|
SendMessage(hProgress, PBM_SETPOS, 0, 0);
|
|
|
|
} else {
|
|
|
|
// This is the only way to achieve instantenous progress transition
|
|
|
|
SendMessage(hProgress, PBM_SETRANGE, 0, (MAX_PROGRESS+1)<<16);
|
|
|
|
SendMessage(hProgress, PBM_SETPOS, (MAX_PROGRESS+1), 0);
|
|
|
|
SendMessage(hProgress, PBM_SETRANGE, 0, MAX_PROGRESS<<16);
|
|
|
|
}
|
2011-11-27 23:40:28 +00:00
|
|
|
return (INT_PTR)TRUE;
|
2011-11-13 20:53:23 +00:00
|
|
|
}
|
|
|
|
return (INT_PTR)FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Application Entrypoint
|
|
|
|
*/
|
|
|
|
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
|
|
|
{
|
|
|
|
HANDLE mutex = NULL;
|
|
|
|
HWND hDlg = NULL;
|
|
|
|
MSG msg;
|
|
|
|
|
2011-11-19 19:08:23 +00:00
|
|
|
uprintf("*** RUFUS INIT ***\n");
|
2011-11-17 01:43:06 +00:00
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
// Prevent 2 applications from running at the same time
|
2011-11-19 19:08:23 +00:00
|
|
|
mutex = CreateMutexA(NULL, TRUE, "Global/RUFUS");
|
2011-11-13 20:53:23 +00:00
|
|
|
if ((mutex == NULL) || (GetLastError() == ERROR_ALREADY_EXISTS))
|
|
|
|
{
|
2011-11-19 19:08:23 +00:00
|
|
|
MessageBoxA(NULL, "Another Rufus application is running.\n"
|
2011-11-13 20:53:23 +00:00
|
|
|
"Please close the first application before running another one.",
|
|
|
|
"Other instance detected", MB_ICONSTOP);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save instance of the application for further reference
|
2011-11-18 23:41:28 +00:00
|
|
|
hMainInstance = hInstance;
|
2011-11-13 20:53:23 +00:00
|
|
|
|
|
|
|
// Initialize COM for folder selection
|
|
|
|
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
|
|
|
|
|
|
// Create the main Window
|
2011-11-18 01:58:08 +00:00
|
|
|
if ( (hDlg = CreateDialogA(hInstance, MAKEINTRESOURCEA(IDD_DIALOG), NULL, MainCallback)) == NULL ) {
|
2011-11-13 20:53:23 +00:00
|
|
|
MessageBoxA(NULL, "Could not create Window", "DialogBox failure", MB_ICONSTOP);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
CenterDialog(hDlg);
|
|
|
|
ShowWindow(hDlg, SW_SHOWNORMAL);
|
|
|
|
UpdateWindow(hDlg);
|
|
|
|
|
|
|
|
// Do our own event processing
|
|
|
|
while(GetMessage(&msg, NULL, 0, 0)) {
|
|
|
|
TranslateMessage(&msg);
|
|
|
|
DispatchMessage(&msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
CloseHandle(mutex);
|
2011-11-19 19:08:23 +00:00
|
|
|
uprintf("*** RUFUS EXIT ***\n");
|
2011-11-13 20:53:23 +00:00
|
|
|
|
2011-11-21 20:12:23 +00:00
|
|
|
#ifdef _CRTDBG_MAP_ALLOC
|
|
|
|
_CrtDumpMemoryLeaks();
|
|
|
|
#endif
|
|
|
|
|
2011-11-13 20:53:23 +00:00
|
|
|
return 0;
|
|
|
|
}
|