diff --git a/src/badblocks.c b/src/badblocks.c index 9be86761..48248632 100644 --- a/src/badblocks.c +++ b/src/badblocks.c @@ -361,14 +361,14 @@ static void print_status(void) percent = calc_percent((unsigned long) currently_testing, (unsigned long) num_blocks); percent = (percent/2.0f) + ((cur_op==OP_READ)? 50.0f : 0.0f); - PrintStatus(0, "PASS %d/%d(%c): %6.2f%% done. (%d/%d/%d errors)", + PrintStatus(0, "BB PASS %d/%d(%c): %0.2f%% done. (%d/%d/%d errors)", cur_pattern, nr_pattern, (cur_op==OP_READ)?'R':'W', percent, num_read_errors, num_write_errors, num_corruption_errors); - PostMessage(hMainDialog, UM_FORMAT_PROGRESS, (WPARAM)(DWORD)percent, (LPARAM)0); + UpdateProgress(OP_BADBLOCKS, (((cur_pattern-1)*100.0f) + percent) / nr_pattern); } static void CALLBACK alarm_intr(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) @@ -567,7 +567,7 @@ static unsigned int test_ro (HANDLE hDrive, blk_t last_block, static unsigned int test_rw(HANDLE hDrive, blk_t last_block, int block_size, blk_t first_block, unsigned int blocks_at_once) { unsigned char *buffer = NULL, *read_buffer; - const unsigned int patterns[] = {0xaa, 0x55, 0xff, 0x00}; + const unsigned int patterns[] = EXT2_RW_PATTERNS; const unsigned int *pattern; int i, tryout, got, pat_idx; unsigned int bb_count = 0; @@ -766,7 +766,7 @@ static unsigned int test_nd(HANDLE hDrive, blk_t last_block, nr_pattern = t_flag; } else { pattern = patterns; - nr_pattern = sizeof(patterns) / sizeof(patterns[0]); + nr_pattern = ARRAYSIZE(patterns); } for (pat_idx = 0; pat_idx < nr_pattern; pat_idx++) { pattern_fill(test_base, pattern[pat_idx], @@ -961,9 +961,9 @@ BOOL BadBlocks(HANDLE hPhysicalDrive, ULONGLONG disk_size, int block_size, } cancel_ops = 0; /* use a timer to update status every second */ - SetTimer(hMainDialog, BADBLOCK_TIMER_ID, 1000, alarm_intr); + SetTimer(hMainDialog, TID_BADBLOCKS_UPDATE, 1000, alarm_intr); report->bb_count = test_func(hPhysicalDrive, last_block, block_size, first_block, EXT2_BLOCKS_AT_ONCE); - KillTimer(hMainDialog, BADBLOCK_TIMER_ID); + KillTimer(hMainDialog, TID_BADBLOCKS_UPDATE); free(t_patts); free(bb_list->list); free(bb_list); diff --git a/src/badblocks.h b/src/badblocks.h index a89ce03f..7cb36660 100644 --- a/src/badblocks.h +++ b/src/badblocks.h @@ -41,6 +41,7 @@ typedef struct ext2_struct_u32_iterate *ext2_u32_iterate; #define EXT2_BAD_BLOCKS_THRESHOLD 256 #define EXT2_BLOCKS_AT_ONCE 64 #define EXT2_SYS_PAGE_SIZE 4096 +#define EXT2_RW_PATTERNS {0xaa, 0x55} enum test_types { BADBLOCKS_RO, /* Read-only */ diff --git a/src/format.c b/src/format.c index cc682e97..4dba22c2 100644 --- a/src/format.c +++ b/src/format.c @@ -44,6 +44,10 @@ */ DWORD FormatStatus; badblocks_report report; +static float format_percent = 0.0f; +static int task_number = 0; +/* Number of steps for each FS for FCC_STRUCTURE_PROGRESS */ +const int nb_steps[FS_MAX] = { 4, 4, 11, 9 }; /* * FormatEx callback. Return FALSE to halt operations @@ -51,31 +55,37 @@ badblocks_report report; static BOOLEAN __stdcall FormatExCallback(FILE_SYSTEM_CALLBACK_COMMAND Command, DWORD Action, PVOID pData) { DWORD* percent; - int task_number = 0; - if (IS_ERROR(FormatStatus)) return FALSE; switch(Command) { case FCC_PROGRESS: + // TODO: send this percentage to the status bar percent = (DWORD*)pData; - PostMessage(hMainDialog, UM_FORMAT_PROGRESS, (WPARAM)*percent, (LPARAM)0); uprintf("%d percent completed.\n", *percent); + format_percent = 1.0f * (*percent); + UpdateProgress(OP_FORMAT_LONG, format_percent); break; case FCC_STRUCTURE_PROGRESS: // No progress on quick format - uprintf("Format task %d/? completed.\n", ++task_number); + uprintf("Format task %d/%d completed.\n", ++task_number, + nb_steps[ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))]); + // TODO: figure out likely values + format_percent += 100.0f / (1.0f * nb_steps[ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))]); + UpdateProgress(OP_FORMAT_QUICK, format_percent); break; case FCC_DONE: if(*(BOOLEAN*)pData == FALSE) { uprintf("Error while formatting.\n"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_GEN_FAILURE; } + UpdateProgress(OP_FORMAT_DONE, 100.0f); break; case FCC_DONE_WITH_STRUCTURE: // We get this message when formatting Small FAT16 // pData Seems to be a struct with at least one (32 BIT!!!) string pointer to the size in MB uprintf("Done with that sort of things: Action=%d pData=%0p\n", Action, pData); DumpBufferHex(pData, 8); uprintf("Volume size: %s MB\n", (char*)(LONG_PTR)(*(ULONG32*)pData)); + UpdateProgress(OP_FORMAT_DONE, 100.0f); break; case FCC_INCOMPATIBLE_FILE_SYSTEM: uprintf("Incompatible File System\n"); @@ -151,6 +161,8 @@ static BOOL FormatDrive(char DriveLetter) } GetWindowTextW(hLabel, wLabel, ARRAYSIZE(wLabel)); uprintf("Using cluster size: %d bytes\n", ComboBox_GetItemData(hClusterSize, ComboBox_GetCurSel(hClusterSize))); + format_percent = 0.0f; + task_number = 0; pfFormatEx(wDriveRoot, SelectedDrive.Geometry.MediaType, wFSType, wLabel, IsChecked(IDC_QUICKFORMAT), (ULONG)ComboBox_GetItemData(hClusterSize, ComboBox_GetCurSel(hClusterSize)), FormatExCallback); @@ -355,18 +367,20 @@ bb_retry: uprintf("Check completed, %u bad block%s found. (%d/%d/%d errors)\n", report.bb_count, (report.bb_count==1)?"":"s", report.num_read_errors, report.num_write_errors, report.num_corruption_errors); - safe_sprintf(bb_msg, sizeof(bb_msg), "Check completed - %u bad block%s found:\n" - " %d read errors\n %d write errors\n %d corruption errors", - report.bb_count, (report.bb_count==1)?"":"s", - report.num_read_errors, report.num_write_errors, - report.num_corruption_errors); - switch(MessageBoxA(hMainDialog, bb_msg, "Bad blocks check", - report.bb_count?(MB_ABORTRETRYIGNORE|MB_ICONWARNING):(MB_OK|MB_ICONINFORMATION))) { - case IDRETRY: - goto bb_retry; - case IDABORT: - FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED; - goto out; + if (report.bb_count) { + safe_sprintf(bb_msg, sizeof(bb_msg), "Check completed - %u bad block%s found:\n" + " %d read errors\n %d write errors\n %d corruption errors", + report.bb_count, (report.bb_count==1)?"":"s", + report.num_read_errors, report.num_write_errors, + report.num_corruption_errors); + switch(MessageBoxA(hMainDialog, bb_msg, "Bad blocks check", + MB_ABORTRETRYIGNORE|MB_ICONWARNING)) { + case IDRETRY: + goto bb_retry; + case IDABORT: + FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED; + goto out; + } } safe_unlockclose(hLogicalVolume); } @@ -378,11 +392,13 @@ bb_retry: FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT; goto out; } + UpdateProgress(OP_ZERO_MBR, -1.0f); if (!CreatePartition(hPhysicalDrive)) { FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE; goto out; } + UpdateProgress(OP_PARTITION, -1.0f); // Make sure we can access the volume again before trying to format it for (i=0; i<10; i++) { @@ -416,6 +432,7 @@ bb_retry: // Errorcode has already been set goto out; } + UpdateProgress(OP_FIX_MBR, -1.0f); if (IsChecked(IDC_DOS)) { // We must have a lock to modify the volume boot record... @@ -432,6 +449,7 @@ bb_retry: } // ... and we must have relinquished that lock to write the MS-DOS files safe_unlockclose(hLogicalVolume); + UpdateProgress(OP_DOS, -1.0f); PrintStatus(0, "Copying MS-DOS files...\n"); if (!ExtractMSDOS(drive_name)) { FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANNOT_COPY; diff --git a/src/msdos.c b/src/msdos.c index ed9e43bb..11806e92 100644 --- a/src/msdos.c +++ b/src/msdos.c @@ -328,6 +328,7 @@ BOOL ExtractMSDOS(const char* path) for (j=0; r && jPartitionEntry[0].PartitionNumber = 1; DriveLayoutEx->PartitionEntry[0].RewritePartition = TRUE; DriveLayoutEx->PartitionEntry[0].Mbr.HiddenSectors = SelectedDrive.Geometry.SectorsPerTrack; - switch (ComboBox_GetCurSel(hFileSystem)) { + switch (ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))) { case FS_FAT16: DriveLayoutEx->PartitionEntry[0].Mbr.PartitionType = 0x0e; // FAT16 LBA break; @@ -550,6 +562,103 @@ static BOOL GetUSBDevices(void) return TRUE; } +/* + * 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; + nb_slots[OP_FORMAT_QUICK] = + nb_steps[ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))]; + nb_slots[OP_FORMAT_DONE] = 1; + if (!IsChecked(IDC_QUICKFORMAT)) { + nb_slots[OP_FORMAT_LONG] = -1; + } + + for (i=0; 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 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)) { + 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); +} + /* * Toggle controls according to operation */ @@ -589,12 +698,6 @@ static void CALLBACK ClockTimer(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dw /* * Main dialog callback */ -#ifndef PBS_MARQUEE // Some versions of MinGW don't know these -#define PBS_MARQUEE 0x08 -#endif -#ifndef PBM_SETMARQUEE -#define PBM_SETMARQUEE (WM_USER+10) -#endif static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { HDC hDC; @@ -604,8 +707,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA DWORD DeviceNum; char str[MAX_PATH], tmp[128]; static uintptr_t format_thid = -1L; - static HWND hProgress, hDOS; -// static LONG ProgressStyle = 0; + static HWND hDOS; static UINT uDOSChecked = BST_CHECKED; switch (message) { @@ -638,8 +740,8 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA SendMessage (hDlg, WM_SETICON, ICON_BIG, (LPARAM)hBigIcon); // Create the status line CreateStatusBar(); - // We'll switch the progressbar to marquee and back => keep a copy of current style -// ProgressStyle = GetWindowLong(hProgress, GWL_STYLE); + // Use maximum granularity for the progress bar + SendMessage(hProgress, PBM_SETRANGE, 0, MAX_PROGRESS<<16); // Create the string array StrArrayCreate(&DriveID, MAX_DRIVES); StrArrayCreate(&DriveLabel, MAX_DRIVES); @@ -729,15 +831,9 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA if (MessageBoxA(hMainDialog, str, "Rufus", MB_OKCANCEL|MB_ICONWARNING) == IDOK) { // Disable all controls except cancel EnableControls(FALSE); -#if 0 - // Handle marquee progress bar on quickformat - SetWindowLongPtr(hProgress, GWL_STYLE, ProgressStyle | (IsChecked(IDC_QUICKFORMAT)?PBS_MARQUEE:0)); - if (IsChecked(IDC_QUICKFORMAT)) { - SendMessage(hProgress, PBM_SETMARQUEE, TRUE, 0); - } -#endif DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex); FormatStatus = 0; + InitProgress(); format_thid = _beginthread(FormatThread, 0, (void*)(uintptr_t)DeviceNum); if (format_thid == -1L) { uprintf("Unable to start formatting thread"); @@ -748,7 +844,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA safe_sprintf(szTimer, sizeof(szTimer), "00:00:00"); SendMessageA(GetDlgItem(hMainDialog, IDC_STATUS), SB_SETTEXTA, SBT_OWNERDRAW | 1, (LPARAM)szTimer); - SetTimer(hMainDialog, STATUSBAR_TIMER_ID, 1000, ClockTimer); + SetTimer(hMainDialog, TID_APP_TIMER, 1000, ClockTimer); } } break; @@ -764,27 +860,20 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA PostQuitMessage(0); break; - case UM_FORMAT_PROGRESS: - SendMessage(hProgress, PBM_SETPOS, wParam, lParam); - return (INT_PTR)TRUE; - case UM_FORMAT_COMPLETED: format_thid = -1L; // Stop the timer - KillTimer(hMainDialog, STATUSBAR_TIMER_ID); + KillTimer(hMainDialog, TID_APP_TIMER); // Close the cancel MessageBox if active SendMessage(FindWindowA(MAKEINTRESOURCEA(32770), RUFUS_CANCELBOX_TITLE), WM_COMMAND, IDNO, 0); -#if 0 - if (IsChecked(IDC_QUICKFORMAT)) { - SendMessage(hProgress, PBM_SETMARQUEE, FALSE, 0); - SetWindowLongPtr(hProgress, GWL_STYLE, ProgressStyle); - // This is the only way to achieve instantanenous progress transition - SendMessage(hProgress, PBM_SETRANGE, 0, 101<<16); - SendMessage(hProgress, PBM_SETPOS, 101, 0); - SendMessage(hProgress, PBM_SETRANGE, 0, 100<<16); + 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); } -#endif - SendMessage(hProgress, PBM_SETPOS, FormatStatus?0:100, 0); EnableControls(TRUE); GetUSBDevices(); if (!IS_ERROR(FormatStatus)) { diff --git a/src/rufus.h b/src/rufus.h index 89e73310..9db01506 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -28,6 +28,7 @@ #define DRIVE_INDEX_MAX 0xC0 #define MAX_DRIVES 16 #define MAX_TOOLTIPS 16 +#define MAX_PROGRESS (0xFFFF-1) // leave room for 1 more for insta-progress workaround #define PROPOSEDLABEL_TOLERANCE 0.10 #define FS_DEFAULT FS_FAT32 #define WHITE RGB(255,255,255) @@ -71,8 +72,7 @@ extern void _uprintf(const char *format, ...); /* Custom Windows messages */ enum user_message_type { - UM_FORMAT_PROGRESS = WM_APP, - UM_FORMAT_COMPLETED + UM_FORMAT_COMPLETED = WM_APP }; /* Custom notifications */ @@ -83,10 +83,23 @@ enum notification_type { }; /* Timers used throughout the program */ -enum timer_id { - PRINTSTATUS_TIMER_ID = 0x1000, - BADBLOCK_TIMER_ID, - STATUSBAR_TIMER_ID +enum timer_type { + TID_MESSAGE = 0x1000, + TID_BADBLOCKS_UPDATE, + TID_APP_TIMER +}; + +/* Action type, for progress bar breakdown */ +enum action_type { + OP_BADBLOCKS, + OP_ZERO_MBR, + OP_PARTITION, + OP_FORMAT_LONG, + OP_FORMAT_QUICK, + OP_FORMAT_DONE, + OP_FIX_MBR, + OP_DOS, + OP_MAX }; /* File system indexes in our FS combobox */ @@ -125,6 +138,7 @@ extern float fScale; extern char szFolderPath[MAX_PATH]; extern DWORD FormatStatus; extern RUFUS_DRIVE_INFO SelectedDrive; +extern const int nb_steps[FS_MAX]; /* * Shared prototypes @@ -132,6 +146,7 @@ extern RUFUS_DRIVE_INFO SelectedDrive; extern const char *WindowsErrorString(void); extern void DumpBufferHex(void *buf, size_t size); extern void PrintStatus(unsigned int duration, const char *format, ...); +extern void UpdateProgress(int op, float percent); extern const char* StrError(DWORD error_code); extern void CenterDialog(HWND hDlg); extern void CreateStatusBar(void); diff --git a/src/rufus.rc b/src/rufus.rc index 954dd1bb..63d774a1 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -30,7 +30,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 206, 278 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_APPWINDOW -CAPTION "Rufus v1.0.2.84 (Beta)" +CAPTION "Rufus v1.0.2.85 (Beta)" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "Start",IDC_START,94,236,50,14 @@ -65,7 +65,7 @@ BEGIN DEFPUSHBUTTON "OK",IDOK,231,175,50,14,WS_GROUP CONTROL "https://github.com/pbatard/rufus",IDC_ABOUT_RUFUS_URL, "SysLink",WS_TABSTOP,46,47,114,9 - LTEXT "Version 1.0.2 (Build 84)",IDC_STATIC,46,19,78,8 + LTEXT "Version 1.0.2 (Build 85)",IDC_STATIC,46,19,78,8 PUSHBUTTON "License...",IDC_ABOUT_LICENSE,46,175,50,14,WS_GROUP EDITTEXT IDC_ABOUT_COPYRIGHTS,46,107,235,63,ES_MULTILINE | ES_READONLY | WS_VSCROLL LTEXT "Report bugs or request enhancements at:",IDC_STATIC,46,66,187,8 @@ -164,8 +164,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,2,84 - PRODUCTVERSION 1,0,2,84 + FILEVERSION 1,0,2,85 + PRODUCTVERSION 1,0,2,85 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -182,13 +182,13 @@ BEGIN BEGIN VALUE "CompanyName", "akeo.ie" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "1.0.2.84" + VALUE "FileVersion", "1.0.2.85" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "1.0.2.84" + VALUE "ProductVersion", "1.0.2.85" END END BLOCK "VarFileInfo" diff --git a/src/stdio.c b/src/stdio.c index fac5697c..14e1cb75 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -134,7 +134,7 @@ static void CALLBACK PrintStatusTimeout(HWND hwnd, UINT uMsg, UINT_PTR idEvent, bStatusTimerArmed = FALSE; // potentially display lower priority message that was overridden SetDlgItemTextU(hMainDialog, IDC_STATUS, szStatusMessage); - KillTimer(hMainDialog, PRINTSTATUS_TIMER_ID); + KillTimer(hMainDialog, TID_MESSAGE); } void PrintStatus(unsigned int duration, const char *format, ...) @@ -159,7 +159,7 @@ void PrintStatus(unsigned int duration, const char *format, ...) } if (duration) { - SetTimer(hMainDialog, PRINTSTATUS_TIMER_ID, duration, PrintStatusTimeout); + SetTimer(hMainDialog, TID_MESSAGE, duration, PrintStatusTimeout); bStatusTimerArmed = TRUE; } }