|
|
#include "shellprv.h"
#include "ids.h"
#include "mtpt.h"
#include "hwcmmn.h"
#pragma hdrstop
#include "apithk.h"
const 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 };
const 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, IDC_PHASE, -1, 0,0 };
// The following structure encapsulates our calling into the FMIFS.DLL
typedef struct { HINSTANCE hFMIFS_DLL; PFMIFS_FORMATEX_ROUTINE FormatEx; PFMIFS_QSUPMEDIA_ROUTINE QuerySupportedMedia; PFMIFS_ENABLECOMP_ROUTINE EnableVolumeCompression; PFMIFS_CHKDSKEX_ROUTINE ChkDskEx; PFMIFS_QUERY_DEVICE_INFO_ROUTINE QueryDeviceInformation; } FMIFS;
typedef HRESULT (*PDISKCOPY_MAKEBOOTDISK_ROUTINE)( IN HINSTANCE hInstance, IN UINT iDrive, IN BOOL* pfCancelled, IN FMIFS_CALLBACK pCallback );
// The following structure encapsulates our calling into the DISKCOPY.DLL
typedef struct { HINSTANCE hDISKCOPY_DLL; PDISKCOPY_MAKEBOOTDISK_ROUTINE MakeBootDisk; } DISKCOPY;
// This structure described the current formatting session
typedef struct { LONG cRef; // reference count on this structure
UINT drive; // 0-based index of drive to format
UINT fmtID; // Last format ID
UINT options; // options passed to us via the API
FMIFS fmifs; // above
DISKCOPY diskcopy; // above
HWND hDlg; // handle to the format dialog
BOOL fIsFloppy; // TRUE -> its a floppy
BOOL fIs35HDFloppy; // TRUE -> its a standard 3.5" High Density floppy
BOOL fIsMemoryStick; // TRUE -> its a memory stick (special formatting only)
BOOL fIsNTFSBlocked; // TRUE -> its a NTFS not-supported device
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?
BOOL fDisabled; // Is rgfControlEnabled[] valid?
DWORD dwClusterSize; // Orig NT cluster size, or last choice
WCHAR wszVolName[MAX_PATH]; // Volume Label
WCHAR wszDriveName[4]; // Root path to drive (eg: A:\)
HANDLE hThread; // Handle of format thread
// Array of media types supported by the device
// for NT5, we have an expanded list that includes japanese types.
FMIFS_MEDIA_TYPE rgMedia[IDS_FMT_MEDIA_J22-IDS_FMT_MEDIA_J0];
// Used to cache the enabled/disabled state of the dialog controls
BOOL rgfControlEnabled[DLG_FORMATDISK_NUMCONTROLS];
// should we create a boot disk rather than a traditional format
BOOL fMakeBootDisk;
} FORMATINFO;
//
// An enumeration to make the filesystem combo-box code more readble
//
typedef enum tagFILESYSENUM { e_FAT = 0, e_NTFS, e_FAT32 } FILESYSENUM;
#define FS_STR_NTFS TEXT("NTFS")
#define FS_STR_FAT32 TEXT("FAT32")
#define FS_STR_FAT TEXT("FAT")
//
// 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;
//
// Synopsis: Loads FMIFS.DLL and sets up the function entry points for
// the member functions we are interested in.
//
HRESULT LoadFMIFS(FMIFS *pFMIFS) { HRESULT hr = S_OK;
//
// Load the FMIFS DLL and query for the entry points we need
//
// SECURITY: what non-relative path do we use that will work on ia64 too?
if (NULL == (pFMIFS->hFMIFS_DLL = LoadLibrary(TEXT("FMIFS.DLL")))) { hr = HRESULT_FROM_WIN32(GetLastError()); } else if (NULL == (pFMIFS->FormatEx = (PFMIFS_FORMATEX_ROUTINE) GetProcAddress(pFMIFS->hFMIFS_DLL, "FormatEx"))) { hr = HRESULT_FROM_WIN32(GetLastError()); } else if (NULL == (pFMIFS->QuerySupportedMedia = (PFMIFS_QSUPMEDIA_ROUTINE) GetProcAddress(pFMIFS->hFMIFS_DLL, "QuerySupportedMedia"))) { hr = HRESULT_FROM_WIN32(GetLastError()); } else if (NULL == (pFMIFS->EnableVolumeCompression = (PFMIFS_ENABLECOMP_ROUTINE) GetProcAddress(pFMIFS->hFMIFS_DLL, "EnableVolumeCompression"))) { hr = HRESULT_FROM_WIN32(GetLastError()); } else if (NULL == (pFMIFS->ChkDskEx = (PFMIFS_CHKDSKEX_ROUTINE) GetProcAddress(pFMIFS->hFMIFS_DLL, "ChkdskEx"))) { hr = HRESULT_FROM_WIN32(GetLastError()); } else if (NULL == (pFMIFS->QueryDeviceInformation = (PFMIFS_QUERY_DEVICE_INFO_ROUTINE) GetProcAddress(pFMIFS->hFMIFS_DLL, "QueryDeviceInformation"))) { 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; }
//
// Synopsis: Loads DISKCOPY.DLL and sets up the function entry points for
// the member functions we are interested in.
//
HRESULT LoadDISKCOPY(DISKCOPY *pDISKCOPY) { HRESULT hr = S_OK;
//
// Load the DISKCOPY DLL and query for the entry points we need
//
// SECURITY: what non-relative path do we use that will work on ia64 too?
if (NULL == (pDISKCOPY->hDISKCOPY_DLL = LoadLibrary(TEXT("DISKCOPY.DLL")))) { hr = HRESULT_FROM_WIN32(GetLastError()); } else if (NULL == (pDISKCOPY->MakeBootDisk = (PDISKCOPY_MAKEBOOTDISK_ROUTINE) GetProcAddress(pDISKCOPY->hDISKCOPY_DLL, MAKEINTRESOURCEA(1)))) //MakeBootDisk is at ordinal 1 in diskcopy.dll
{ hr = HRESULT_FROM_WIN32(GetLastError()); }
//
// If anything failed, and we've got the DLL loaded, release the DLL
//
if (hr != S_OK && pDISKCOPY->hDISKCOPY_DLL) { FreeLibrary(pDISKCOPY->hDISKCOPY_DLL); } return hr; }
void AddRefFormatInfo(FORMATINFO *pFormatInfo) { InterlockedIncrement(&pFormatInfo->cRef); }
void ReleaseFormatInfo(FORMATINFO *pFormatInfo) { if (InterlockedDecrement(&pFormatInfo->cRef) == 0) { if (pFormatInfo->fmifs.hFMIFS_DLL) { FreeLibrary(pFormatInfo->fmifs.hFMIFS_DLL); }
if (pFormatInfo->diskcopy.hDISKCOPY_DLL) { FreeLibrary(pFormatInfo->diskcopy.hDISKCOPY_DLL); }
if (pFormatInfo->hThread) { CloseHandle(pFormatInfo->hThread); }
LocalFree(pFormatInfo); } }
//
// Thread-Local Storage index for our FORMATINFO structure pointer
//
static DWORD g_iTLSFormatInfo = 0; static LONG g_cTLSFormatInfo = 0; // Usage count
// 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
//
HRESULT StuffFormatInfoPtr(FORMATINFO *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, (void *) pFormatInfo)) { g_cTLSFormatInfo++; } else { hr = HRESULT_FROM_WIN32(GetLastError()); } } LEAVECRITICAL;
return hr; }
// 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
//
void UnstuffFormatInfoPtr() { ENTERCRITICAL; if (0 == --g_cTLSFormatInfo) { TlsFree(g_iTLSFormatInfo); g_iTLSFormatInfo = 0; } LEAVECRITICAL; }
// Synopsis: Retrieves this threads FORMATINFO ptr by grabbing the
// thread-local value previously stuff'd
//
// Arguments: [none]
//
// Returns: The pointer, of course
//
FORMATINFO *GetFormatInfoPtr() { return (FORMATINFO*)TlsGetValue(g_iTLSFormatInfo); }
// Synopsis: Ghosts all controls except "Cancel", saving their
// previous state in the FORMATINFO structure
//
// Arguments: [pFormatInfo] -- Describes a format dialog session
//
// Notes: Also changes "Close" button text to read "Cancel"
//
void DisableControls(FORMATINFO *pFormatInfo) { WCHAR wszCancel[64];
// Do this only if we haven't disabled the controls yet, otherwise
// we double-disable and our rgfControlEnabled[] array gets corrupted.
if (!pFormatInfo->fDisabled) { int i; pFormatInfo->fDisabled = TRUE; for (i = 0; i < DLG_FORMATDISK_NUMCONTROLS; i++) { HWND hControl = GetDlgItem(pFormatInfo->hDlg, i + DLG_FORMATDISK_FIRSTCONTROL); pFormatInfo->rgfControlEnabled[i] = !EnableWindow(hControl, FALSE); } }
EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDOK), FALSE);
LoadString(HINST_THISDLL, IDS_FMT_CANCEL, wszCancel, ARRAYSIZE(wszCancel)); SetWindowText(GetDlgItem(pFormatInfo->hDlg, IDCANCEL), wszCancel); }
// Synopsis: Restores controls to the enabled/disabled state they were
// before a previous call to DisableControls().
//
// Arguments: [pFormatInfo] -- Decribes a format dialog session
// [fReady] - If TRUE, then enable everything
// If FALSE, then enable combo boxes but leave
// buttons in limbo because there is still a format
// pending
//
// Notes: Also changes "Cancel" button to say "Close"
// Also sets focus to Cancel button instead of Start button
//
//--------------------------------------------------------------------------
void EnableControls(FORMATINFO *pFormatInfo, BOOL fReady) { WCHAR wszClose[64]; int i; HWND hwnd;
// Do this only if we have valid info in rgfControlEnabled[].
// This catches the case where we give up on a format because it is
// unstuck, and then finally it unsticks itself and tells us,
// so we go and re-enable a second time.
if (pFormatInfo->fDisabled) { pFormatInfo->fDisabled = FALSE;
for (i = 0; i < DLG_FORMATDISK_NUMCONTROLS; i++) { HWND hControl = GetDlgItem(pFormatInfo->hDlg, i + DLG_FORMATDISK_FIRSTCONTROL); EnableWindow(hControl, pFormatInfo->rgfControlEnabled[i]); } }
hwnd = GetDlgItem(pFormatInfo->hDlg, IDOK); EnableWindow(hwnd, fReady); SendMessage(hwnd, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE,0));
LoadString(HINST_THISDLL, IDS_FMT_CLOSE, wszClose, ARRAYSIZE(wszClose)); hwnd = GetDlgItem(pFormatInfo->hDlg, IDCANCEL); SetWindowText(hwnd, wszClose); SendMessage(hwnd, BM_SETSTYLE, BS_DEFPUSHBUTTON, MAKELPARAM(TRUE,0)); SendMessage(pFormatInfo->hDlg, DM_SETDEFID, IDCANCEL, 0);
// Shove focus only if it's on the OK button. Otherwise we end up
// yanking focus away from a user who is busy dorking with the dialog,
// or -- worse -- dorking with a completely unrelated dialog!
if (GetFocus() == GetDlgItem(pFormatInfo->hDlg, IDOK)) SetFocus(hwnd); }
// Sets the dialog's title to "Format Floppy (A:)" or
// "Formatting Floppy (A:)"
void SetDriveWindowTitle(HWND hdlg, LPCWSTR pszDrive, UINT ids) { SHFILEINFO sfi; WCHAR wszWinTitle[MAX_PATH]; // Format dialog window title
LoadString(HINST_THISDLL, ids, wszWinTitle, ARRAYSIZE(wszWinTitle));
if (SHGetFileInfo(pszDrive, FILE_ATTRIBUTE_DIRECTORY, &sfi, sizeof(sfi), SHGFI_USEFILEATTRIBUTES | SHGFI_DISPLAYNAME)) { lstrcat(wszWinTitle, sfi.szDisplayName); }
SetWindowText(hdlg, wszWinTitle); }
//
// 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: [fsenum] -- One of e_FAT, e_NTFS, or e_FAT32
// [pFormatInfo] -- Current format dialog session
//
void FileSysChange(FILESYSENUM fsenum, FORMATINFO *pFormatInfo) { WCHAR wszTmp[MAX_PATH];
switch (fsenum) { case e_FAT: case e_FAT32: { // un-check & disable the "Enable Compression" checkbox
CheckDlgButton(pFormatInfo->hDlg, IDC_ECCHECK, FALSE); EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_ECCHECK), FALSE);
SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_RESETCONTENT, 0, 0); LoadString(HINST_THISDLL, IDS_FMT_ALLOC0, wszTmp, ARRAYSIZE(wszTmp)); SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_ADDSTRING, 0, (LPARAM)wszTmp); SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_SETCURSEL, 0, 0); } break; case e_NTFS: { int i;
// un-check & disable the "Enable Compression" checkbox
EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_ECCHECK), TRUE); CheckDlgButton(pFormatInfo->hDlg, IDC_ECCHECK, pFormatInfo->fEnableComp);
// 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++) { LoadString(HINST_THISDLL, i, wszTmp, ARRAYSIZE(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; } }
//
// Is this drive a GPT drive?
// GPT drive: Guid-Partition Table - a replacement for the Master Boot Record, used on some IA64 machines, can only use NTFS
BOOL IsGPTDrive(int iDrive) { BOOL fRetVal = FALSE; #ifdef _WIN64
HANDLE hDrive; TCHAR szDrive[] = TEXT("\\\\.\\A:");
ASSERT(iDrive < 26); szDrive[4] += (TCHAR)iDrive; hDrive = CreateFile(szDrive, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != hDrive) { PARTITION_INFORMATION_EX partitionEx; DWORD cbReturned; if (DeviceIoControl(hDrive, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, (void*)&partitionEx, sizeof(PARTITION_INFORMATION_EX), &cbReturned, NULL)) { if (partitionEx.PartitionStyle == PARTITION_STYLE_GPT) { fRetVal = TRUE; } } CloseHandle(hDrive); } #endif
return fRetVal; }
BOOL IsDVDRAMMedia(int iDrive) { BOOL fRetVal = FALSE; CMountPoint *pmtpt = CMountPoint::GetMountPoint(iDrive); if (pmtpt) { DWORD dwMediaCap, dwDriveCap; if (SUCCEEDED(pmtpt->GetCDInfo(&dwDriveCap, &dwMediaCap))) { fRetVal = (dwMediaCap & HWDMC_DVDRAM); } pmtpt->Release(); }
return fRetVal; }
#define GIG_INBYTES (1024 * 1024 * 1024)
//
// FAT32 has some limit which prevents the number of clusters from being
// less than 65526. And minimum cluster size is 512 bytes. So minimum FAT32
// volume size is 65526*512.
#define FAT32_MIN ((ULONGLONG)65526*512)
#define FMTAVAIL_MASK_MIN 0x1
#define FMTAVAIL_MASK_MAX 0x2
#define FMTAVAIL_MASK_REQUIRE 0x3
#define FMTAVAIL_MASK_FORBID 0x4
#define FMTAVAIL_TYPE_FLOPPY 0x1
#define FMTAVAIL_TYPE_DVDRAM 0x2
#define FMTAVAIL_TYPE_GPT 0x4
#define FMTAVAIL_TYPE_MEMSTICK 0x8
#define FMTAVAIL_TYPE_NTFS_BLOCKED 0x10
typedef struct _FMTAVAIL { DWORD dwfs; DWORD dwMask; DWORD dwForbiddenTypes; ULONGLONG qMinSize; ULONGLONG qMaxSize; } FMTAVAIL;
FMTAVAIL rgFmtAvail[] = { {e_FAT, FMTAVAIL_MASK_MAX | FMTAVAIL_MASK_FORBID, FMTAVAIL_TYPE_DVDRAM | FMTAVAIL_TYPE_GPT, 0, ((ULONGLONG)2 * GIG_INBYTES) }, {e_FAT32, FMTAVAIL_MASK_MIN | FMTAVAIL_MASK_MAX | FMTAVAIL_MASK_FORBID, FMTAVAIL_TYPE_GPT | FMTAVAIL_TYPE_FLOPPY | FMTAVAIL_TYPE_MEMSTICK, FAT32_MIN, ((ULONGLONG)32 * GIG_INBYTES) }, {e_NTFS, FMTAVAIL_MASK_FORBID, FMTAVAIL_TYPE_DVDRAM | FMTAVAIL_TYPE_FLOPPY | FMTAVAIL_TYPE_MEMSTICK | FMTAVAIL_TYPE_NTFS_BLOCKED, 0, 0 } };
// is a particular disk format available for a drive with given parameters and capacity?
BOOL FormatAvailable (DWORD dwfs, FORMATINFO* pFormatInfo, ULONGLONG* pqwCapacity) { BOOL fAvailable = TRUE; DWORD dwType = 0;
if (pFormatInfo->fIsFloppy) { dwType |= FMTAVAIL_TYPE_FLOPPY; } if (IsDVDRAMMedia(pFormatInfo->drive)) { dwType |= FMTAVAIL_TYPE_DVDRAM; } if (IsGPTDrive(pFormatInfo->drive)) { dwType |= FMTAVAIL_TYPE_GPT; } if (pFormatInfo->fIsMemoryStick) { dwType |= FMTAVAIL_TYPE_MEMSTICK; } if (pFormatInfo->fIsNTFSBlocked) { dwType |= FMTAVAIL_TYPE_NTFS_BLOCKED; }
for (int i = 0; i < ARRAYSIZE(rgFmtAvail); i++) { // check only entries that match the format we're looking for
if (rgFmtAvail[i].dwfs == dwfs) { // if a failure conditions is true, then this format is unavailable
if ((rgFmtAvail[i].dwMask & FMTAVAIL_MASK_FORBID) && (rgFmtAvail[i].dwForbiddenTypes & dwType)) { fAvailable = FALSE; break; }
if ((rgFmtAvail[i].dwMask & FMTAVAIL_MASK_MIN) && (*pqwCapacity < rgFmtAvail[i].qMinSize)) { fAvailable = FALSE; break; }
if ((rgFmtAvail[i].dwMask & FMTAVAIL_MASK_MAX) && (*pqwCapacity > rgFmtAvail[i].qMaxSize)) { fAvailable = FALSE; break; } } }
return fAvailable; }
HRESULT GetPartitionSizeInBytes(int iDrive, ULONGLONG* pqwPartitionSize) { HRESULT hr = E_FAIL; HANDLE hFile; TCHAR szDrive[] = TEXT("\\\\.\\A:");
*pqwPartitionSize = 0;
ASSERT(iDrive < 26); szDrive[4] += (TCHAR)iDrive; hFile = CreateFile(szDrive, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != hFile) { GET_LENGTH_INFORMATION LengthInfo; DWORD cbReturned;
if (DeviceIoControl(hFile, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, (void*)&LengthInfo, sizeof(LengthInfo), &cbReturned, NULL) && LengthInfo.Length.QuadPart) { *pqwPartitionSize = LengthInfo.Length.QuadPart; hr = S_OK; }
CloseHandle(hFile); }
return hr; }
// this helper function adds a string to a combo box with the associated dword (dwfs) as its itemdata
void _AddFSString(HWND hwndCB, WCHAR* pwsz, DWORD dwfs) { int iIndex = ComboBox_AddString(hwndCB, pwsz); if (iIndex != CB_ERR) { ComboBox_SetItemData(hwndCB, iIndex, dwfs); } }
// We only support formatting these types of devices
const FMIFS_MEDIA_TYPE rgFmtSupported[] = { FmMediaRemovable, FmMediaFixed, FmMediaF3_1Pt44_512, FmMediaF3_120M_512, FmMediaF3_200Mb_512};
//
// 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
//
HRESULT InitializeFormatDlg(FORMATINFO *pFormatInfo) { HRESULT hr = S_OK; ULONG cMedia; HWND hCapacityCombo; HWND hFilesystemCombo; HWND hDlg = pFormatInfo->hDlg; WCHAR wszBuffer[256]; ULONGLONG qwCapacity = 0;
// Set up some typical default values
pFormatInfo->fEnableComp = FALSE; pFormatInfo->dwClusterSize = 0; pFormatInfo->fIsFloppy = TRUE; pFormatInfo->fIsMemoryStick = FALSE; pFormatInfo->fIsNTFSBlocked = FALSE; pFormatInfo->fIs35HDFloppy = TRUE; pFormatInfo->fWasFAT = TRUE; pFormatInfo->fFinishedOK = FALSE; pFormatInfo->fErrorAlready = FALSE; pFormatInfo->wszVolName[0] = L'\0';
// Initialize the Quick Format checkbox based on option passed to the SHFormatDrive() API
Button_SetCheck(GetDlgItem(hDlg, IDC_QFCHECK), pFormatInfo->options & SHFMT_OPT_FULL);
// Set the dialog title to indicate which drive we are dealing with
PathBuildRootW(pFormatInfo->wszDriveName, pFormatInfo->drive); SetDriveWindowTitle(pFormatInfo->hDlg, pFormatInfo->wszDriveName, IDS_FMT_FORMAT);
// Query the supported media types for the drive in question
if (!pFormatInfo->fmifs.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) { UINT olderror; ULONG i; ULONG j;
hCapacityCombo = GetDlgItem(hDlg, IDC_CAPCOMBO); hFilesystemCombo = GetDlgItem(hDlg, IDC_FSCOMBO);
ASSERT(hCapacityCombo && hFilesystemCombo);
FMIFS_DEVICE_INFORMATION fmifsdeviceinformation; BOOL fOk = pFormatInfo->fmifs.QueryDeviceInformation( pFormatInfo->wszDriveName, &fmifsdeviceinformation, sizeof(fmifsdeviceinformation));
if (fOk) { if (fmifsdeviceinformation.Flags & FMIFS_SONY_MS) { pFormatInfo->fIsMemoryStick = TRUE; }
if (fmifsdeviceinformation.Flags & FMIFS_NTFS_NOT_SUPPORTED) { pFormatInfo->fIsNTFSBlocked = TRUE; } }
// Allow only certain media types
j = 0; for (i = 0; i < cMedia; i++) { for (int k = 0; k < ARRAYSIZE(rgFmtSupported); k++) { if (pFormatInfo->rgMedia[i] == rgFmtSupported[k]) { pFormatInfo->rgMedia[j] = pFormatInfo->rgMedia[i]; j++; break; } } } cMedia = j;
if (0 == cMedia) { hr = ERROR_UNRECOGNIZED_MEDIA; } else { 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; }
// if we find any non-3.5" HD floppy format, clear the fIs35HDFloppy flag
if (FmMediaF3_1Pt44_512 != pFormatInfo->rgMedia[i]) { pFormatInfo->fIs35HDFloppy = 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] || (FmMediaRemovable == pFormatInfo->rgMedia[i])) { DWORD dwSectorsPerCluster, dwBytesPerSector, dwFreeClusters, dwClusters;
if (SUCCEEDED(GetPartitionSizeInBytes(pFormatInfo->drive, &qwCapacity))) { // Add a capacity desciption to the combobox
ShortSizeFormat64(qwCapacity, wszBuffer, ARRAYSIZE(wszBuffer)); } else { // Couldn't get the free space... prob. not fatal
LoadString(HINST_THISDLL, IDS_FMT_CAPUNKNOWN, wszBuffer, sizeof(wszBuffer)); } ComboBox_AddString(hCapacityCombo, wszBuffer);
if (GetDiskFreeSpace(pFormatInfo->wszDriveName, &dwSectorsPerCluster, &dwBytesPerSector, &dwFreeClusters, &dwClusters)) { pFormatInfo->dwClusterSize = dwBytesPerSector * dwSectorsPerCluster; } } else { // removable media:
//
// add a capacity desciption to the combo baseed on the sequential list of
// media format descriptors
LoadString(HINST_THISDLL, IDS_FMT_MEDIA0 + pFormatInfo->rgMedia[i], wszBuffer, ARRAYSIZE(wszBuffer)); ComboBox_AddString(hCapacityCombo, wszBuffer); } }
// set capacity to default
ComboBox_SetCurSel(hCapacityCombo, 0);
// Add the appropriate filesystem selections to the combobox
// We now prioritize NTFS
if (FormatAvailable(e_NTFS, pFormatInfo, &qwCapacity)) { _AddFSString(hFilesystemCombo, FS_STR_NTFS, e_NTFS); }
if (FormatAvailable(e_FAT32, pFormatInfo, &qwCapacity)) {
_AddFSString(hFilesystemCombo, FS_STR_FAT32, e_FAT32); }
if (FormatAvailable(e_FAT, pFormatInfo, &qwCapacity)) { _AddFSString(hFilesystemCombo, FS_STR_FAT, e_FAT); }
// By default, pick the 0-th entry in the _nonsorted_ combobox.
// NOTE: this can be overwritten below
ComboBox_SetCurSel(hFilesystemCombo, 0);
// If we can determine something other than FAT is being used,
// select it as the default in the combobox
olderror = SetErrorMode(SEM_FAILCRITICALERRORS);
if (GetVolumeInformation(pFormatInfo->wszDriveName, pFormatInfo->wszVolName, ARRAYSIZE(pFormatInfo->wszVolName), NULL, NULL, NULL, wszBuffer, ARRAYSIZE(wszBuffer))) { // If we got a current volume label, stuff it in the edit control
if (pFormatInfo->wszVolName[0] != L'\0') { SetWindowText(GetDlgItem(pFormatInfo->hDlg, IDC_VLABEL), pFormatInfo->wszVolName); }
// for non-floppies we default to keeping the FS the same as the current one
if (!pFormatInfo->fIsFloppy) { if (0 == lstrcmpi(FS_STR_NTFS, wszBuffer)) { ComboBox_SelectString(hFilesystemCombo, -1, FS_STR_NTFS); pFormatInfo->fWasFAT = FALSE; } else if (0 == lstrcmpi(FS_STR_FAT32, wszBuffer)) { ComboBox_SelectString(hFilesystemCombo, -1, FS_STR_FAT32); pFormatInfo->fWasFAT = TRUE; pFormatInfo->dwClusterSize = 0; } else { ComboBox_SelectString(hFilesystemCombo, -1, FS_STR_FAT); pFormatInfo->fWasFAT = TRUE; pFormatInfo->dwClusterSize = 0; } } // FEATURE - What about specialized file-systems? Don't care for now.
}
#ifndef _WIN64
// if not WIN64, enable boot-disk creation if we are a 3.5" HD floppy
EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_BTCHECK), pFormatInfo->fIs35HDFloppy); #else
// if WIN64, hide this option, since we can't use these boot floppies on WIN64
ShowWindow(GetDlgItem(pFormatInfo->hDlg, IDC_BTCHECK), FALSE); #endif
// restore the old errormode
SetErrorMode(olderror);
// set the state of the chkboxes properly based on the FS chosen
FileSysChange((FILESYSENUM)ComboBox_GetItemData(hFilesystemCombo, ComboBox_GetCurSel(hFilesystemCombo)), pFormatInfo); } }
// If the above failed due to disk not in drive, notify the user
if (FAILED(hr)) { switch (HRESULT_CODE(hr)) { case ERROR_UNRECOGNIZED_MEDIA: ShellMessageBox(HINST_THISDLL, hDlg, MAKEINTRESOURCE(IDS_UNFORMATTABLE_DISK), NULL, MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK, NULL);
break;
case ERROR_NOT_READY: ShellMessageBox(HINST_THISDLL, hDlg, MAKEINTRESOURCE(IDS_DRIVENOTREADY), NULL, MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK, pFormatInfo->wszDriveName[0]); break;
case ERROR_ACCESS_DENIED: ShellMessageBox(HINST_THISDLL, hDlg, MAKEINTRESOURCE(IDS_ACCESSDENIED), NULL, MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK, pFormatInfo->wszDriveName[0]); break;
case ERROR_WRITE_PROTECT: ShellMessageBox(HINST_THISDLL, hDlg, MAKEINTRESOURCE(IDS_WRITEPROTECTED), NULL, MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK, pFormatInfo->wszDriveName[0]); break; } }
return hr; }
// 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
//
BOOLEAN FormatCallback(FMIFS_PACKET_TYPE PacketType, ULONG PacketLength, void *pPacketData) { UINT iMessageID = IDS_FORMATFAILED; BOOL fFailed = FALSE; FORMATINFO* pFormatInfo = GetFormatInfoPtr();
ASSERT(g_iTLSFormatInfo);
// Grab the FORMATINFO structure for this thread
if (pFormatInfo) { if (!pFormatInfo->fShouldCancel) { 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) { // fmifs will "succeed" even if we already failed, so we need to double-check
// that we haven't already put up error UI
if (!pFormatInfo->fErrorAlready) { // If "Enable Compression" is checked, try to enable filesystem compression
if (IsDlgButtonChecked(pFormatInfo->hDlg, IDC_ECCHECK)) { if (pFormatInfo->fmifs.EnableVolumeCompression(pFormatInfo->wszDriveName, COMPRESSION_FORMAT_DEFAULT) == FALSE) { 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, // set %100 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 (fFailed && !pFormatInfo->fErrorAlready) { // If we received any kind of failure information, put up a final
// "Format Failed" message. UNLESS we've already put up some nice message
ShellMessageBox(HINST_THISDLL, pFormatInfo->hDlg, MAKEINTRESOURCE(iMessageID), NULL, MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK);
pFormatInfo->fErrorAlready = TRUE; } } else { // user hit cancel
pFormatInfo->fCancelled = TRUE; fFailed = TRUE; } } else { // no pFormatInfo? we're screwed
fFailed = TRUE; }
return (BOOLEAN) (fFailed == FALSE); }
//
// 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
//
DWORD WINAPI BeginFormat(void * pIn) { FORMATINFO *pFormatInfo = (FORMATINFO*)pIn; HRESULT hr = S_OK; // Save the FORAMTINFO ptr for this thread, to be used in the format
// callback function
hr = StuffFormatInfoPtr(pFormatInfo); if (hr == S_OK) { HWND hwndFileSysCB = GetDlgItem(pFormatInfo->hDlg, IDC_FSCOMBO); int iCurSel;
// Set the window title to indicate format in proress...
SetDriveWindowTitle(pFormatInfo->hDlg, pFormatInfo->wszDriveName, IDS_FMT_FORMATTING);
// Determine the user's choice of filesystem
iCurSel = ComboBox_GetCurSel(hwndFileSysCB); if (iCurSel != CB_ERR) { LPCWSTR pwszFileSystemName; FMIFS_MEDIA_TYPE MediaType; LPITEMIDLIST pidlFormat; BOOLEAN fQuickFormat;
FILESYSENUM fseType = (FILESYSENUM)ComboBox_GetItemData(hwndFileSysCB, iCurSel);
switch (fseType) { case e_FAT: pwszFileSystemName = FS_STR_FAT; break;
case e_FAT32: pwszFileSystemName = FS_STR_FAT32; break;
case e_NTFS: pwszFileSystemName = FS_STR_NTFS; break; }
// Determine the user's choice of media formats
iCurSel = ComboBox_GetCurSel(GetDlgItem(pFormatInfo->hDlg, IDC_CAPCOMBO)); if (iCurSel == CB_ERR) { iCurSel = 0; } MediaType = pFormatInfo->rgMedia[iCurSel];
// Get the cluster size. First selection ("Use Default") yields a zero,
// while the next 4 select 512, 1024, 2048, or 4096
iCurSel = ComboBox_GetCurSel(GetDlgItem(pFormatInfo->hDlg, IDC_ASCOMBO)); if ((iCurSel == CB_ERR) || (iCurSel == 0)) { pFormatInfo->dwClusterSize = 0; } else { pFormatInfo->dwClusterSize = 256 << iCurSel; }
// Quickformatting?
fQuickFormat = Button_GetCheck(GetDlgItem(pFormatInfo->hDlg, IDC_QFCHECK));
// Clear the error state.
pFormatInfo->fErrorAlready = FALSE;
// Tell the shell to get ready... Announce that the media is no
// longer valid (so people who have active views on it will navigate
// away) and tell the shell to close its FindFirstChangeNotifications.
if (SUCCEEDED(SHILCreateFromPath(pFormatInfo->wszDriveName, &pidlFormat, NULL))) { SHChangeNotify(SHCNE_MEDIAREMOVED, SHCNF_IDLIST | SHCNF_FLUSH, pidlFormat, 0); SHChangeNotifySuspendResume(TRUE, pidlFormat, TRUE, 0); } else { pidlFormat = NULL; }
if (!pFormatInfo->fMakeBootDisk) { // Do the format.
pFormatInfo->fmifs.FormatEx(pFormatInfo->wszDriveName, MediaType, (PWSTR)pwszFileSystemName, pFormatInfo->wszVolName, fQuickFormat, pFormatInfo->dwClusterSize, FormatCallback); } else { pFormatInfo->diskcopy.MakeBootDisk(pFormatInfo->diskcopy.hDISKCOPY_DLL, pFormatInfo->drive, &pFormatInfo->fCancelled, FormatCallback); }
// Wake the shell back up.
if (pidlFormat) { SHChangeNotifySuspendResume(FALSE, pidlFormat, TRUE, 0); ILFree(pidlFormat); }
// 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, (void *)pFormatInfo->wszDriveName, NULL); } else { // couldn't get the filesys CB selection
hr = E_FAIL; }
// 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);
ReleaseFormatInfo(pFormatInfo);
return (DWORD)hr; }
BOOL_PTR CALLBACK FormatDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam) { HRESULT hr = S_OK; int iID = GET_WM_COMMAND_ID(wParam, lParam); int iCMD = GET_WM_COMMAND_CMD(wParam, lParam);
// Grab our previously cached pointer to the FORMATINFO struct (see WM_INITDIALOG)
FORMATINFO *pFormatInfo = (FORMATINFO *) GetWindowLongPtr(hDlg, DWLP_USER);
switch (wMsg) { case PWM_FORMATDONE: // Format is done. Reset the window title and clear the progress meter
SetDriveWindowTitle(pFormatInfo->hDlg, pFormatInfo->wszDriveName, IDS_FMT_FORMAT); SendDlgItemMessage(pFormatInfo->hDlg, IDC_FMTPROGRESS, PBM_SETPOS, 0 /* Reset Percent Complete */, 0); EnableControls(pFormatInfo, TRUE);
if (pFormatInfo->fCancelled) { // Don't put up UI if the background thread finally finished
// long after the user issued the cancel
if (!pFormatInfo->fShouldCancel) { ShellMessageBox(HINST_THISDLL, pFormatInfo->hDlg, MAKEINTRESOURCE(IDS_FORMATCANCELLED), NULL, MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK); } pFormatInfo->fCancelled = FALSE; }
if (pFormatInfo->hThread) { CloseHandle(pFormatInfo->hThread); pFormatInfo->hThread = NULL; } break;
case WM_INITDIALOG: // Initialize the dialog and cache the FORMATINFO structure's pointer
// as our dialog's DWLP_USER data
pFormatInfo = (FORMATINFO *) lParam; pFormatInfo->hDlg = hDlg; if (FAILED(InitializeFormatDlg(pFormatInfo))) { EndDialog(hDlg, 0); return -1; } SetWindowLongPtr(hDlg, DWLP_USER, lParam); break;
case WM_DESTROY: if (pFormatInfo && pFormatInfo->hDlg) { pFormatInfo->hDlg = NULL; } break;
case WM_COMMAND: if (iCMD == CBN_SELCHANGE) { // User made a selection in one of the combo boxes
if (iID == IDC_FSCOMBO) { // User selected a filesystem... update the rest of the dialog
// based on this choice
HWND hFilesystemCombo = (HWND)lParam; int iCurSel = ComboBox_GetCurSel(hFilesystemCombo);
FileSysChange((FILESYSENUM)ComboBox_GetItemData(hFilesystemCombo, iCurSel), pFormatInfo); } } else { // Codepath for controls other than combo boxes...
switch (iID) { case IDC_BTCHECK: pFormatInfo->fMakeBootDisk = IsDlgButtonChecked(pFormatInfo->hDlg, IDC_BTCHECK); EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_CAPCOMBO), !pFormatInfo->fMakeBootDisk); EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_FSCOMBO), !pFormatInfo->fMakeBootDisk); EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_ASCOMBO), !pFormatInfo->fMakeBootDisk); EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_VLABEL), !pFormatInfo->fMakeBootDisk); EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_QFCHECK), !pFormatInfo->fMakeBootDisk); break; case IDC_ECCHECK: pFormatInfo->fEnableComp = IsDlgButtonChecked(hDlg, IDC_ECCHECK); break;
case IDOK: { // 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; }
ASSERT(pFormatInfo->hThread == NULL);
DisableControls(pFormatInfo); pFormatInfo->fCancelled = FALSE; pFormatInfo->fShouldCancel = FALSE; GetWindowText(GetDlgItem(pFormatInfo->hDlg, IDC_VLABEL), pFormatInfo->wszVolName, MAX_PATH); AddRefFormatInfo(pFormatInfo); pFormatInfo->hThread = CreateThread(NULL, 0, BeginFormat, (void *)pFormatInfo, 0, NULL); if (!pFormatInfo->hThread) { // ISSUE: we should probably do something...
ReleaseFormatInfo(pFormatInfo); } } 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, 10000); } 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. Just abandon it and let it clean up
// when it finally gets around to it, at which point we will
// enable the OK button to let the user take another stab.
//
// Careful: The format may have cleaned up while the dialog box
// was up, so revalidate.
if (pFormatInfo->hThread) { CloseHandle(pFormatInfo->hThread); pFormatInfo->hThread = NULL; pFormatInfo->fCancelled = TRUE; EnableControls(pFormatInfo, FALSE); } } else { EndDialog(hDlg, IDCANCEL); } break; } } break;
case WM_HELP: WinHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP, (ULONG_PTR) (LPSTR) FmtaIds); break;
case WM_CONTEXTMENU: WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU, (ULONG_PTR) (LPSTR) FmtaIds); break;
default: return FALSE; }
return TRUE; }
//
// 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
//
DWORD WINAPI SHFormatDrive(HWND hwnd, UINT drive, UINT fmtID, UINT options) { INT_PTR ret; FORMATINFO *pFormatInfo = (FORMATINFO *)LocalAlloc(LPTR, sizeof(*pFormatInfo)); ASSERT(drive < 26);
if (!pFormatInfo) return SHFMT_ERROR;
HRESULT hrCoInit = SHCoInitialize();
pFormatInfo->cRef = 1; pFormatInfo->drive = drive; pFormatInfo->fmtID = fmtID; pFormatInfo->options = options;
// It makes no sense for NT to "SYS" a disk
if (pFormatInfo->options & SHFMT_OPT_SYSONLY) { ret = 0; goto done; }
// Load FMIFS.DLL and DISKCOPY.DLL and open the Format dialog
if (S_OK == LoadFMIFS(&pFormatInfo->fmifs) && S_OK == LoadDISKCOPY(&pFormatInfo->diskcopy)) { DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_FORMATDISK), hwnd, FormatDlgProc, (LPARAM) pFormatInfo); } else { ASSERT(0 && "Can't load FMIFS.DLL"); ret = SHFMT_ERROR; goto done; }
// Since time immemorial it has been almost impossible to
// get SHFMT_CANCEL as a return code. Most of the time, you get
// SHFMT_ERROR if the user cancels.
if (pFormatInfo->fCancelled) { ret = SHFMT_CANCEL; } else if (pFormatInfo->fFinishedOK) { // APPCOMPAT: (stephstm) We used to say that we return the Serial
// Number but we never did. So keep on returning 0 for success.
// Furthermore, Serial number values could conflict SHFMT_*
// error codes.
ret = 0; } else { ret = SHFMT_ERROR; }
done: ReleaseFormatInfo(pFormatInfo); SHCoUninitialize(hrCoInit); return (DWORD)ret; }
////////////////////////////////////////////////////////////////////////////
//
// CHKDSK
//
////////////////////////////////////////////////////////////////////////////
//
// This structure described the current chkdsk session
//
typedef struct { UINT lastpercent; // last percentage complete received
UINT currentphase; // current chkdsk phase
FMIFS fmifs; // 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[MAX_PATH]; // For example, "A:\", or "C:\folder\mountedvolume\"
LONG cRef; // reference count on this structure
} CHKDSKINFO;
void AddRefChkDskInfo(CHKDSKINFO *pChkDskInfo) { InterlockedIncrement(&pChkDskInfo->cRef); }
void ReleaseChkDskInfo(CHKDSKINFO *pChkDskInfo) { if (InterlockedDecrement(&pChkDskInfo->cRef) == 0) { if (pChkDskInfo->fmifs.hFMIFS_DLL) { FreeLibrary(pChkDskInfo->fmifs.hFMIFS_DLL); }
if (pChkDskInfo->hThread) { CloseHandle(pChkDskInfo->hThread); }
LocalFree(pChkDskInfo); } }
static DWORD g_iTLSChkDskInfo = 0; static LONG g_cTLSChkDskInfo = 0; // Usage count
//
// 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
//
//
// Thread-Local Storage index for our CHKDSKINFO structure pointer
//
HRESULT StuffChkDskInfoPtr(CHKDSKINFO *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) { g_iTLSChkDskInfo = TlsAlloc();
if (g_iTLSChkDskInfo == (DWORD)-1) { hr = HRESULT_FROM_WIN32(GetLastError()); } g_cTLSChkDskInfo = 0; }
if (S_OK == hr) { if (TlsSetValue(g_iTLSChkDskInfo, (void *)pChkDskInfo)) { g_cTLSChkDskInfo++; } else { hr = HRESULT_FROM_WIN32(GetLastError()); } } LEAVECRITICAL;
return hr; }
//
// 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
//
void UnstuffChkDskInfoPtr() { ENTERCRITICAL; g_cTLSChkDskInfo--;
if (g_cTLSChkDskInfo == 0) { TlsFree(g_iTLSChkDskInfo); g_iTLSChkDskInfo = 0; } LEAVECRITICAL; }
//
// Synopsis: Retrieves this threads CHKDSKINFO ptr by grabbing the
// thread-local value previously stuff'd
//
// Arguments: [none]
//
// Returns: The pointer, of course
//
CHKDSKINFO *GetChkDskInfoPtr() { return (CHKDSKINFO *)TlsGetValue(g_iTLSChkDskInfo); }
//
// Synopsis: Ghosts all controls except "Cancel", saving their
// previous state in the CHKDSKINFO structure
//
// Arguments: [pChkDskInfo] -- Describes a ChkDsk dialog session
//
// Notes: Also changes "Close" button text to read "Cancel"
//
void DisableChkDskControls(CHKDSKINFO *pChkDskInfo) { // 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); }
//
// Synopsis: Restores controls to the enabled/disabled state they were
// before a previous call to DisableControls().
//
// Arguments: [pChkDskInfo] -- Decribes a chkdsk dialog session
//
void EnableChkDskControls(CHKDSKINFO *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);
// Erase the current phase text
SetWindowText(GetDlgItem(pChkDskInfo->hDlg, IDC_PHASE), TEXT("")); pChkDskInfo->lastpercent = 101; pChkDskInfo->currentphase = 0; }
//
// 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
//
BOOLEAN ChkDskCallback(FMIFS_PACKET_TYPE PacketType, ULONG PacketLength, void *pPacketData) { UINT iMessageID = IDS_CHKDSKFAILED; BOOL fFailed = FALSE; CHKDSKINFO* pChkDskInfo = GetChkDskInfoPtr();
ASSERT(g_iTLSChkDskInfo);
// Grab the CHKDSKINFO structure for this thread
if (pChkDskInfo) { if (!pChkDskInfo->fShouldCancel) { 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;
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, // updatee % complete
0);
if (pPercent->PercentCompleted < pChkDskInfo->lastpercent) { WCHAR wszTmp[100]; WCHAR wszFormat[100]; // 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.
LoadString(HINST_THISDLL, IDS_CHKPHASE, wszFormat, ARRAYSIZE(wszFormat)); wsprintf(wszTmp, wszFormat, ++(pChkDskInfo->currentphase)); SetDlgItemText(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;
// ChkDskEx now return the proper success value
if (pFinishedInfo->Success) { // Since we're done, force the progress gauge to 100%, so we
// don't sit here 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);
SetDlgItemText(pChkDskInfo->hDlg, IDC_PHASE, TEXT(""));
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 && (pChkDskInfo->fNoFinalMsg == FALSE)) { pChkDskInfo->fNoFinalMsg = TRUE;
ShellMessageBox(HINST_THISDLL, pChkDskInfo->hDlg, MAKEINTRESOURCE(iMessageID), NULL, MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK);
}
} else { // If the user has signalled to abort the ChkDsk, return
// FALSE out of here right now
pChkDskInfo->fCancelled = TRUE; fFailed = TRUE; } } else { fFailed = TRUE; }
return (BOOLEAN) (fFailed == FALSE); }
void DoChkDsk(CHKDSKINFO* pChkDskInfo, LPWSTR pwszFileSystem) { TCHAR szVolumeGUID[50]; // 50: from doc
FMIFS_CHKDSKEX_PARAM param = {0};
param.Major = 1; param.Minor = 0; param.Flags = pChkDskInfo->fRecovery ? FMIFS_CHKDSK_RECOVER : 0;
GetVolumeNameForVolumeMountPoint(pChkDskInfo->wszDriveName, szVolumeGUID, ARRAYSIZE(szVolumeGUID));
// the backslash at the end means check for fragmentation.
PathRemoveBackslash(szVolumeGUID);
pChkDskInfo->fmifs.ChkDskEx(szVolumeGUID, pwszFileSystem, (BOOLEAN)pChkDskInfo->fFixErrors, ¶m, ChkDskCallback); }
//
// 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
//
DWORD WINAPI BeginChkDsk(void * pIn) { CHKDSKINFO *pChkDskInfo = (CHKDSKINFO *)pIn; HRESULT hr;
// Save the CHKDSKINFO ptr for this thread, to be used in the ChkDsk
// callback function
hr = StuffChkDskInfoPtr(pChkDskInfo); if (hr == S_OK) { WCHAR swzFileSystem[MAX_PATH];
// Get the filesystem in use on the device
if (GetVolumeInformationW(pChkDskInfo->wszDriveName, NULL, 0, NULL, NULL, NULL, swzFileSystem, MAX_PATH)) { // Set the window title to indicate ChkDsk in proress...
SetDriveWindowTitle(pChkDskInfo->hDlg, pChkDskInfo->wszDriveName, IDS_CHKINPROGRESS);
pChkDskInfo->fNoFinalMsg = FALSE;
// Should we try data recovery?
pChkDskInfo->fRecovery = IsDlgButtonChecked(pChkDskInfo->hDlg, IDC_RECOVERY);
// Should we fix filesystem errors?
pChkDskInfo->fFixErrors = IsDlgButtonChecked(pChkDskInfo->hDlg, IDC_FIXERRORS);
// just do it!
DoChkDsk(pChkDskInfo, swzFileSystem);
} else { hr = HRESULT_FROM_WIN32(GetLastError()); } // Release the TLS index
UnstuffChkDskInfoPtr(); }
PostMessage(pChkDskInfo->hDlg, (UINT) PWM_CHKDSKDONE, 0, 0); ReleaseChkDskInfo(pChkDskInfo);
return (DWORD)hr; }
//
// 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.
//
BOOL_PTR CALLBACK ChkDskDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam) { HRESULT hr = S_OK; int iID = GET_WM_COMMAND_ID(wParam, lParam);
// Grab our previously cached pointer to the CHKDSKINFO struct (see WM_INITDIALOG)
CHKDSKINFO *pChkDskInfo = (CHKDSKINFO *) GetWindowLongPtr(hDlg, DWLP_USER);
switch (wMsg) { // done. Reset the window title and clear the progress meter
case PWM_CHKDSKDONE: { // chdsk is done. Reset the window title and clear the progress meter
SetDriveWindowTitle(pChkDskInfo->hDlg, pChkDskInfo->wszDriveName, IDS_CHKDISK);
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); }
if (pChkDskInfo->hThread) { 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 DWLP_USER data
pChkDskInfo = (CHKDSKINFO *) lParam; pChkDskInfo->hDlg = hDlg; SetWindowLongPtr(hDlg, DWLP_USER, lParam);
// Set the dialog title to indicate which drive we are dealing with
SetDriveWindowTitle(pChkDskInfo->hDlg, pChkDskInfo->wszDriveName, IDS_CHKDISK); break;
case WM_DESTROY: if (pChkDskInfo && pChkDskInfo->hDlg) { pChkDskInfo->hDlg = NULL; } break;
case WM_COMMAND: { switch (iID) { case IDC_FIXERRORS: pChkDskInfo->fFixErrors = Button_GetCheck((HWND)lParam); break;
case IDC_RECOVERY: pChkDskInfo->fRecovery = Button_GetCheck((HWND)lParam); break;
case IDOK: { // Get user verification for chkdsk, break out on CANCEL
DisableChkDskControls(pChkDskInfo);
pChkDskInfo->fShouldCancel = FALSE; pChkDskInfo->fCancelled = FALSE; AddRefChkDskInfo(pChkDskInfo); pChkDskInfo->hThread = CreateThread(NULL, 0, BeginChkDsk, (void *)pChkDskInfo, 0, NULL); if (!pChkDskInfo->hThread) { // ISSUE: we should probably do something here...
ReleaseChkDskInfo(pChkDskInfo); } } break;
case IDCANCEL: { // If the chdsk thread is running, wait for it. If not,
// exit the dialog
pChkDskInfo->fCancelled = TRUE; pChkDskInfo->fShouldCancel = TRUE;
if (pChkDskInfo->hThread) { DWORD dwWait;
do { dwWait = WaitForSingleObject(pChkDskInfo->hThread, 10000); } 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. Just abandon it and let it clean up
// when it finally gets around to it, at which point we will
// enable the controls to let the user take another stab.
//
// Careful: The chkdsk may have cleaned up while the dialog box
// was up, so revalidate.
if (pChkDskInfo->hThread) { 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, (ULONG_PTR)(LPSTR)ChkaIds); break; case WM_CONTEXTMENU: WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU, (ULONG_PTR)(LPSTR)ChkaIds); break;
default: return FALSE; }
return TRUE; }
#define GET_INTRESOURCE(r) (LOWORD((UINT_PTR)(r)))
static HDPA hpdaChkdskActive = NULL;
//
// Synopsis: Same as SHChkDskDrive but takes a path rather than a drive int ID
// Call this fct for both path and drive int ID to be protected
// against chkdsk'ing the same drive simultaneously
//
// Arguments: [hwnd] -- Parent window (Must NOT be NULL)
// [pszDrive] -- INTRESOURCE: string if mounted on folder, drive
// number if mounted on drive letter (0 based)
//
STDAPI_(DWORD) SHChkDskDriveEx(HWND hwnd, LPWSTR pszDrive) { HRESULT hr = SHFMT_ERROR; WCHAR szUniqueID[50]; // 50: size of VolumeGUID, which can fit "A:\\" too
CHKDSKINFO *pChkDskInfo = (CHKDSKINFO *)LocalAlloc(LPTR, sizeof(*pChkDskInfo));
if (pChkDskInfo) { hr = S_OK;
// We use a last percentage-complete value of 101, to guarantee that the
// next one received will be less, indicating next (first) phase
pChkDskInfo->lastpercent = 101; pChkDskInfo->cRef = 1;
lstrcpyn(pChkDskInfo->wszDriveName, pszDrive, ARRAYSIZE(pChkDskInfo->wszDriveName)); PathAddBackslash(pChkDskInfo->wszDriveName);
// Prevent multiple chkdsks of the same drive
GetVolumeNameForVolumeMountPoint(pChkDskInfo->wszDriveName, szUniqueID, ARRAYSIZE(szUniqueID));
// scoping ENTERCRITICAL's var definitions to make it cooperate with other ENTERCRITICAL
{ ENTERCRITICAL; if (!hpdaChkdskActive) { hpdaChkdskActive = DPA_Create(1); }
if (hpdaChkdskActive) { int i, n = DPA_GetPtrCount(hpdaChkdskActive);
// Go through the DPA of currently chkdsk'ed volumes, and check if we're already
// processing this volume
for (i = 0; i < n; ++i) { LPWSTR pszUniqueID = (LPWSTR)DPA_GetPtr(hpdaChkdskActive, i);
if (pszUniqueID) { if (!lstrcmpi(szUniqueID, pszUniqueID)) { // we're already chkdsk'ing this drive
hr = E_FAIL; break; } } }
// Looks like we're currently not chkdsk'ing this volume, add it to the DPA of currently
// chkdsk'ed volumes
if (S_OK == hr) { LPWSTR pszUniqueID = StrDup(szUniqueID); if (pszUniqueID) { if (-1 == DPA_AppendPtr(hpdaChkdskActive, pszUniqueID)) { LocalFree((HLOCAL)pszUniqueID);
// if can't allocate room to store a pointer, pretty useless to go on
hr = E_FAIL; } } } } LEAVECRITICAL; }
// Load the FMIFS DLL and open the ChkDsk dialog
if (S_OK == hr) { if (S_OK == LoadFMIFS(&(pChkDskInfo->fmifs))) { INT_PTR ret; INITCOMMONCONTROLSEX icc = {sizeof(icc), ICC_PROGRESS_CLASS}; InitCommonControlsEx(&icc);
ret = DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_CHKDSK), hwnd, ChkDskDlgProc, (LPARAM) pChkDskInfo); if (-1 == ret) { hr = E_UNEXPECTED; } else { if (IDCANCEL == ret) { hr = S_FALSE; } } } else { ASSERT(0 && "Can't load FMIFS.DLL"); hr = E_OUTOFMEMORY; }
// We're finish for this volume, remove from the list of currently processed volumes
ENTERCRITICAL; if (hpdaChkdskActive) { int i, n = DPA_GetPtrCount(hpdaChkdskActive);
for (i = 0; i < n; ++i) { LPWSTR pszUniqueID = (LPWSTR)DPA_GetPtr(hpdaChkdskActive, i); if (pszUniqueID) { if (!lstrcmpi(szUniqueID, pszUniqueID)) { LocalFree((HLOCAL)pszUniqueID);
DPA_DeletePtr(hpdaChkdskActive, i); break; } } } } LEAVECRITICAL; }
// If the DPA is empty delete it
ENTERCRITICAL; if (hpdaChkdskActive && !DPA_GetPtrCount(hpdaChkdskActive)) { DPA_Destroy(hpdaChkdskActive); hpdaChkdskActive = NULL; } LEAVECRITICAL;
ReleaseChkDskInfo(pChkDskInfo); }
return (DWORD) hr; }
//****************************************************************************
//
// Special hook for Win9x app compat
//
// Some Win9x apps like to WinExec("DEFRAG") or WinExec("SCANDSKW")
// even though those apps don't exist on Windows NT. When such apps
// are found, we can shim them to come here instead.
BOOL ScanDskW_OnInitDialog(HWND hdlg) { HICON hico; HWND hwndList; SHFILEINFO sfi; HIMAGELIST himlSys; RECT rc; LVCOLUMN lvc; int iDrive; TCHAR szDrive[4];
hico = (HICON)SendDlgItemMessage(hdlg, IDC_SCANDSKICON, STM_GETICON, 0, 0); SendMessage(hdlg, WM_SETICON, ICON_BIG, (LPARAM)hico); SendMessage(hdlg, WM_SETICON, ICON_SMALL, (LPARAM)hico);
hwndList = GetDlgItem(hdlg, IDC_SCANDSKLV);
if (Shell_GetImageLists(NULL, &himlSys)) { ListView_SetImageList(hwndList, himlSys, LVSIL_SMALL); }
GetClientRect(hwndList, &rc);
lvc.mask = LVCF_WIDTH; lvc.cx = rc.right; lvc.iSubItem = 0; ListView_InsertColumn(hwndList, 0, &lvc);
for (iDrive = 0; iDrive < 26; iDrive++) { PathBuildRoot(szDrive, iDrive); switch (GetDriveType(szDrive)) { case DRIVE_UNKNOWN: case DRIVE_NO_ROOT_DIR: case DRIVE_REMOTE: case DRIVE_CDROM: break; // Can't scan these drives
default: if (SHGetFileInfo(szDrive, FILE_ATTRIBUTE_DIRECTORY, &sfi, sizeof(sfi), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_DISPLAYNAME)) { LVITEM lvi; lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; lvi.iItem = MAXLONG; lvi.iSubItem = 0; lvi.pszText = sfi.szDisplayName; lvi.iImage = sfi.iIcon; lvi.lParam = iDrive; ListView_InsertItem(hwndList, &lvi); } break; }
}
return TRUE; }
void ScanDskW_OnOk(HWND hdlg) { HWND hwndList = GetDlgItem(hdlg, IDC_SCANDSKLV);
LVITEM lvi; lvi.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED); if (lvi.iItem >= 0) { lvi.iSubItem = 0; lvi.mask = LVIF_PARAM; if (ListView_GetItem(hwndList, &lvi)) { TCHAR szDrive[4]; PathBuildRoot(szDrive, (int)lvi.lParam); SHChkDskDriveEx(hdlg, szDrive); } } }
INT_PTR CALLBACK ScanDskW_DlgProc(HWND hdlg, UINT wm, WPARAM wParam, LPARAM lParam) { switch (wm) { case WM_INITDIALOG: return ScanDskW_OnInitDialog(hdlg);
case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDOK: ScanDskW_OnOk(hdlg); break;
case IDCANCEL: EndDialog(hdlg, 0); break; } break;
case WM_NOTIFY: { LPNMHDR pnm = (LPNMHDR)lParam; if (pnm->code == LVN_ITEMCHANGED) { EnableWindow(GetDlgItem(hdlg, IDOK), ListView_GetSelectedCount(GetDlgItem(hdlg, IDC_SCANDSKLV))); } } break; }
return FALSE; }
// Right now, we have only one app compat shim entry point (SCANDSKW)
// In the future we can add others to the command line.
STDAPI_(void) AppCompat_RunDLLW(HWND hwndStub, HINSTANCE hAppInstance, LPWSTR lpwszCmdLine, int nCmdShow) { TCHAR szCmd[MAX_PATH]; LPTSTR pszArgs;
lstrcpyn(szCmd, lpwszCmdLine, ARRAYSIZE(szCmd)); pszArgs = PathGetArgs(szCmd); PathRemoveArgs(szCmd);
if (lstrcmpi(szCmd, L"SCANDSKW") == 0) { DialogBoxParam(g_hinst, MAKEINTRESOURCE(IDD_SCANDSKW), NULL, ScanDskW_DlgProc, (LPARAM)pszArgs); } }
|