//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1994 - 1995. // // File: format.c // // Contents: Implements disk formatting from a drive's context menu // // Functions: SHELL API SHFormatDrive // // file local BeginFormat // file local DiableControls // file local EnableControls // file local StuffFormatInfoPtr // file local UnstuffFormatInfoPtr // file local GetFormatInfoPtr // file local FileSysChange // file local FormatCallback // file local FormatDlgProc // file local InitializeFormatDlg // file local LoadFMIFS // // History: 2-13-95 davepl Created // 10-15-95 brianau Added compression setting when fmifs not // available. // 10-23-95 brianau Enabled FMIFS support. Removed changes // of 10-15-95. // //-------------------------------------------------------------------------- #include "precomp.h" #pragma hdrstop #ifdef WINNT // Chicago has its own format code #define WTEXT(quote) L##quote #ifdef DEBUG #define LOAD_STRING(id,buffer)\ {\ if (0==LoadStringW(HINST_THISDLL, id, buffer, ARRAYSIZE(buffer)))\ Assert(FALSE);\ } #else #define LOAD_STRING(id,buffer) LoadStringW(HINST_THISDLL, id, buffer, ARRAYSIZE(buffer)) #endif const WCHAR cwsz_FAT[] = WTEXT("FAT"); const WCHAR cwsz_NTFS[] = WTEXT("NTFS"); const WCHAR cwsz_OFS[] = WTEXT("OFS"); static DWORD FmtaIds[]={IDOK, IDH_FORMATDLG_START, IDCANCEL, IDH_CANCEL, IDC_CAPCOMBO, IDH_FORMATDLG_CAPACITY, IDC_FSCOMBO, IDH_FORMATDLG_FILESYS, IDC_ASCOMBO, IDH_FORMATDLG_ALLOCSIZE, IDC_VLABEL, IDH_FORMATDLG_LABEL, IDC_GROUPBOX_1, IDH_COMM_GROUPBOX, IDC_QFCHECK, IDH_FORMATDLG_QUICKFULL, IDC_ECCHECK, IDH_FORMATDLG_COMPRESS, IDC_FMTPROGRESS, IDH_FORMATDLG_PROGRESS, 0,0}; static DWORD ChkaIds[]={IDOK, IDH_CHKDSKDLG_START, IDCANCEL, IDH_CHKDSKDLG_CANCEL, IDC_GROUPBOX_1, IDH_COMM_GROUPBOX, IDC_FIXERRORS, IDH_CHKDSKDLG_FIXERRORS, IDC_RECOVERY, IDH_CHKDSKDLG_SCAN, IDC_CHKDSKPROGRESS, IDH_CHKDSKDLG_PROGRESS, 0,0}; // // The following structure encapsulates our calling into the FMIFS.DLL // #define HAVE_FMIFS_SUPPORT 1 // Yes, we have FMIFS support. typedef struct tagFMIFSEntryPoints { HINSTANCE hFMIFS_DLL; #ifdef HAVE_FMIFS_SUPPORT PFMIFS_FORMATEX_ROUTINE FormatEx; #else PFMIFS_FORMAT_ROUTINE FormatEx; #endif PFMIFS_QSUPMEDIA_ROUTINE QuerySupportedMedia; #ifdef HAVE_FMIFS_SUPPORT PFMIFS_ENABLECOMP_ROUTINE EnableVolumeCompression; #else #endif PFMIFS_CHKDSK_ROUTINE ChkDsk; } FMIFS, * LPFMIFS; // // This structure described the current formatting session // typedef struct tagFormatInfo { UINT drive; // 0-based index of drive to format UINT fmtID; // Last format ID UINT options; // options passed to us via the API LPFMIFS pFMIFS; // ptr to FMIFS structure, above HWND hDlg; // handle to the format dialog BOOL fIsFloppy; // TRUE -> its a floppy BOOL fEnableComp; // Last "Enable Comp" choice from user BOOL fCancelled; // User cancelled the last format BOOL fShouldCancel; // User has clicked cancel; pending abort BOOL fWasFAT; // Was it FAT originally? BOOL fFinishedOK; // Did format complete sucessfully? BOOL fErrorAlready; // Did we put up an error dialog already? DWORD dwClusterSize; // Orig NT cluster size, or last choice WCHAR wszVolName[MAX_PATH]; // Volume Label WCHAR wszWinTitle[MAX_PATH]; // Format dialog window title WCHAR wszDriveName[4]; // Root path to drive (eg: A:\) HANDLE hThread; // Handle of format thread // Array of media types supported by the device FMIFS_MEDIA_TYPE rgMedia[IDS_FMT_MEDIA11-IDS_FMT_MEDIA0]; // Used to cache the enabled/disabled state of the dialog controls BOOL fControlEnabled[DLG_FORMATDISK_NUMCONTROLS]; } FORMATINFO, * LPFORMATINFO; // // An enumeration to make the filesystem combo-box code more readble // typedef enum tagFILESYSENUM { e_FAT = 0, e_NTFS, e_OFS } FILESYSENUM; // // Private WM_USER messages we will use. For some unknown reason, USER sends // us a WM_USER during initialization, so I start my private messages at // WM_USER + 0x0100 // typedef enum tagPRIVMSGS { PWM_FORMATDONE = WM_USER + 0x0100, PWM_CHKDSKDONE } PRIVMSGS; #define cdw_Kilobyte (1024) #define cdw_Megabyte (1024 * 1024) #define cdw_Gigabyte (1024 * 1024 * 1024) #define cdwTHREADWAIT (10000) // Wait 10 seconds for fmt thread to exit // before asking retry / killing it //+------------------------------------------------------------------------- // // Function: LoadFMIFS // // Synopsis: Loads FMIFS.DLL and sets up the function entry points for // the member functions we are interested in. // // Arguments: [pFEP] -- Pointer to a FMIFSEntryPoints struc // // Returns: HRESULT // // History: 2-15-95 davepl Created // // Notes: // //-------------------------------------------------------------------------- HRESULT LoadFMIFS(LPFMIFS pFMIFS) { HRESULT hr = S_OK; // // Load the FMIFS DLL and query for the entry points we need // if (NULL == (pFMIFS->hFMIFS_DLL = LoadLibrary(WTEXT("FMIFS.DLL")))) { hr = HRESULT_FROM_WIN32(GetLastError()); } #ifdef HAVE_FMIFS_SUPPORT else if (NULL == (pFMIFS->FormatEx = (PFMIFS_FORMATEX_ROUTINE) GetProcAddress(pFMIFS->hFMIFS_DLL, "FormatEx"))) #else else if (NULL == (pFMIFS->FormatEx = (PFMIFS_FORMAT_ROUTINE) GetProcAddress(pFMIFS->hFMIFS_DLL, "Format"))) #endif { hr = HRESULT_FROM_WIN32(GetLastError()); } else if (NULL == (pFMIFS->QuerySupportedMedia = (PFMIFS_QSUPMEDIA_ROUTINE) GetProcAddress(pFMIFS->hFMIFS_DLL, "QuerySupportedMedia"))) { hr = HRESULT_FROM_WIN32(GetLastError()); } #ifdef HAVE_FMIFS_SUPPORT else if (NULL == (pFMIFS->EnableVolumeCompression = (PFMIFS_ENABLECOMP_ROUTINE) GetProcAddress(pFMIFS->hFMIFS_DLL, "EnableVolumeCompression"))) { hr = HRESULT_FROM_WIN32(GetLastError()); } #endif else if (NULL == (pFMIFS->ChkDsk = (PFMIFS_CHKDSK_ROUTINE) GetProcAddress(pFMIFS->hFMIFS_DLL, "Chkdsk"))) { hr = HRESULT_FROM_WIN32(GetLastError()); } // // If anything failed, and we've got the DLL loaded, release the DLL // if (hr != S_OK && pFMIFS->hFMIFS_DLL) { FreeLibrary(pFMIFS->hFMIFS_DLL); } return hr; } //+------------------------------------------------------------------------- // // Function: StuffFormatInfoPtr() // // Synopsis: Allocates a thread-local index slot for this thread's // FORMATINFO pointer, if the index doesn't already exist. // In any event, stores the FORMATINFO pointer in the slot // and increments the index's usage count. // // Arguments: [pFormatInfo] -- The pointer to store // // Returns: HRESULT // // History: 2-20-95 davepl Created // //-------------------------------------------------------------------------- // // Thread-Local Storage index for our FORMATINFO structure pointer // static DWORD g_iTLSFormatInfo = 0; static LONG g_cTLSFormatInfo = 0; // Usage count HRESULT StuffFormatInfoPtr(LPFORMATINFO pFormatInfo) { HRESULT hr = S_OK; // // Allocate an index slot for our thread-local FORMATINFO pointer, if one // doesn't already exist, then stuff our FORMATINFO ptr at that index. // ENTERCRITICAL; if (0 == g_iTLSFormatInfo) { if (0xFFFFFFFF == (g_iTLSFormatInfo = TlsAlloc())) { hr = HRESULT_FROM_WIN32(GetLastError()); } g_cTLSFormatInfo = 0; } if (S_OK == hr) { if (TlsSetValue(g_iTLSFormatInfo, (LPVOID) pFormatInfo)) { g_cTLSFormatInfo++; } else { hr = HRESULT_FROM_WIN32(GetLastError()); } } LEAVECRITICAL; return hr; } //+------------------------------------------------------------------------- // // Function: UnstuffFormatInfoPtr() // // Synopsis: Decrements the usage count on our thread-local storage // index, and if it goes to zero the index is free'd // // Arguments: [none] // // Returns: none // // History: 2-20-95 davepl Created // //-------------------------------------------------------------------------- __inline void UnstuffFormatInfoPtr() { ENTERCRITICAL; if (0 == --g_cTLSFormatInfo) { TlsFree(g_iTLSFormatInfo); g_iTLSFormatInfo = 0; } LEAVECRITICAL; } //+------------------------------------------------------------------------- // // Function: GetFormatInfoPtr() // // Synopsis: Retrieves this threads FORMATINFO ptr by grabbing the // thread-local value previously stuff'd // // Arguments: [none] // // Returns: The pointer, of course // // History: 2-20-95 davepl Created // //-------------------------------------------------------------------------- __inline LPFORMATINFO GetFormatInfoPtr() { return TlsGetValue(g_iTLSFormatInfo); } //+------------------------------------------------------------------------- // // Function: DisableControls // // Synopsis: Ghosts all controls except "Cancel", saving their // previous state in the FORMATINFO structure // // Arguments: [pFormatInfo] -- Describes a format dialog session // // History: 2-14-95 davepl Created // // Notes: Also changes "Close" button text to read "Cancel" // //-------------------------------------------------------------------------- void DisableControls(LPFORMATINFO pFormatInfo) { WCHAR wszCancel[64]; int i; for (i = 0; i < DLG_FORMATDISK_NUMCONTROLS; i++) { HWND hControl = GetDlgItem(pFormatInfo->hDlg, i + DLG_FORMATDISK_FIRSTCONTROL); pFormatInfo->fControlEnabled[i] = IsWindowEnabled(hControl); EnableWindow(hControl, FALSE); } EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDOK), FALSE); LOAD_STRING( IDS_FMT_CANCEL, wszCancel ); SetWindowText(GetDlgItem(pFormatInfo->hDlg, IDCANCEL), wszCancel ); } //+------------------------------------------------------------------------- // // Function: EnableControls // // Synopsis: Restores controls to the enabled/disabled state they were // before a previous call to DisableControls(). // // Arguments: [pFormatInfo] -- Decribes a format dialog session // // History: 2-14-95 davepl Created // // Notes: Undefined behaviour if DisableControls has not been called // Also changes "Cancel" button to say "Close" // //-------------------------------------------------------------------------- void EnableControls(LPFORMATINFO pFormatInfo) { WCHAR wszClose[64]; int i; for (i = 0; i < DLG_FORMATDISK_NUMCONTROLS; i++) { HWND hControl = GetDlgItem(pFormatInfo->hDlg, i + DLG_FORMATDISK_FIRSTCONTROL); EnableWindow(hControl, pFormatInfo->fControlEnabled[i]); } EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDOK), TRUE); LOAD_STRING( IDS_FMT_CLOSE, wszClose ); SetWindowText(GetDlgItem(pFormatInfo->hDlg, IDCANCEL), wszClose); } //+------------------------------------------------------------------------- // // Function: SetWindowTitle // // Synopsis: Sets the format dialog's title to "Format A:" or // "Formatting A:" depending on the drive letter and the // fInProgress flag. // // Arguments: [pFormatInfo] -- Carries the drive letter // [fInProgress] -- TRUE => currently formatting // // History: 2-14-95 davepl Created // // //-------------------------------------------------------------------------- void SetWindowTitle(LPFORMATINFO pFormatInfo, BOOL fInProgress) { LOAD_STRING( fInProgress ? IDS_FMT_FORMATTING:IDS_FMT_FORMAT, pFormatInfo->wszWinTitle ); lstrcat(pFormatInfo->wszWinTitle, pFormatInfo->wszDriveName); pFormatInfo->wszDriveName[lstrlen(pFormatInfo->wszDriveName)] = WTEXT('\0'); SetWindowText(pFormatInfo->hDlg, pFormatInfo->wszWinTitle); } //+------------------------------------------------------------------------- // // Function: FileSysChange // // Synopsis: Called when a user picks a filesystem in the dialog, this // sets the states of the other relevant controls, such as // Enable Compression, Allocation Size, etc. // // Arguments: [n] -- One of e_FAT, e_NTFS, or e_OFS // [pFormatInfo] -- Current format dialog session // // History: 2-14-95 davepl Created // //-------------------------------------------------------------------------- void FileSysChange(FILESYSENUM n, LPFORMATINFO pFormatInfo) { WCHAR wszTmp[MAX_PATH]; int i; switch(n) { case e_FAT: // Clean & Diable the Enable Compression option SendDlgItemMessage( pFormatInfo->hDlg, IDC_ECCHECK, BM_SETCHECK, FALSE, 0 ); EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_ECCHECK), FALSE); SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_RESETCONTENT, 0, 0); LOAD_STRING(IDS_FMT_ALLOC0, wszTmp ); SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_ADDSTRING, 0, (LPARAM)wszTmp); SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_SETCURSEL, 0, 0); break; case e_NTFS: case e_OFS: EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_ECCHECK), TRUE); SendDlgItemMessage(pFormatInfo->hDlg, IDC_ECCHECK, BM_SETCHECK, pFormatInfo->fEnableComp, 0); // Set up the NTFS Allocation choices, and select the current choice SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_RESETCONTENT, 0, 0); for ( i = IDS_FMT_ALLOC0 ; i <= IDS_FMT_ALLOC4 ; i++ ) { LOAD_STRING( i, wszTmp ); SendDlgItemMessage( pFormatInfo->hDlg, IDC_ASCOMBO, CB_ADDSTRING, 0, (LPARAM)wszTmp ); } switch(pFormatInfo->dwClusterSize) { case 512: SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_SETCURSEL, 1, 0); break; case 1024: SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_SETCURSEL, 2, 0); break; case 2048: SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_SETCURSEL, 3, 0); break; case 4096: SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_SETCURSEL, 4, 0); break; default: SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_SETCURSEL, 0, 0); break; } break; } // switch(n) } //+------------------------------------------------------------------------- // // Function: InitializeFormatDlg // // Synopsis: Initializes the format dialog to a default state. Examines // the disk/partition to obtain default values. // // Arguments: [hDlg] -- Handle to the format dialog // [pFormatInfo] -- Describes current format session // // Returns: HRESULT // // History: 2-14-95 davepl Created // //-------------------------------------------------------------------------- HRESULT InitializeFormatDlg(LPFORMATINFO pFormatInfo) { HRESULT hr = S_OK; ULONG cMedia; HWND hCapacityCombo; HWND hFilesystemCombo; HWND hDlg = pFormatInfo->hDlg; WCHAR wszBuffer[256]; // // Set up some typical default values // pFormatInfo->fEnableComp = FALSE; pFormatInfo->dwClusterSize = 0; pFormatInfo->fIsFloppy = TRUE; pFormatInfo->fWasFAT = TRUE; pFormatInfo->fFinishedOK = FALSE; pFormatInfo->fErrorAlready = FALSE; pFormatInfo->wszVolName[0] = WTEXT('\0'); // // Initialize the Quick Format checkbox based on option passed to // the SHFormatDrive() API // SendDlgItemMessage(hDlg, IDC_QFCHECK, BM_SETCHECK, (pFormatInfo->options & SHFMT_OPT_FULL) ? TRUE : FALSE, 0); // // Set the dialog title to indicate which drive we are dealing with // lstrcpyW(pFormatInfo->wszDriveName, WTEXT("A:\\")); ASSERT(pFormatInfo->drive < 26); pFormatInfo->wszDriveName[0] += (WCHAR) pFormatInfo->drive; SetWindowTitle(pFormatInfo, FALSE); // // Query the supported media types for the drive in question // if (FALSE == pFormatInfo->pFMIFS->QuerySupportedMedia(pFormatInfo->wszDriveName, pFormatInfo->rgMedia, ARRAYSIZE(pFormatInfo->rgMedia), &cMedia)) { hr = HRESULT_FROM_WIN32(GetLastError()); } // // For each of the formats that the drive can handle, add a selection // to the capcity combobox. // if (S_OK == hr) { ULONG i,j; hCapacityCombo = GetDlgItem(hDlg, IDC_CAPCOMBO); hFilesystemCombo = GetDlgItem(hDlg, IDC_FSCOMBO); Assert(hCapacityCombo && hFilesystemCombo); // // Strip out weird media types // j = 0; for ( i = 0; i < cMedia; i++) { if (pFormatInfo->rgMedia[i] != FmMediaF5_160_512 && pFormatInfo->rgMedia[i] != FmMediaF5_180_512 && pFormatInfo->rgMedia[i] != FmMediaF5_320_512 && pFormatInfo->rgMedia[i] != FmMediaF5_320_1024 ) { // Ok, its not a weird one... pFormatInfo->rgMedia[j] = pFormatInfo->rgMedia[i]; j++; } } cMedia = j; for (i = 0; i < cMedia; i++) { // // If we find any non-floppy format, clear the fIsFloppy flag // if (FmMediaFixed == pFormatInfo->rgMedia[i] || FmMediaRemovable == pFormatInfo->rgMedia[i]) { pFormatInfo->fIsFloppy = FALSE; } // // For fixed media we query the size, for floppys we present // a set of options supported by the drive // if (FmMediaFixed == pFormatInfo->rgMedia[i]) { DWORD dwSectorsPerCluster, dwBytesPerSector, dwFreeClusters, dwClusters; if (GetDiskFreeSpace(pFormatInfo->wszDriveName, &dwSectorsPerCluster, &dwBytesPerSector, &dwFreeClusters, &dwClusters)) { WCHAR wszBuf[100]; __int64 iCapacity = (__int64)dwSectorsPerCluster * (__int64)dwBytesPerSector * (__int64)dwClusters; pFormatInfo->dwClusterSize = dwBytesPerSector * dwSectorsPerCluster; ShortSizeFormat64(iCapacity, wszBuf); // Add a capacity desciption to the combobox SendMessage(hCapacityCombo, CB_ADDSTRING, 0, (LPARAM) wszBuf); } else { // Couldn't get the free space... prob. not fatal LOAD_STRING( IDS_FMT_CAPUNKNOWN, wszBuffer ); SendMessage(hCapacityCombo, CB_ADDSTRING, 0, (LPARAM)wszBuffer); } } else { // Add a capacity desciption to the combo LOAD_STRING(IDS_FMT_MEDIA0+pFormatInfo->rgMedia[i], wszBuffer ); SendMessage(hCapacityCombo, CB_ADDSTRING, 0, (LPARAM)wszBuffer); } } SendMessage(hCapacityCombo, CB_SETCURSEL, 0, 0); } // // Add the appropriate filesystem selections to the combobox // if (S_OK == hr) { SendMessage(hFilesystemCombo, CB_ADDSTRING, 0, (LPARAM)cwsz_FAT ); if (FALSE == pFormatInfo->fIsFloppy) { SendMessage(hFilesystemCombo, CB_ADDSTRING, 0, (LPARAM)cwsz_NTFS ); //#ifdef CAIRO // BUGBUG (DavePl) I mean _really_ CAIRO //LOAD_STRING( IDS_FMT_OFS, wszBuffer ); //SendMessage(hFilesystemCombo, CB_ADDSTRING, 0, (LPARAM)szBuffer); //#endif } // By default, pick FAT (entry 0 in the _nonsorted_ combobox) SendMessage(hFilesystemCombo, CB_SETCURSEL, e_FAT, 0); FileSysChange(e_FAT, pFormatInfo); } // If we can determine something other than FAT is being used, // select it as the default in the combobox if (S_OK == hr && !pFormatInfo->fIsFloppy) { WCHAR wszCurFileSys[MAX_PATH]; UINT olderror = SetErrorMode(SEM_FAILCRITICALERRORS); if (GetVolumeInformation(pFormatInfo->wszDriveName, pFormatInfo->wszVolName, ARRAYSIZE(pFormatInfo->wszVolName), NULL, NULL, NULL, wszCurFileSys, ARRAYSIZE(wszCurFileSys))) { // // If we got a current volume label, stuff it in the edit control // if (pFormatInfo->wszVolName[0] != WTEXT('\0')) { SetWindowText(GetDlgItem(pFormatInfo->hDlg, IDC_VLABEL), pFormatInfo->wszVolName); } if (0 == lstrcmpi(cwsz_NTFS, wszCurFileSys)) { SendMessage(hFilesystemCombo, CB_SETCURSEL, e_NTFS, 0); pFormatInfo->fWasFAT = FALSE; FileSysChange(e_NTFS, pFormatInfo); } else // if (0 == lstrcmpi(cwsz_FAT, wszCurFileSys)) { SendMessage(hFilesystemCombo, CB_SETCURSEL, e_FAT, 0); pFormatInfo->fWasFAT = TRUE; pFormatInfo->dwClusterSize = 0; FileSysChange(e_FAT, pFormatInfo); } // BUGBUG - What about specialized file-systems? Don't care for now. //#ifdef CAIRO // BUGBUG (DavePl) I mean _really_ CAIRO //if (0 == lstrcmpi(cwsz_OFS, wszCurFileSys)) //{ // SendMessage(hFilesystemCombo, CB_SETCURSEL, e_OFS, 0); // pFormatInfo->fWasFAT = FALSE; // FileSysChange(e_OFS, pFormatInfo); //} //#endif } } // // If the above failed due to disk not in drive, notify the user // if (HRESULT_FROM_WIN32(ERROR_NOT_READY) == hr) { ShellMessageBox(HINST_THISDLL, hDlg, MAKEINTRESOURCE(IDS_DRIVENOTREADY), NULL, MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK, pFormatInfo->wszDriveName[0]); // BUGBUG - Retry? (only if we can get rid of the shell dialog that tells // you that you don't have a drive inserted. otherwise leave it alone. } return hr; } //+------------------------------------------------------------------------- // // Function: FormatCallback // // Synopsis: Called from within the FMIFS DLL's Format function, this // updates the format dialog's status bar and responds to // format completion/error notifications. // // Arguments: [PacketType] -- Type of packet (ie: % complete, error, etc) // [PacketLength] -- Size, in bytes, of the packet // [pPacketData] -- Pointer to the packet // // Returns: BOOLEAN continuation value // // History: 2-14-95 davepl Created // //-------------------------------------------------------------------------- BOOLEAN FormatCallback(FMIFS_PACKET_TYPE PacketType, ULONG PacketLength, PVOID pPacketData) { UINT iMessageID = IDS_FORMATFAILED; BOOL fFailed = FALSE; LPFORMATINFO pFormatInfo; Assert(g_iTLSFormatInfo); // // Grab the FORMATINFO structure for this thread // if (NULL == (pFormatInfo = GetFormatInfoPtr())) { return FALSE; } // // If the user has signalled to abort the format, return // FALSE out of here right now // if (pFormatInfo->fShouldCancel) { pFormatInfo->fCancelled = TRUE; return FALSE; } // // I could table-drive this, but it compiles surprisingly well... // switch(PacketType) { case FmIfsIncompatibleFileSystem: fFailed = TRUE; iMessageID = IDS_INCOMPATIBLEFS; break; case FmIfsIncompatibleMedia: fFailed = TRUE; iMessageID = IDS_INCOMPATIBLEMEDIA; break; case FmIfsAccessDenied: fFailed = TRUE; iMessageID = IDS_ACCESSDENIED; break; case FmIfsMediaWriteProtected: fFailed = TRUE; iMessageID = IDS_WRITEPROTECTED; break; case FmIfsCantLock: fFailed = TRUE; iMessageID = IDS_CANTLOCK; break; case FmIfsCantQuickFormat: fFailed = TRUE; iMessageID = IDS_CANTQUICKFORMAT; break; case FmIfsIoError: fFailed = TRUE; iMessageID = IDS_IOERROR; // FUTURE Consider showing head/track etc where error was break; case FmIfsBadLabel: fFailed = TRUE; iMessageID = IDS_BADLABEL; break; case FmIfsPercentCompleted: { FMIFS_PERCENT_COMPLETE_INFORMATION * pPercent = (FMIFS_PERCENT_COMPLETE_INFORMATION *) pPacketData; SendDlgItemMessage(pFormatInfo->hDlg, IDC_FMTPROGRESS, PBM_SETPOS, pPercent->PercentCompleted, 0); break; } case FmIfsFinished: { // // Format is done; check for failure or success // FMIFS_FINISHED_INFORMATION * pFinishedInfo = (FMIFS_FINISHED_INFORMATION *) pPacketData; pFormatInfo->fFinishedOK = pFinishedInfo->Success; if (pFinishedInfo->Success) { // // If "Enable Compression" is checked, try to enable filesystem compression // if (SendDlgItemMessage(pFormatInfo->hDlg, IDC_ECCHECK, BM_GETCHECK, 0, 0)) { BOOL bStatus = FALSE; #ifdef HAVE_FMIFS_SUPPORT bStatus = pFormatInfo->pFMIFS->EnableVolumeCompression(pFormatInfo->wszDriveName, COMPRESSION_FORMAT_DEFAULT); #endif if (FALSE == bStatus) { ShellMessageBox(HINST_THISDLL, pFormatInfo->hDlg, MAKEINTRESOURCE(IDS_CANTENABLECOMP), NULL, MB_SETFOREGROUND | MB_ICONINFORMATION | MB_OK); } } // // Even though its a quick format, the progress meter should // show 100% when the "Format Complete" requester is up // SendDlgItemMessage(pFormatInfo->hDlg, IDC_FMTPROGRESS, PBM_SETPOS, 100 /* Percent Complete */, 0); // FUTURE Consider showing format stats, ie: ser no, bytes, etc ShellMessageBox(HINST_THISDLL, pFormatInfo->hDlg, MAKEINTRESOURCE(IDS_FORMATCOMPLETE), NULL, MB_SETFOREGROUND | MB_ICONINFORMATION | MB_OK); // // Restore the dialog title, reset progress and flags // SendDlgItemMessage(pFormatInfo->hDlg, IDC_FMTPROGRESS, PBM_SETPOS, 0 /* Reset Percent Complete */, 0); // // Set the focus onto the Close button // pFormatInfo->fCancelled = FALSE; } else { fFailed = TRUE; } break; } } // // If we received any kind of failure information, put up a final // "Format Failed" message. UNLESS we've already put up some nice message // if (fFailed && !pFormatInfo->fErrorAlready) { ShellMessageBox(HINST_THISDLL, pFormatInfo->hDlg, MAKEINTRESOURCE(iMessageID), NULL, MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK); pFormatInfo->fErrorAlready = TRUE; } return (BOOLEAN) (fFailed == FALSE); } //+------------------------------------------------------------------------- // // Function: BeginFormat // // Synopsis: Spun off as its own thread, this ghosts all controls in the // dialog except "Cancel", then does the actual format // // Arguments: [pIn] -- FORMATINFO structure pointer as a void * // // Returns: HRESULT thread exit code // // History: 2-14-95 davepl Created // //-------------------------------------------------------------------------- DWORD WINAPI BeginFormat(LPVOID pIn) { LPFORMATINFO pFormatInfo = pIn; int n; FMIFS_MEDIA_TYPE MediaType; LPCWSTR pwszFileSystemName; BOOLEAN fQuickFormat; HRESULT hr = S_OK; // // Save the FORAMTINFO ptr for this thread, to be used in the format // callback function // if (S_OK != (hr = StuffFormatInfoPtr(pFormatInfo))) { PostMessage(pFormatInfo->hDlg, (UINT) PWM_FORMATDONE, 0, 0); return (DWORD) hr; } // // Set the window title to indicate format in proress... // SetWindowTitle(pFormatInfo, TRUE); // // Determine the user's choice of filesystem // n = SendDlgItemMessage(pFormatInfo->hDlg, IDC_FSCOMBO, CB_GETCURSEL, 0, 0); switch((FILESYSENUM) n) { case e_FAT: pwszFileSystemName = cwsz_FAT; break; case e_NTFS: pwszFileSystemName = cwsz_NTFS; break; case e_OFS: pwszFileSystemName = cwsz_OFS; break; } // // Determine the user's choice of media formats // n = SendDlgItemMessage(pFormatInfo->hDlg, IDC_CAPCOMBO, CB_GETCURSEL, 0, 0); MediaType = pFormatInfo->rgMedia[n]; // // Get the cluster size. First selection ("Use Default") yields a zero, // while the next 4 select 512, 1024, 2048, or 4096 // n = SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_GETCURSEL, 0, 0); pFormatInfo->dwClusterSize = n ? (256 << n) : 0; // // Quickformatting? // fQuickFormat = (BOOLEAN) SendDlgItemMessage(pFormatInfo->hDlg, IDC_QFCHECK, BM_GETCHECK, 0, 0); // // Do the format. // #ifdef HAVE_FMIFS_SUPPORT pFormatInfo->pFMIFS->FormatEx(pFormatInfo->wszDriveName, MediaType, (PWSTR) pwszFileSystemName, pFormatInfo->wszVolName, fQuickFormat, pFormatInfo->dwClusterSize, FormatCallback); #else pFormatInfo->pFMIFS->FormatEx(pFormatInfo->wszDriveName, MediaType, (PWSTR) pwszFileSystemName, pFormatInfo->wszVolName, fQuickFormat, FormatCallback); #endif // // Success or failure, we should fire a notification on the disk // since we don't really know the state after the format // SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATHW, (LPVOID) pFormatInfo->wszDriveName, NULL); // // Release the TLS index // UnstuffFormatInfoPtr(); // // Post a message back to the DialogProc thread to let it know // the format is done. We post the message since otherwise the // DialogProc thread will be too busy waiting for this thread // to exit to be able to process the PWM_FORMATDONE message // immediately. // PostMessage(pFormatInfo->hDlg, (UINT) PWM_FORMATDONE, 0, 0); return (DWORD) S_OK; } //+------------------------------------------------------------------------- // // Function: FormatDlgProc // // Synopsis: DLGPROC for the format dialog // // Arguments: [hDlg] -- Typical // [wMsg] -- Typical // [wParam] -- Typical // [lParam] -- For WM_INIT, carries the FORMATINFO structure // pointer passed to DialogBoxParam() when the // dialog was created. // // History: 2-14-95 davepl Created // //-------------------------------------------------------------------------- int CALLBACK FormatDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam) { HRESULT hr = S_OK; int ID = GET_WM_COMMAND_ID(wParam, lParam); int CMD = GET_WM_COMMAND_CMD(wParam, lParam); // Grab our previously cached pointer to the FORMATINFO struct (see WM_INITDIALOG) LPFORMATINFO pFormatInfo = (LPFORMATINFO) GetWindowLong(hDlg, DWL_USER); switch (wMsg) { case PWM_FORMATDONE: { // // Format is done. Reset the window title and clear the progress meter // SetWindowTitle(pFormatInfo, FALSE); SendDlgItemMessage(pFormatInfo->hDlg, IDC_FMTPROGRESS, PBM_SETPOS, 0 /* Reset Percent Complete */, 0); EnableControls(pFormatInfo); if (pFormatInfo->fCancelled) { ShellMessageBox(HINST_THISDLL, pFormatInfo->hDlg, MAKEINTRESOURCE(IDS_FORMATCANCELLED), NULL, MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK); pFormatInfo->fCancelled = FALSE; } CloseHandle(pFormatInfo->hThread); pFormatInfo->hThread = NULL; break; } case WM_INITDIALOG: { // // Initialize the dialog and cache the FORMATINFO structure's pointer // as our dialog's DWL_USER data // pFormatInfo = (LPFORMATINFO) lParam; pFormatInfo->hDlg = hDlg; if (FAILED(InitializeFormatDlg(pFormatInfo))) { EndDialog(hDlg, 0); return -1; } SetWindowLong(hDlg, DWL_USER, lParam); break; } case WM_DESTROY: break; case WM_COMMAND: { switch(CMD) { // // User made a selection in one of the combo boxes // case CBN_SELCHANGE: if (IDC_FSCOMBO == ID) { // // User selected a filesystem... update the rest of the dialog // based on this choice // HWND hFilesystemCombo = (HWND) lParam; int n = (WORD) SendMessage(hFilesystemCombo, CB_GETCURSEL, 0, 0); FileSysChange((FILESYSENUM) n, pFormatInfo); } // // Codepath for controls other than combo boxes... // default: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDC_ECCHECK: pFormatInfo->fEnableComp = SendMessage((HWND) lParam, BM_GETCHECK, 0, 0); break; case IDOK: { DWORD dwThreadID; // // Get user verification for format, break out on CANCEL // if (IDCANCEL == ShellMessageBox(HINST_THISDLL, hDlg, MAKEINTRESOURCE(IDS_OKTOFORMAT), NULL, MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OKCANCEL)) { break; } DisableControls(pFormatInfo); pFormatInfo->fCancelled = FALSE; pFormatInfo->fShouldCancel = FALSE; GetWindowText(GetDlgItem(pFormatInfo->hDlg, IDC_VLABEL), pFormatInfo->wszVolName, MAX_PATH); pFormatInfo->hThread = CreateThread( NULL, 0, BeginFormat, (LPVOID) pFormatInfo, 0, &dwThreadID ); break; } case IDCANCEL: // // If the format thread is running, wait for it. If not, // exit the dialog // pFormatInfo->fShouldCancel = TRUE; if (pFormatInfo->hThread) { DWORD dwWait; do { dwWait = WaitForSingleObject(pFormatInfo->hThread, cdwTHREADWAIT); } while ( WAIT_TIMEOUT == dwWait && IDRETRY == ShellMessageBox(HINST_THISDLL, hDlg, MAKEINTRESOURCE(IDS_CANTCANCELFMT), NULL, MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_RETRYCANCEL)); // // If the format doesn't admit to having been killed, it didn't // give up peacefully. Finish it... // BUGBUG Stack cleanup // if (FALSE == pFormatInfo->fCancelled) { TerminateThread(pFormatInfo->hThread, 0); } CloseHandle(pFormatInfo->hThread); pFormatInfo->hThread = NULL; pFormatInfo->fCancelled = TRUE; EnableControls(pFormatInfo); } else { EndDialog(hDlg, IDCANCEL); } break; } } break; } // end WM_COMMAND case case WM_HELP: WinHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP, (DWORD) (LPSTR) FmtaIds); break; case WM_CONTEXTMENU: WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU, (DWORD) (LPSTR) FmtaIds); break; default: return FALSE; } return TRUE; } //+------------------------------------------------------------------------- // // Function: SHFormatDrive // // Synopsis: The SHFormatDrive API provides access to the Shell // format dialog. This allows apps which want to format disks // to bring up the same dialog that the Shell does to do it. // // NOTE that the user can format as many diskettes in the // specified drive, or as many times, as he/she wishes to. // // Arguments: [hwnd] -- Parent window (Must NOT be NULL) // [drive] -- 0 = A:, 1 = B:, etc. // [fmtID] -- see below // [options] -- SHFMT_OPT_FULL overrised default quickformat // SHFMT_OPT_SYSONLY not support for NT // // Returns: See Notes // // History: 2-14-95 davepl Created // // Notes: BUGBUGs: // Should return volume ID, but doesn't yet // There's some backdoor magic about passing in the the low // DWORD of the last disk's serial number to force the // same type of format, still investigating it... // //-------------------------------------------------------------------------- DWORD WINAPI SHFormatDrive( HWND hwnd, UINT drive, UINT fmtID, UINT options ) { int ret; FMIFS fmifs; FORMATINFO FormatInfo = { (BYTE) drive, fmtID, options, NULL}; ASSERT(drive < 26); // // It makes no sense for NT to "SYS" a disk // if (FormatInfo.options & SHFMT_OPT_SYSONLY) { return 0; } // // Load the FMIFS DLL and open the Format dialog // if (S_OK == LoadFMIFS(&fmifs)) { FormatInfo.pFMIFS = &fmifs; ret = DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_FORMATDISK), hwnd, FormatDlgProc, (LPARAM) &FormatInfo); } else { Assert(0 && "Can't load FMIFS.DLL"); return SHFMT_ERROR; } // // Free the FMIFS library and return a success code the caller // FreeLibrary(FormatInfo.pFMIFS->hFMIFS_DLL); if (FormatInfo.fCancelled) { return SHFMT_CANCEL; } if (FormatInfo.fFinishedOK) { return 0; // BUGBUG FormatInfo.dwSerialNumber; } else { return SHFMT_ERROR; } } //////////////////////////////////////////////////////////////////////////// // // CHKDSK // //////////////////////////////////////////////////////////////////////////// // // This structure described the current chkdsk session // typedef struct tagChkDskInfo { UINT lastpercent; // last percentage complete received UINT currentphase; // current chkdsk phase UINT drive; // 0-based index of drive to chkdsk LPFMIFS pFMIFS; // ptr to FMIFS structure, above BOOL fRecovery; // Attempt to recover bad sectors BOOL fFixErrors; // Fix filesystem errors as found BOOL fCancelled; // Was chkdsk terminated early? BOOL fShouldCancel; // User has clicked cancel; pending abort HWND hDlg; // handle to the chkdsk dialog HANDLE hThread; BOOL fNoFinalMsg; // Do not put up a final failure message WCHAR wszDriveName[4]; // For example, "A:\" } CHKDSKINFO, * LPCHKDSKINFO; //+------------------------------------------------------------------------- // // Function: StuffChkDskInfoPtr() // // Synopsis: Allocates a thread-local index slot for this thread's // CHKDSKINFO pointer, if the index doesn't already exist. // In any event, stores the CHKDSKINFO pointer in the slot // and increments the index's usage count. // // Arguments: [pChkDskInfo] -- The pointer to store // // Returns: HRESULT // // History: 2-21-95 davepl Created // //-------------------------------------------------------------------------- // // Thread-Local Storage index for our CHKDSKINFO structure pointer // static DWORD g_iTLSChkDskInfo = 0; static LONG g_cTLSChkDskInfo = 0; // Usage count HRESULT StuffChkDskInfoPtr(LPCHKDSKINFO pChkDskInfo) { HRESULT hr = S_OK; // // Allocate an index slot for our thread-local CHKDSKINFO pointer, if one // doesn't already exist, then stuff our CHKDSKINFO ptr at that index. // ENTERCRITICAL; if (0 == g_iTLSChkDskInfo) { if (0 == (g_iTLSChkDskInfo = TlsAlloc())) { hr = HRESULT_FROM_WIN32(GetLastError()); } g_cTLSChkDskInfo = 0; } if (S_OK == hr) { if (TlsSetValue(g_iTLSChkDskInfo, (LPVOID) pChkDskInfo)) { g_cTLSChkDskInfo++; } else { hr = HRESULT_FROM_WIN32(GetLastError()); } } LEAVECRITICAL; return hr; } //+------------------------------------------------------------------------- // // Function: UnstuffChkDskInfoPtr() // // Synopsis: Decrements the usage count on our thread-local storage // index, and if it goes to zero the index is free'd // // Arguments: [none] // // Returns: none // // History: 2-21-95 davepl Created // //-------------------------------------------------------------------------- __inline void UnstuffChkDskInfoPtr() { ENTERCRITICAL; if (0 == --g_cTLSChkDskInfo) { TlsFree(g_iTLSChkDskInfo); g_iTLSChkDskInfo = 0; } LEAVECRITICAL; } //+------------------------------------------------------------------------- // // Function: GetChkDskInfoPtr() // // Synopsis: Retrieves this threads CHKDSKINFO ptr by grabbing the // thread-local value previously stuff'd // // Arguments: [none] // // Returns: The pointer, of course // // History: 2-21-95 davepl Created // //-------------------------------------------------------------------------- __inline LPCHKDSKINFO GetChkDskInfoPtr() { return TlsGetValue(g_iTLSChkDskInfo); } //+------------------------------------------------------------------------- // // Function: DisableChkDskControls // // Synopsis: Ghosts all controls except "Cancel", saving their // previous state in the CHKDSKINFO structure // // Arguments: [pChkDskInfo] -- Describes a ChkDsk dialog session // // History: 2-21-95 davepl Created // // Notes: Also changes "Close" button text to read "Cancel" // //-------------------------------------------------------------------------- __inline void DisableChkDskControls(LPCHKDSKINFO pChkDskInfo) { // // BUGBUG (DavePl) We disable CANCEL because CHKDSK does not // allow interruption at the filesystem level. // EnableWindow(GetDlgItem(pChkDskInfo->hDlg, IDC_FIXERRORS), FALSE); EnableWindow(GetDlgItem(pChkDskInfo->hDlg, IDC_RECOVERY), FALSE); EnableWindow(GetDlgItem(pChkDskInfo->hDlg, IDOK), FALSE); EnableWindow(GetDlgItem(pChkDskInfo->hDlg, IDCANCEL), FALSE); // SetWindowText(GetDlgItem(pChkDskInfo->hDlg, IDCANCEL), cwsz_Cancel); } //+------------------------------------------------------------------------- // // Function: EnableChkDskControls // // Synopsis: Restores controls to the enabled/disabled state they were // before a previous call to DisableControls(). // // Arguments: [pChkDskInfo] -- Decribes a chkdsk dialog session // // History: 2-21-95 davepl Created // //-------------------------------------------------------------------------- __inline void EnableChkDskControls(LPCHKDSKINFO pChkDskInfo) { EnableWindow(GetDlgItem(pChkDskInfo->hDlg, IDC_FIXERRORS), TRUE); EnableWindow(GetDlgItem(pChkDskInfo->hDlg, IDC_RECOVERY), TRUE); EnableWindow(GetDlgItem(pChkDskInfo->hDlg, IDOK), TRUE); EnableWindow(GetDlgItem(pChkDskInfo->hDlg, IDCANCEL), TRUE); // SetWindowText(GetDlgItem(pChkDskInfo->hDlg, IDCANCEL), cwsz_Close); // Erase the current phase text SetWindowText(GetDlgItem(pChkDskInfo->hDlg, IDC_PHASE), WTEXT("")); pChkDskInfo->lastpercent = 101; pChkDskInfo->currentphase = 0; } //+------------------------------------------------------------------------- // // Function: SetChkDskWindowTitle // // Synopsis: Sets the chkdsk dialog's title to "Check Disk A:" or // "Checking Disk A:" depending on the drive letter and the // fInProgress flag. // // Arguments: [pChkDskInfo] -- Carries the drive letter // [fInProgress] -- TRUE => currently checking the disk // // History: 2-21-95 davepl Created // // //-------------------------------------------------------------------------- void SetChkDskWindowTitle(LPCHKDSKINFO pChkDskInfo, BOOL fInProgress) { WCHAR swzTmp[MAX_PATH]; LOAD_STRING( fInProgress ? IDS_CHKINPROGRESS:IDS_CHKDISK, swzTmp ); lstrcat(swzTmp, pChkDskInfo->wszDriveName); SetWindowText(pChkDskInfo->hDlg, swzTmp); } //+------------------------------------------------------------------------- // // Function: ChkDskCallback // // Synopsis: Called from within the FMIFS DLL's ChkDsk function, this // updates the ChkDsk dialog's status bar and responds to // chkdsk completion/error notifications. // // Arguments: [PacketType] -- Type of packet (ie: % complete, error, etc) // [PacketLength] -- Size, in bytes, of the packet // [pPacketData] -- Pointer to the packet // // Returns: BOOLEAN continuation value // // History: 2-21-95 davepl Created // //-------------------------------------------------------------------------- BOOLEAN ChkDskCallback(FMIFS_PACKET_TYPE PacketType, ULONG PacketLength, PVOID pPacketData) { UINT iMessageID = IDS_CHKDSKFAILED; BOOL fFailed = FALSE; LPCHKDSKINFO pChkDskInfo; Assert(g_iTLSChkDskInfo); // // Grab the CHKDSKINFO structure for this thread // if (NULL == (pChkDskInfo = GetChkDskInfoPtr())) { return FALSE; } // // If the user has signalled to abort the ChkDsk, return // FALSE out of here right now // if (pChkDskInfo->fShouldCancel) { pChkDskInfo->fCancelled = TRUE; return FALSE; } switch(PacketType) { case FmIfsAccessDenied: fFailed = TRUE; iMessageID = IDS_CHKACCESSDENIED; break; case FmIfsCheckOnReboot: { FMIFS_CHECKONREBOOT_INFORMATION * pRebootInfo = (FMIFS_CHECKONREBOOT_INFORMATION *) pPacketData; // Check to see whether or not the user wants to schedule this // chkdsk for the next reboot, since the drive cannot be locked // right now. if (IDYES == ShellMessageBox(HINST_THISDLL, pChkDskInfo->hDlg, MAKEINTRESOURCE(IDS_CHKONREBOOT), NULL, MB_SETFOREGROUND | MB_ICONINFORMATION | MB_YESNO)) { // Yes, have FMIFS schedule an autochk for us pRebootInfo->QueryResult = TRUE; pChkDskInfo->fNoFinalMsg = TRUE; } else { // Nope, just fail out with "cant lock drive" fFailed = TRUE; iMessageID = IDS_CHKDSKFAILED; } break; } case FmIfsMediaWriteProtected: fFailed = TRUE; iMessageID = IDS_WRITEPROTECTED; break; /* This case will show up with a checkonreboot also, so don't do the same error twice case FmIfsCantLock: fFailed = TRUE; iMessageID = IDS_CANTLOCK; break; */ case FmIfsIoError: fFailed = TRUE; iMessageID = IDS_IOERROR; // FUTURE Consider showing head/track etc where error was break; case FmIfsPercentCompleted: { FMIFS_PERCENT_COMPLETE_INFORMATION * pPercent = (FMIFS_PERCENT_COMPLETE_INFORMATION *) pPacketData; SendMessage(GetDlgItem(pChkDskInfo->hDlg, IDC_CHKDSKPROGRESS), PBM_SETPOS, pPercent->PercentCompleted, 0); if (pPercent->PercentCompleted < pChkDskInfo->lastpercent) { // // If this % complete is less than the last one seen, // we have completed a phase of the chkdsk and should // advance to the next one. // WCHAR wszTmp[100]; WCHAR wszFormat[100]; LOAD_STRING( IDS_CHKPHASE, wszFormat ); wsprintf(wszTmp, wszFormat, ++(pChkDskInfo->currentphase)); SetWindowText(GetDlgItem(pChkDskInfo->hDlg, IDC_PHASE), wszTmp); } pChkDskInfo->lastpercent = pPercent->PercentCompleted; break; } case FmIfsFinished: { // // ChkDsk is done; check for failure or success // FMIFS_FINISHED_INFORMATION * pFinishedInfo = (FMIFS_FINISHED_INFORMATION *) pPacketData; // // BUGBUG !! (DavePl) ChkDsk sets an inverted success value! // if (pFinishedInfo->Success == FALSE) { // // Since we're done, force the progress gauge to 100%, so we // don't sit here looking stupid if the chkdsk code misled us // SendMessage(GetDlgItem(pChkDskInfo->hDlg, IDC_CHKDSKPROGRESS), PBM_SETPOS, 100 /* Percent Complete */, 0); ShellMessageBox(HINST_THISDLL, pChkDskInfo->hDlg, MAKEINTRESOURCE(IDS_CHKDSKCOMPLETE), NULL, MB_SETFOREGROUND | MB_ICONINFORMATION | MB_OK); SetWindowText(GetDlgItem(pChkDskInfo->hDlg, IDC_PHASE), WTEXT("")); SendMessage(GetDlgItem(pChkDskInfo->hDlg, IDC_CHKDSKPROGRESS), PBM_SETPOS, 0 /* Reset Percent Complete */, 0); } else { iMessageID = IDS_CHKDSKFAILED; fFailed = TRUE; } break; } } // // If we received any kind of failure information, put up a final // "ChkDsk Failed" message. // if (fFailed && FALSE == pChkDskInfo->fNoFinalMsg) { pChkDskInfo->fNoFinalMsg = TRUE; ShellMessageBox(HINST_THISDLL, pChkDskInfo->hDlg, MAKEINTRESOURCE(iMessageID), NULL, MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK); } return (BOOLEAN) (fFailed == FALSE); } //+------------------------------------------------------------------------- // // Function: BeginChkDsk // // Synopsis: Spun off as its own thread, this ghosts all controls in the // dialog except "Cancel", then does the actual ChkDsk // // Arguments: [pIn] -- CHKDSKINFO structure pointer as a void * // // Returns: HRESULT thread exit code // // History: 2-21-95 davepl Created // //-------------------------------------------------------------------------- DWORD WINAPI BeginChkDsk(LPVOID pIn) { LPCHKDSKINFO pChkDskInfo = pIn; int n; HRESULT hr = S_OK; WCHAR swzFileSystem[MAX_PATH]; // // Save the CHKDSKINFO ptr for this thread, to be used in the ChkDsk // callback function // if (S_OK != (hr = StuffChkDskInfoPtr(pChkDskInfo))) { PostMessage(pChkDskInfo->hDlg, (UINT) PWM_CHKDSKDONE, 0, 0); return (DWORD) hr; } // // Get the filesystem in use on the device // if (FALSE == GetVolumeInformationW(pChkDskInfo->wszDriveName, NULL, 0, NULL, NULL, NULL, swzFileSystem, MAX_PATH)) { PostMessage(pChkDskInfo->hDlg, (UINT) PWM_CHKDSKDONE, 0, 0); return (HRESULT_FROM_WIN32(GetLastError())); } // // Set the window title to indicate ChkDsk in proress... // SetChkDskWindowTitle(pChkDskInfo, TRUE); pChkDskInfo->fNoFinalMsg = FALSE; // // Should we try data recovery? // pChkDskInfo->fRecovery = (BOOLEAN) SendMessage(GetDlgItem(pChkDskInfo->hDlg, IDC_RECOVERY), BM_GETCHECK, 0, 0); // // Should we fix filesystem errors? // pChkDskInfo->fFixErrors = (BOOLEAN) SendMessage(GetDlgItem(pChkDskInfo->hDlg, IDC_FIXERRORS), BM_GETCHECK, 0, 0); // // Do the ChkDsk. // pChkDskInfo->pFMIFS->ChkDsk(pChkDskInfo->wszDriveName, swzFileSystem, (BOOLEAN) pChkDskInfo->fFixErrors, FALSE, /* Verbose */ FALSE, /* Only if dirty */ (BOOLEAN) pChkDskInfo->fRecovery, /* Recovery */ NULL, /* Frag path */ FALSE, /* Extend */ ChkDskCallback); /* Callback fn */ // // Release the TLS index // UnstuffChkDskInfoPtr(); // // Post a message back to the DialogProc thread to let it know // the chkdsk is done. We post the message since otherwise the // DialogProc thread will be too busy waiting for this thread // to exit to be able to process the PWM_CHKDSKDONE message // immediately. // PostMessage(pChkDskInfo->hDlg, (UINT) PWM_CHKDSKDONE, 0, 0); return (DWORD) S_OK; } //+------------------------------------------------------------------------- // // Function: ChkDskDlgProc // // Synopsis: DLGPROC for the chkdsk dialog // // Arguments: [hDlg] -- Typical // [wMsg] -- Typical // [wParam] -- Typical // [lParam] -- For WM_INIT, carries the CHKDSKINFO structure // pointer passed to DialogBoxParam() when the // dialog was created. // // History: 2-22-95 davepl Created // //-------------------------------------------------------------------------- int CALLBACK ChkDskDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam) { HRESULT hr = S_OK; int ID = GET_WM_COMMAND_ID(wParam, lParam); // Grab our previously cached pointer to the CHKDSKINFO struct (see WM_INITDIALOG) LPCHKDSKINFO pChkDskInfo = (LPCHKDSKINFO) GetWindowLong(hDlg, DWL_USER); switch (wMsg) { case PWM_CHKDSKDONE: { // // chdsk is done. Reset the window title and clear the progress meter // SetChkDskWindowTitle(pChkDskInfo, FALSE); SendMessage(GetDlgItem(pChkDskInfo->hDlg, IDC_CHKDSKPROGRESS), PBM_SETPOS, 0 /* Reset Percent Complete */, 0); EnableChkDskControls(pChkDskInfo); if (pChkDskInfo->fCancelled) { ShellMessageBox(HINST_THISDLL, pChkDskInfo->hDlg, MAKEINTRESOURCE(IDS_CHKDSKCANCELLED), NULL, MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK); } CloseHandle(pChkDskInfo->hThread); pChkDskInfo->hThread = NULL; EndDialog(hDlg, 0); break; } case WM_INITDIALOG: { // // Initialize the dialog and cache the CHKDSKINFO structure's pointer // as our dialog's DWL_USER data // pChkDskInfo = (LPCHKDSKINFO) lParam; pChkDskInfo->hDlg = hDlg; SetWindowLong(hDlg, DWL_USER, lParam); // // Set the dialog title to indicate which drive we are dealing with // lstrcpyW(pChkDskInfo->wszDriveName, WTEXT("A:\\")); ASSERT(pChkDskInfo->drive < 26); pChkDskInfo->wszDriveName[0] += (WCHAR) pChkDskInfo->drive; SetChkDskWindowTitle(pChkDskInfo, FALSE); break; } case WM_DESTROY: break; case WM_COMMAND: { switch (ID) { case IDC_FIXERRORS: pChkDskInfo->fFixErrors = SendMessage((HWND) lParam, BM_GETCHECK, 0, 0); break; case IDC_RECOVERY: pChkDskInfo->fRecovery = SendMessage((HWND) lParam, BM_GETCHECK, 0, 0); break; case IDOK: { DWORD dwThreadID; // // Get user verification for chkdsk, break out on CANCEL // DisableChkDskControls(pChkDskInfo); pChkDskInfo->fShouldCancel = FALSE; pChkDskInfo->fCancelled = FALSE; pChkDskInfo->hThread = CreateThread( NULL, 0, BeginChkDsk, (LPVOID) pChkDskInfo, 0, &dwThreadID ); break; } case IDCANCEL: // // If the chdsk thread is running, wait for it. If not, // exit the dialog // pChkDskInfo->fShouldCancel = TRUE; if (pChkDskInfo->hThread) { DWORD dwWait; do { dwWait = WaitForSingleObject(pChkDskInfo->hThread, cdwTHREADWAIT); } while ( WAIT_TIMEOUT == dwWait && IDRETRY == ShellMessageBox(HINST_THISDLL, hDlg, MAKEINTRESOURCE(IDS_CANTCANCELCHKDSK), NULL, MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_RETRYCANCEL)); // // If the chkdsk doesn't admit to having been killed, it didn't // give up peacefully. Finish it... // BUGBUG Stack cleanup // if (FALSE == pChkDskInfo->fCancelled) { TerminateThread(pChkDskInfo->hThread, 0); } CloseHandle(pChkDskInfo->hThread); pChkDskInfo->hThread = NULL; pChkDskInfo->fCancelled = TRUE; EnableChkDskControls(pChkDskInfo); } else { EndDialog(hDlg, IDCANCEL); } break; } break; } case WM_HELP: WinHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP, (DWORD) (LPSTR) ChkaIds); break; case WM_CONTEXTMENU: WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU, (DWORD) (LPSTR) ChkaIds); break; default: return FALSE; } return TRUE; } //+------------------------------------------------------------------------- // // Function: SHChkDskDrive // // Synopsis: Displays the "Check Disk" dialog and calls chkdsk on the // drive in question, as appropriate // // Arguments: [hwnd] -- Parent window (Must NOT be NULL) // [drive] -- 0 = A:, 1 = B:, etc. // // Returns: HRESULT // // History: 2-14-95 davepl Created // // Notes: // //-------------------------------------------------------------------------- static BOOL fChkdskActive[26]; DWORD WINAPI SHChkDskDrive( HWND hwnd, UINT drive ) { int ret = S_OK; FMIFS fmifs; // // We use a last percentage-complete value of 101, to guarantee that the // next one received will be less, indicating next (first) phase // CHKDSKINFO ChkDskInfo = { 101, 0, drive, NULL, FALSE, FALSE, FALSE, FALSE }; // // Cheap semaphore to prevent multiple chkdsks of the same drive // ENTERCRITICAL; if (fChkdskActive[drive]) { LEAVECRITICAL; return (DWORD)E_FAIL; } fChkdskActive[drive] = 1; LEAVECRITICAL; // // Load the FMIFS DLL and open the ChkDsk dialog // if (S_OK == LoadFMIFS(&fmifs)) { ChkDskInfo.pFMIFS = &fmifs; ret = DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_CHKDSK), hwnd, ChkDskDlgProc, (LPARAM) &ChkDskInfo); if (-1 == ret) { ret = GetLastError(); } } else { Assert(0 && "Can't load FMIFS.DLL"); fChkdskActive[drive] = 0; return (DWORD) E_OUTOFMEMORY; } // // Free the FMIFS library and return a success code the caller // FreeLibrary(ChkDskInfo.pFMIFS->hFMIFS_DLL); fChkdskActive[drive] = 0; return (DWORD) S_OK; } #endif // WINNT