[core] improved error and cancellation handling

* return standard Windows error codes where possible
* add custom error codes that follow the Windows error format
* automatically close cancel MessageBox if the process completes
This commit is contained in:
Pete Batard 2011-11-28 12:37:58 +00:00
parent 23b1f55338
commit d6c66e0d09
2 changed files with 51 additions and 44 deletions

84
rufus.c
View File

@ -84,7 +84,7 @@ struct {
static HWND hDeviceList, hCapacity, hFileSystem, hLabel;
static HWND hDeviceTooltip = NULL, hFSTooltip = NULL;
static StrArray DriveID, DriveLabel;
static DWORD FormatErr;
static DWORD FormatStatus;
#ifdef RUFUS_DEBUG
void _uprintf(const char *format, ...)
@ -209,7 +209,7 @@ static BOOL GetDriveHandle(DWORD DriveIndex, HANDLE* hDrive, char* DriveLetter,
safe_closehandle(*hDrive);
return FALSE;
}
uprintf("Warning: Opening %s drive for write access\n", drive_name);
uprintf("Caution: Opened %s drive for write access\n", drive_name);
}
break;
}
@ -217,7 +217,7 @@ static BOOL GetDriveHandle(DWORD DriveIndex, HANDLE* hDrive, char* DriveLetter,
}
if (DriveLetter != NULL) {
*DriveLetter = *drive?*drive:' '; // TODO: handle NUL char upstream
*DriveLetter = *drive?*drive:' ';
}
return (*hDrive != INVALID_HANDLE_VALUE);
@ -293,6 +293,7 @@ static BOOL GetDriveInfo(void)
if (DriveLayout->PartitionEntry[i].Mbr.PartitionType != PARTITION_ENTRY_UNUSED) {
uprintf("Partition #%d:\n", ++nb_partitions);
if (hFSTooltip == NULL) {
// TODO: provide all partitions FS on tooltip, not just the one
safe_sprintf(tmp, sizeof(tmp), "Current file system: %s (0x%02x)",
GetPartitionType(DriveLayout->PartitionEntry[i].Mbr.PartitionType),
DriveLayout->PartitionEntry[i].Mbr.PartitionType);
@ -508,7 +509,8 @@ static BOOLEAN __stdcall FormatExCallback(FILE_SYSTEM_CALLBACK_COMMAND Command,
DWORD* percent;
int task_number = 0;
if (FormatErr != 0) return FALSE;
if (IS_ERROR(FormatStatus))
return FALSE;
switch(Command) {
case FCC_PROGRESS:
@ -517,65 +519,60 @@ static BOOLEAN __stdcall FormatExCallback(FILE_SYSTEM_CALLBACK_COMMAND Command,
uprintf("%d percent completed.\n", *percent);
break;
case FCC_STRUCTURE_PROGRESS: // No progress on quick format
uprintf("format task %d/n completed.\n", ++task_number);
uprintf("Format task %d/? completed.\n", ++task_number);
break;
case FCC_DONE:
if(*(BOOLEAN*)Data == FALSE) {
uprintf("Error while formatting.\n");
FormatErr = FCC_DONE;
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_GEN_FAILURE;
}
break;
case FCC_INCOMPATIBLE_FILE_SYSTEM:
uprintf("Incompatible File System\n");
FormatErr = Command;
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INCOMPATIBLE_FS;
break;
case FCC_ACCESS_DENIED:
uprintf("Access denied\n");
FormatErr = Command;
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ACCESS_DENIED;
break;
case FCC_MEDIA_WRITE_PROTECTED:
uprintf("Media is write protected\n");
FormatErr = Command;
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_PROTECT;
break;
case FCC_VOLUME_IN_USE:
uprintf("Volume is in use\n");
FormatErr = Command;
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_DEVICE_IN_USE;
break;
case FCC_CANT_QUICK_FORMAT:
uprintf("Cannot quick format this volume\n");
FormatErr = Command;
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANT_QUICK_FORMAT;
break;
case FCC_BAD_LABEL:
uprintf("Bad label\n");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INVALID_LABEL;
break;
case FCC_OUTPUT:
uprintf("%s\n", ((PTEXTOUTPUT)Data)->Output);
break;
case FCC_CLUSTER_SIZE_TOO_SMALL:
uprintf("Allocation unit size is too small\n");
FormatErr = Command;
break;
case FCC_CLUSTER_SIZE_TOO_BIG:
uprintf("Allocation unit size is too big\n");
FormatErr = Command;
break;
case FCC_VOLUME_TOO_SMALL:
uprintf("Volume is too small\n");
FormatErr = Command;
case FCC_CLUSTER_SIZE_TOO_SMALL:
uprintf("Allocation unit size is too %s\n", FCC_CLUSTER_SIZE_TOO_BIG?"big":"small");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INVALID_CLUSTER_SIZE;
break;
case FCC_VOLUME_TOO_BIG:
uprintf("Volume is too big\n");
FormatErr = Command;
break;
case FCC_VOLUME_TOO_SMALL:
uprintf("Volume is too %s\n", FCC_VOLUME_TOO_BIG?"big":"small");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INVALID_VOLUME_SIZE;
case FCC_NO_MEDIA_IN_DRIVE:
uprintf("No media\n");
FormatErr = Command;
uprintf("No media in drive\n");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NO_MEDIA_IN_DRIVE;
break;
default:
uprintf("FormatExCallback: received unhandled command %X\n", Command);
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_SUPPORTED;
break;
}
return (FormatErr == 0);
return (!IS_ERROR(FormatStatus));
}
/*
@ -594,17 +591,14 @@ static BOOL FormatDrive(char DriveLetter)
PF_INIT_OR_OUT(FormatEx, fmifs);
// TODO: properly set MediaType
FormatErr = 0;
GetWindowTextW(hFileSystem, wFSType, ARRAYSIZE(wFSType));
GetWindowTextW(hLabel, wLabel, ARRAYSIZE(wLabel));
// TODO set sector size
pfFormatEx(wDriveRoot, RemovableMedia, wFSType, wLabel,
IsChecked(IDC_QUICKFORMAT), 4096, FormatExCallback);
if (FormatErr == 0) {
if (!IS_ERROR(FormatStatus)) {
uprintf("Format completed.\n");
r = TRUE;
} else {
uprintf("Format error: 0x%02x\n", FormatErr);
}
out:
@ -623,14 +617,14 @@ static void __cdecl FormatThread(void* param)
int i;
if (!GetDriveHandle(num, &hDrive, NULL, TRUE)) {
// TODO: use FormatErr to report an error
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
goto out;
}
r = CreatePartition(hDrive);
safe_closehandle(hDrive);
if (!r) {
// TODO: use FormatErr to report an error
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE;
goto out;
}
@ -643,12 +637,14 @@ static void __cdecl FormatThread(void* param)
}
if (i >= 10) {
uprintf("Unable to reopen drive post partitioning\n");
// TODO: use FormatErr to report an error
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
goto out;
}
safe_closehandle(hDrive);
if (!FormatDrive(drive_name[0])) {
// Error will be set by FormatDrive() in FormatStatus
uprintf("Format error: 0x%08X\n", FormatStatus);
goto out;
}
@ -855,13 +851,12 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
case IDOK: // close application
case IDCANCEL:
if (format_thid != -1L) {
// TODO: destroy MessageBox if operation completed while waiting
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.",
"Do you want to cancel?", MB_YESNO|MB_ICONWARNING) == IDYES) {
// Operation may have completed
RUFUS_CANCELBOX_TITLE, MB_YESNO|MB_ICONWARNING) == IDYES) {
// Operation may have completed in the meantime
if (format_thid != -1L) {
FormatErr = -1;
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED;
StatusPrintf("Cancelling - please wait...");
}
}
@ -886,7 +881,6 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
}
break;
case IDC_START:
// TODO: disable all controls and replace Close with Cancel
if (format_thid != -1L) {
return (INT_PTR)TRUE;
}
@ -904,10 +898,12 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
SendMessage(hProgress, PBM_SETMARQUEE, TRUE, 0);
}
DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex);
FormatStatus = 0;
format_thid = _beginthread(FormatThread, 0, (void*)(uintptr_t)DeviceNum);
if (format_thid == -1L) {
// TODO: handle error
uprintf("Unable to start formatting thread");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANT_START_THREAD;
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0);
}
}
}
@ -930,6 +926,8 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
case UM_FORMAT_COMPLETED:
format_thid = -1L;
// Close the cancel MessageBox if active
SendMessage(FindWindowA(MAKEINTRESOURCEA(32770), RUFUS_CANCELBOX_TITLE), WM_COMMAND, IDNO, 0);
if (IsChecked(IDC_QUICKFORMAT)) {
SendMessage(hProgress, PBM_SETMARQUEE, FALSE, 0);
SetWindowLongPtr(hProgress, GWL_STYLE, ProgressStyle);
@ -938,9 +936,9 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
SendMessage(hProgress, PBM_SETPOS, 101, 0);
SendMessage(hProgress, PBM_SETRANGE, 0, 100<<16);
}
SendMessage(hProgress, PBM_SETPOS, FormatErr?0:100, 0);
// TODO: report cancelled status
StatusPrintf(FormatErr?"FAILED":"DONE");
SendMessage(hProgress, PBM_SETPOS, FormatStatus?0:100, 0);
StatusPrintf(!IS_ERROR(FormatStatus)?"DONE":
((SCODE_CODE(FormatStatus)==ERROR_CANCELLED)?"Cancelled":"FAILED"));
EnableControls(TRUE);
return (INT_PTR)TRUE;
}

11
rufus.h
View File

@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <winioctl.h> // for MEDIA_TYPE
#include <winioctl.h> // for MEDIA_TYPE
#pragma once
@ -23,6 +23,7 @@
#define APP_VERSION "Rufus v1.0.0.1"
#define STR_NO_LABEL "NO_LABEL"
#define RUFUS_CANCELBOX_TITLE "Rufus - Cancellation"
#define DRIVE_INDEX_MIN 0x80
#define DRIVE_INDEX_MAX 0xC0
#define MAX_DRIVES 16
@ -213,3 +214,11 @@ typedef BOOLEAN (WINAPI* EnableVolumeCompression_t)(
WCHAR* DriveRoot,
ULONG CompressionFlags // FILE_SYSTEM_PROP_FLAG
);
/* Custom application errors */
#define FAC(f) (f<<16)
#define ERROR_INCOMPATIBLE_FS (APPLICATION_ERROR_MASK|0x1201)
#define ERROR_CANT_QUICK_FORMAT (APPLICATION_ERROR_MASK|0x1202)
#define ERROR_INVALID_CLUSTER_SIZE (APPLICATION_ERROR_MASK|0x1203)
#define ERROR_INVALID_VOLUME_SIZE (APPLICATION_ERROR_MASK|0x1204)
#define ERROR_CANT_START_THREAD (APPLICATION_ERROR_MASK|0x1205)