Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2426 lines
86 KiB

  1. #include "shellprv.h"
  2. #include "ids.h"
  3. #include "mtpt.h"
  4. #include "hwcmmn.h"
  5. #pragma hdrstop
  6. #include "apithk.h"
  7. const static DWORD FmtaIds[] =
  8. {
  9. IDOK, IDH_FORMATDLG_START,
  10. IDCANCEL, IDH_CANCEL,
  11. IDC_CAPCOMBO, IDH_FORMATDLG_CAPACITY,
  12. IDC_FSCOMBO, IDH_FORMATDLG_FILESYS,
  13. IDC_ASCOMBO, IDH_FORMATDLG_ALLOCSIZE,
  14. IDC_VLABEL, IDH_FORMATDLG_LABEL,
  15. IDC_GROUPBOX_1, IDH_COMM_GROUPBOX,
  16. IDC_QFCHECK, IDH_FORMATDLG_QUICKFULL,
  17. IDC_ECCHECK, IDH_FORMATDLG_COMPRESS,
  18. IDC_FMTPROGRESS, IDH_FORMATDLG_PROGRESS,
  19. 0,0
  20. };
  21. const static DWORD ChkaIds[] =
  22. {
  23. IDOK, IDH_CHKDSKDLG_START,
  24. IDCANCEL, IDH_CHKDSKDLG_CANCEL,
  25. IDC_GROUPBOX_1, IDH_COMM_GROUPBOX,
  26. IDC_FIXERRORS, IDH_CHKDSKDLG_FIXERRORS,
  27. IDC_RECOVERY, IDH_CHKDSKDLG_SCAN,
  28. IDC_CHKDSKPROGRESS, IDH_CHKDSKDLG_PROGRESS,
  29. IDC_PHASE, -1,
  30. 0,0
  31. };
  32. // The following structure encapsulates our calling into the FMIFS.DLL
  33. typedef struct
  34. {
  35. HINSTANCE hFMIFS_DLL;
  36. PFMIFS_FORMATEX_ROUTINE FormatEx;
  37. PFMIFS_QSUPMEDIA_ROUTINE QuerySupportedMedia;
  38. PFMIFS_ENABLECOMP_ROUTINE EnableVolumeCompression;
  39. PFMIFS_CHKDSKEX_ROUTINE ChkDskEx;
  40. PFMIFS_QUERY_DEVICE_INFO_ROUTINE QueryDeviceInformation;
  41. } FMIFS;
  42. typedef
  43. HRESULT
  44. (*PDISKCOPY_MAKEBOOTDISK_ROUTINE)(
  45. IN HINSTANCE hInstance,
  46. IN UINT iDrive,
  47. IN BOOL* pfCancelled,
  48. IN FMIFS_CALLBACK pCallback
  49. );
  50. // The following structure encapsulates our calling into the DISKCOPY.DLL
  51. typedef struct
  52. {
  53. HINSTANCE hDISKCOPY_DLL;
  54. PDISKCOPY_MAKEBOOTDISK_ROUTINE MakeBootDisk;
  55. } DISKCOPY;
  56. // This structure described the current formatting session
  57. typedef struct
  58. {
  59. LONG cRef; // reference count on this structure
  60. UINT drive; // 0-based index of drive to format
  61. UINT fmtID; // Last format ID
  62. UINT options; // options passed to us via the API
  63. FMIFS fmifs; // above
  64. DISKCOPY diskcopy; // above
  65. HWND hDlg; // handle to the format dialog
  66. BOOL fIsFloppy; // TRUE -> its a floppy
  67. BOOL fIs35HDFloppy; // TRUE -> its a standard 3.5" High Density floppy
  68. BOOL fIsMemoryStick; // TRUE -> its a memory stick (special formatting only)
  69. BOOL fIsNTFSBlocked; // TRUE -> its a NTFS not-supported device
  70. BOOL fEnableComp; // Last "Enable Comp" choice from user
  71. BOOL fCancelled; // User cancelled the last format
  72. BOOL fShouldCancel; // User has clicked cancel; pending abort
  73. BOOL fWasFAT; // Was it FAT originally?
  74. BOOL fFinishedOK; // Did format complete sucessfully?
  75. BOOL fErrorAlready; // Did we put up an error dialog already?
  76. BOOL fDisabled; // Is rgfControlEnabled[] valid?
  77. DWORD dwClusterSize; // Orig NT cluster size, or last choice
  78. WCHAR wszVolName[MAX_PATH]; // Volume Label
  79. WCHAR wszDriveName[4]; // Root path to drive (eg: A:\)
  80. HANDLE hThread; // Handle of format thread
  81. // Array of media types supported by the device
  82. // for NT5, we have an expanded list that includes japanese types.
  83. FMIFS_MEDIA_TYPE rgMedia[IDS_FMT_MEDIA_J22-IDS_FMT_MEDIA_J0];
  84. // Used to cache the enabled/disabled state of the dialog controls
  85. BOOL rgfControlEnabled[DLG_FORMATDISK_NUMCONTROLS];
  86. // should we create a boot disk rather than a traditional format
  87. BOOL fMakeBootDisk;
  88. } FORMATINFO;
  89. //
  90. // An enumeration to make the filesystem combo-box code more readble
  91. //
  92. typedef enum tagFILESYSENUM
  93. {
  94. e_FAT = 0,
  95. e_NTFS,
  96. e_FAT32
  97. } FILESYSENUM;
  98. #define FS_STR_NTFS TEXT("NTFS")
  99. #define FS_STR_FAT32 TEXT("FAT32")
  100. #define FS_STR_FAT TEXT("FAT")
  101. //
  102. // Private WM_USER messages we will use. For some unknown reason, USER sends
  103. // us a WM_USER during initialization, so I start my private messages at
  104. // WM_USER + 0x0100
  105. //
  106. typedef enum tagPRIVMSGS
  107. {
  108. PWM_FORMATDONE = WM_USER + 0x0100,
  109. PWM_CHKDSKDONE
  110. } PRIVMSGS;
  111. //
  112. // Synopsis: Loads FMIFS.DLL and sets up the function entry points for
  113. // the member functions we are interested in.
  114. //
  115. HRESULT LoadFMIFS(FMIFS *pFMIFS)
  116. {
  117. HRESULT hr = S_OK;
  118. //
  119. // Load the FMIFS DLL and query for the entry points we need
  120. //
  121. // SECURITY: what non-relative path do we use that will work on ia64 too?
  122. if (NULL == (pFMIFS->hFMIFS_DLL = LoadLibrary(TEXT("FMIFS.DLL"))))
  123. {
  124. hr = HRESULT_FROM_WIN32(GetLastError());
  125. }
  126. else if (NULL == (pFMIFS->FormatEx = (PFMIFS_FORMATEX_ROUTINE)
  127. GetProcAddress(pFMIFS->hFMIFS_DLL, "FormatEx")))
  128. {
  129. hr = HRESULT_FROM_WIN32(GetLastError());
  130. }
  131. else if (NULL == (pFMIFS->QuerySupportedMedia = (PFMIFS_QSUPMEDIA_ROUTINE)
  132. GetProcAddress(pFMIFS->hFMIFS_DLL, "QuerySupportedMedia")))
  133. {
  134. hr = HRESULT_FROM_WIN32(GetLastError());
  135. }
  136. else if (NULL == (pFMIFS->EnableVolumeCompression = (PFMIFS_ENABLECOMP_ROUTINE)
  137. GetProcAddress(pFMIFS->hFMIFS_DLL, "EnableVolumeCompression")))
  138. {
  139. hr = HRESULT_FROM_WIN32(GetLastError());
  140. }
  141. else if (NULL == (pFMIFS->ChkDskEx = (PFMIFS_CHKDSKEX_ROUTINE)
  142. GetProcAddress(pFMIFS->hFMIFS_DLL, "ChkdskEx")))
  143. {
  144. hr = HRESULT_FROM_WIN32(GetLastError());
  145. }
  146. else if (NULL == (pFMIFS->QueryDeviceInformation = (PFMIFS_QUERY_DEVICE_INFO_ROUTINE)
  147. GetProcAddress(pFMIFS->hFMIFS_DLL, "QueryDeviceInformation")))
  148. {
  149. hr = HRESULT_FROM_WIN32(GetLastError());
  150. }
  151. //
  152. // If anything failed, and we've got the DLL loaded, release the DLL
  153. //
  154. if (hr != S_OK && pFMIFS->hFMIFS_DLL)
  155. {
  156. FreeLibrary(pFMIFS->hFMIFS_DLL);
  157. }
  158. return hr;
  159. }
  160. //
  161. // Synopsis: Loads DISKCOPY.DLL and sets up the function entry points for
  162. // the member functions we are interested in.
  163. //
  164. HRESULT LoadDISKCOPY(DISKCOPY *pDISKCOPY)
  165. {
  166. HRESULT hr = S_OK;
  167. //
  168. // Load the DISKCOPY DLL and query for the entry points we need
  169. //
  170. // SECURITY: what non-relative path do we use that will work on ia64 too?
  171. if (NULL == (pDISKCOPY->hDISKCOPY_DLL = LoadLibrary(TEXT("DISKCOPY.DLL"))))
  172. {
  173. hr = HRESULT_FROM_WIN32(GetLastError());
  174. }
  175. else if (NULL == (pDISKCOPY->MakeBootDisk = (PDISKCOPY_MAKEBOOTDISK_ROUTINE)
  176. GetProcAddress(pDISKCOPY->hDISKCOPY_DLL, MAKEINTRESOURCEA(1)))) //MakeBootDisk is at ordinal 1 in diskcopy.dll
  177. {
  178. hr = HRESULT_FROM_WIN32(GetLastError());
  179. }
  180. //
  181. // If anything failed, and we've got the DLL loaded, release the DLL
  182. //
  183. if (hr != S_OK && pDISKCOPY->hDISKCOPY_DLL)
  184. {
  185. FreeLibrary(pDISKCOPY->hDISKCOPY_DLL);
  186. }
  187. return hr;
  188. }
  189. void AddRefFormatInfo(FORMATINFO *pFormatInfo)
  190. {
  191. InterlockedIncrement(&pFormatInfo->cRef);
  192. }
  193. void ReleaseFormatInfo(FORMATINFO *pFormatInfo)
  194. {
  195. ASSERT( 0 != pFormatInfo->cRef );
  196. if (InterlockedDecrement(&pFormatInfo->cRef) == 0)
  197. {
  198. if (pFormatInfo->fmifs.hFMIFS_DLL)
  199. {
  200. FreeLibrary(pFormatInfo->fmifs.hFMIFS_DLL);
  201. }
  202. if (pFormatInfo->diskcopy.hDISKCOPY_DLL)
  203. {
  204. FreeLibrary(pFormatInfo->diskcopy.hDISKCOPY_DLL);
  205. }
  206. if (pFormatInfo->hThread)
  207. {
  208. CloseHandle(pFormatInfo->hThread);
  209. }
  210. LocalFree(pFormatInfo);
  211. }
  212. }
  213. //
  214. // Thread-Local Storage index for our FORMATINFO structure pointer
  215. //
  216. static DWORD g_iTLSFormatInfo = 0;
  217. static LONG g_cTLSFormatInfo = 0; // Usage count
  218. // Synopsis: Allocates a thread-local index slot for this thread's
  219. // FORMATINFO pointer, if the index doesn't already exist.
  220. // In any event, stores the FORMATINFO pointer in the slot
  221. // and increments the index's usage count.
  222. //
  223. // Arguments: [pFormatInfo] -- The pointer to store
  224. //
  225. // Returns: HRESULT
  226. //
  227. HRESULT StuffFormatInfoPtr(FORMATINFO *pFormatInfo)
  228. {
  229. HRESULT hr = S_OK;
  230. // Allocate an index slot for our thread-local FORMATINFO pointer, if one
  231. // doesn't already exist, then stuff our FORMATINFO ptr at that index.
  232. ENTERCRITICAL;
  233. if (0 == g_iTLSFormatInfo)
  234. {
  235. if (0xFFFFFFFF == (g_iTLSFormatInfo = TlsAlloc()))
  236. {
  237. hr = HRESULT_FROM_WIN32(GetLastError());
  238. }
  239. g_cTLSFormatInfo = 0;
  240. }
  241. if (S_OK == hr)
  242. {
  243. if (TlsSetValue(g_iTLSFormatInfo, (void *) pFormatInfo))
  244. {
  245. g_cTLSFormatInfo++;
  246. }
  247. else
  248. {
  249. hr = HRESULT_FROM_WIN32(GetLastError());
  250. }
  251. }
  252. LEAVECRITICAL;
  253. return hr;
  254. }
  255. // Synopsis: Decrements the usage count on our thread-local storage
  256. // index, and if it goes to zero the index is free'd
  257. //
  258. // Arguments: [none]
  259. //
  260. // Returns: none
  261. //
  262. void UnstuffFormatInfoPtr()
  263. {
  264. ENTERCRITICAL;
  265. if (0 == --g_cTLSFormatInfo)
  266. {
  267. TlsFree(g_iTLSFormatInfo);
  268. g_iTLSFormatInfo = 0;
  269. }
  270. LEAVECRITICAL;
  271. }
  272. // Synopsis: Retrieves this threads FORMATINFO ptr by grabbing the
  273. // thread-local value previously stuff'd
  274. //
  275. // Arguments: [none]
  276. //
  277. // Returns: The pointer, of course
  278. //
  279. FORMATINFO *GetFormatInfoPtr()
  280. {
  281. return (FORMATINFO*)TlsGetValue(g_iTLSFormatInfo);
  282. }
  283. // Synopsis: Ghosts all controls except "Cancel", saving their
  284. // previous state in the FORMATINFO structure
  285. //
  286. // Arguments: [pFormatInfo] -- Describes a format dialog session
  287. //
  288. // Notes: Also changes "Close" button text to read "Cancel"
  289. //
  290. void DisableControls(FORMATINFO *pFormatInfo)
  291. {
  292. WCHAR wszCancel[64];
  293. // Do this only if we haven't disabled the controls yet, otherwise
  294. // we double-disable and our rgfControlEnabled[] array gets corrupted.
  295. if (!pFormatInfo->fDisabled)
  296. {
  297. int i;
  298. pFormatInfo->fDisabled = TRUE;
  299. for (i = 0; i < DLG_FORMATDISK_NUMCONTROLS; i++)
  300. {
  301. HWND hControl = GetDlgItem(pFormatInfo->hDlg, i + DLG_FORMATDISK_FIRSTCONTROL);
  302. pFormatInfo->rgfControlEnabled[i] = !EnableWindow(hControl, FALSE);
  303. }
  304. }
  305. EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDOK), FALSE);
  306. LoadString(HINST_THISDLL, IDS_FMT_CANCEL, wszCancel, ARRAYSIZE(wszCancel));
  307. SetWindowText(GetDlgItem(pFormatInfo->hDlg, IDCANCEL), wszCancel);
  308. }
  309. // Synopsis: Restores controls to the enabled/disabled state they were
  310. // before a previous call to DisableControls().
  311. //
  312. // Arguments: [pFormatInfo] -- Decribes a format dialog session
  313. // [fReady] - If TRUE, then enable everything
  314. // If FALSE, then enable combo boxes but leave
  315. // buttons in limbo because there is still a format
  316. // pending
  317. //
  318. // Notes: Also changes "Cancel" button to say "Close"
  319. // Also sets focus to Cancel button instead of Start button
  320. //
  321. //--------------------------------------------------------------------------
  322. void EnableControls(FORMATINFO *pFormatInfo, BOOL fReady)
  323. {
  324. WCHAR wszClose[64];
  325. int i;
  326. HWND hwnd;
  327. // Do this only if we have valid info in rgfControlEnabled[].
  328. // This catches the case where we give up on a format because it is
  329. // unstuck, and then finally it unsticks itself and tells us,
  330. // so we go and re-enable a second time.
  331. if (pFormatInfo->fDisabled)
  332. {
  333. pFormatInfo->fDisabled = FALSE;
  334. for (i = 0; i < DLG_FORMATDISK_NUMCONTROLS; i++)
  335. {
  336. HWND hControl = GetDlgItem(pFormatInfo->hDlg, i + DLG_FORMATDISK_FIRSTCONTROL);
  337. EnableWindow(hControl, pFormatInfo->rgfControlEnabled[i]);
  338. }
  339. }
  340. hwnd = GetDlgItem(pFormatInfo->hDlg, IDOK);
  341. EnableWindow(hwnd, fReady);
  342. SendMessage(hwnd, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE,0));
  343. LoadString(HINST_THISDLL, IDS_FMT_CLOSE, wszClose, ARRAYSIZE(wszClose));
  344. hwnd = GetDlgItem(pFormatInfo->hDlg, IDCANCEL);
  345. SetWindowText(hwnd, wszClose);
  346. SendMessage(hwnd, BM_SETSTYLE, BS_DEFPUSHBUTTON, MAKELPARAM(TRUE,0));
  347. SendMessage(pFormatInfo->hDlg, DM_SETDEFID, IDCANCEL, 0);
  348. // Shove focus only if it's on the OK button. Otherwise we end up
  349. // yanking focus away from a user who is busy dorking with the dialog,
  350. // or -- worse -- dorking with a completely unrelated dialog!
  351. if (GetFocus() == GetDlgItem(pFormatInfo->hDlg, IDOK))
  352. SetFocus(hwnd);
  353. }
  354. // Sets the dialog's title to "Format Floppy (A:)" or
  355. // "Formatting Floppy (A:)"
  356. void SetDriveWindowTitle(HWND hdlg, LPCWSTR pszDrive, UINT ids)
  357. {
  358. SHFILEINFO sfi;
  359. WCHAR wszWinTitle[MAX_PATH]; // Format dialog window title
  360. LoadString(HINST_THISDLL, ids, wszWinTitle, ARRAYSIZE(wszWinTitle));
  361. if (SHGetFileInfo(pszDrive, FILE_ATTRIBUTE_DIRECTORY, &sfi, sizeof(sfi),
  362. SHGFI_USEFILEATTRIBUTES | SHGFI_DISPLAYNAME))
  363. {
  364. StringCchCat(wszWinTitle, ARRAYSIZE(wszWinTitle), sfi.szDisplayName); // ok to truncate
  365. }
  366. SetWindowText(hdlg, wszWinTitle);
  367. }
  368. //
  369. // Synopsis: Called when a user picks a filesystem in the dialog, this
  370. // sets the states of the other relevant controls, such as
  371. // Enable Compression, Allocation Size, etc.
  372. //
  373. // Arguments: [fsenum] -- One of e_FAT, e_NTFS, or e_FAT32
  374. // [pFormatInfo] -- Current format dialog session
  375. //
  376. void FileSysChange(FILESYSENUM fsenum, FORMATINFO *pFormatInfo)
  377. {
  378. WCHAR wszTmp[MAX_PATH];
  379. switch (fsenum)
  380. {
  381. case e_FAT:
  382. case e_FAT32:
  383. {
  384. // un-check & disable the "Enable Compression" checkbox
  385. CheckDlgButton(pFormatInfo->hDlg, IDC_ECCHECK, FALSE);
  386. EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_ECCHECK), FALSE);
  387. SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_RESETCONTENT, 0, 0);
  388. LoadString(HINST_THISDLL, IDS_FMT_ALLOC0, wszTmp, ARRAYSIZE(wszTmp));
  389. SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_ADDSTRING, 0, (LPARAM)wszTmp);
  390. SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_SETCURSEL, 0, 0);
  391. }
  392. break;
  393. case e_NTFS:
  394. {
  395. int i;
  396. // un-check & disable the "Enable Compression" checkbox
  397. EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_ECCHECK), TRUE);
  398. CheckDlgButton(pFormatInfo->hDlg, IDC_ECCHECK, pFormatInfo->fEnableComp);
  399. // Set up the NTFS Allocation choices, and select the current choice
  400. SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_RESETCONTENT, 0, 0);
  401. for (i = IDS_FMT_ALLOC0; i <= IDS_FMT_ALLOC4; i++)
  402. {
  403. LoadString(HINST_THISDLL, i, wszTmp, ARRAYSIZE(wszTmp));
  404. SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_ADDSTRING, 0, (LPARAM)wszTmp);
  405. }
  406. switch (pFormatInfo->dwClusterSize)
  407. {
  408. case 512:
  409. SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_SETCURSEL, 1, 0);
  410. break;
  411. case 1024:
  412. SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_SETCURSEL, 2, 0);
  413. break;
  414. case 2048:
  415. SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_SETCURSEL, 3, 0);
  416. break;
  417. case 4096:
  418. SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_SETCURSEL, 4, 0);
  419. break;
  420. default:
  421. SendDlgItemMessage(pFormatInfo->hDlg, IDC_ASCOMBO, CB_SETCURSEL, 0, 0);
  422. break;
  423. }
  424. }
  425. break;
  426. }
  427. }
  428. //
  429. // Is this drive a GPT drive?
  430. // GPT drive: Guid-Partition Table - a replacement for the Master Boot Record, used on some IA64 machines, can only use NTFS
  431. BOOL IsGPTDrive(int iDrive)
  432. {
  433. BOOL fRetVal = FALSE;
  434. #ifdef _WIN64
  435. HANDLE hDrive;
  436. TCHAR szDrive[] = TEXT("\\\\.\\A:");
  437. ASSERT(iDrive < 26);
  438. szDrive[4] += (TCHAR)iDrive;
  439. hDrive = CreateFile(szDrive, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  440. if (INVALID_HANDLE_VALUE != hDrive)
  441. {
  442. PARTITION_INFORMATION_EX partitionEx;
  443. DWORD cbReturned;
  444. if (DeviceIoControl(hDrive, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, (void*)&partitionEx, sizeof(PARTITION_INFORMATION_EX), &cbReturned, NULL))
  445. {
  446. if (partitionEx.PartitionStyle == PARTITION_STYLE_GPT)
  447. {
  448. fRetVal = TRUE;
  449. }
  450. }
  451. CloseHandle(hDrive);
  452. }
  453. #endif
  454. return fRetVal;
  455. }
  456. BOOL IsDVDRAMMedia(int iDrive)
  457. {
  458. BOOL fRetVal = FALSE;
  459. CMountPoint *pmtpt = CMountPoint::GetMountPoint(iDrive);
  460. if (pmtpt)
  461. {
  462. DWORD dwMediaCap, dwDriveCap;
  463. if (SUCCEEDED(pmtpt->GetCDInfo(&dwDriveCap, &dwMediaCap)))
  464. {
  465. fRetVal = (dwMediaCap & HWDMC_DVDRAM);
  466. }
  467. pmtpt->Release();
  468. }
  469. return fRetVal;
  470. }
  471. #define GIG_INBYTES (1024 * 1024 * 1024)
  472. //
  473. // FAT32 has some limit which prevents the number of clusters from being
  474. // less than 65526. And minimum cluster size is 512 bytes. So minimum FAT32
  475. // volume size is 65526*512.
  476. #define FAT32_MIN ((ULONGLONG)65526*512)
  477. #define FMTAVAIL_MASK_MIN 0x1
  478. #define FMTAVAIL_MASK_MAX 0x2
  479. #define FMTAVAIL_MASK_REQUIRE 0x3
  480. #define FMTAVAIL_MASK_FORBID 0x4
  481. #define FMTAVAIL_TYPE_FLOPPY 0x1
  482. #define FMTAVAIL_TYPE_DVDRAM 0x2
  483. #define FMTAVAIL_TYPE_GPT 0x4
  484. #define FMTAVAIL_TYPE_MEMSTICK 0x8
  485. #define FMTAVAIL_TYPE_NTFS_BLOCKED 0x10
  486. typedef struct _FMTAVAIL
  487. {
  488. DWORD dwfs;
  489. DWORD dwMask;
  490. DWORD dwForbiddenTypes;
  491. ULONGLONG qMinSize;
  492. ULONGLONG qMaxSize;
  493. } FMTAVAIL;
  494. FMTAVAIL rgFmtAvail[] = {
  495. {e_FAT, FMTAVAIL_MASK_MAX | FMTAVAIL_MASK_FORBID, FMTAVAIL_TYPE_DVDRAM | FMTAVAIL_TYPE_GPT, 0, ((ULONGLONG)2 * GIG_INBYTES) },
  496. {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) },
  497. {e_NTFS, FMTAVAIL_MASK_FORBID, FMTAVAIL_TYPE_DVDRAM | FMTAVAIL_TYPE_FLOPPY | FMTAVAIL_TYPE_MEMSTICK | FMTAVAIL_TYPE_NTFS_BLOCKED, 0, 0 }
  498. };
  499. // is a particular disk format available for a drive with given parameters and capacity?
  500. BOOL FormatAvailable (DWORD dwfs, FORMATINFO* pFormatInfo, ULONGLONG* pqwCapacity)
  501. {
  502. BOOL fAvailable = TRUE;
  503. DWORD dwType = 0;
  504. if (pFormatInfo->fIsFloppy)
  505. {
  506. dwType |= FMTAVAIL_TYPE_FLOPPY;
  507. }
  508. if (IsDVDRAMMedia(pFormatInfo->drive))
  509. {
  510. dwType |= FMTAVAIL_TYPE_DVDRAM;
  511. }
  512. if (IsGPTDrive(pFormatInfo->drive))
  513. {
  514. dwType |= FMTAVAIL_TYPE_GPT;
  515. }
  516. if (pFormatInfo->fIsMemoryStick)
  517. {
  518. dwType |= FMTAVAIL_TYPE_MEMSTICK;
  519. }
  520. if (pFormatInfo->fIsNTFSBlocked)
  521. {
  522. dwType |= FMTAVAIL_TYPE_NTFS_BLOCKED;
  523. }
  524. for (int i = 0; i < ARRAYSIZE(rgFmtAvail); i++)
  525. {
  526. // check only entries that match the format we're looking for
  527. if (rgFmtAvail[i].dwfs == dwfs)
  528. {
  529. // if a failure conditions is true, then this format is unavailable
  530. if ((rgFmtAvail[i].dwMask & FMTAVAIL_MASK_FORBID) && (rgFmtAvail[i].dwForbiddenTypes & dwType))
  531. {
  532. fAvailable = FALSE;
  533. break;
  534. }
  535. if ((rgFmtAvail[i].dwMask & FMTAVAIL_MASK_MIN) && (*pqwCapacity < rgFmtAvail[i].qMinSize))
  536. {
  537. fAvailable = FALSE;
  538. break;
  539. }
  540. if ((rgFmtAvail[i].dwMask & FMTAVAIL_MASK_MAX) && (*pqwCapacity > rgFmtAvail[i].qMaxSize))
  541. {
  542. fAvailable = FALSE;
  543. break;
  544. }
  545. }
  546. }
  547. return fAvailable;
  548. }
  549. HRESULT GetPartitionSizeInBytes(int iDrive, ULONGLONG* pqwPartitionSize)
  550. {
  551. HRESULT hr = E_FAIL;
  552. HANDLE hFile;
  553. TCHAR szDrive[] = TEXT("\\\\.\\A:");
  554. *pqwPartitionSize = 0;
  555. ASSERT(iDrive < 26);
  556. szDrive[4] += (TCHAR)iDrive;
  557. hFile = CreateFile(szDrive, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  558. if (INVALID_HANDLE_VALUE != hFile)
  559. {
  560. GET_LENGTH_INFORMATION LengthInfo;
  561. DWORD cbReturned;
  562. if (DeviceIoControl(hFile, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, (void*)&LengthInfo, sizeof(LengthInfo), &cbReturned, NULL) &&
  563. LengthInfo.Length.QuadPart)
  564. {
  565. *pqwPartitionSize = LengthInfo.Length.QuadPart;
  566. hr = S_OK;
  567. }
  568. CloseHandle(hFile);
  569. }
  570. return hr;
  571. }
  572. // this helper function adds a string to a combo box with the associated dword (dwfs) as its itemdata
  573. void _AddFSString(HWND hwndCB, WCHAR* pwsz, DWORD dwfs)
  574. {
  575. int iIndex = ComboBox_AddString(hwndCB, pwsz);
  576. if (iIndex != CB_ERR)
  577. {
  578. ComboBox_SetItemData(hwndCB, iIndex, dwfs);
  579. }
  580. }
  581. // We only support formatting these types of devices
  582. const FMIFS_MEDIA_TYPE rgFmtSupported[] = { FmMediaRemovable, FmMediaFixed,
  583. FmMediaF3_1Pt44_512, FmMediaF3_120M_512, FmMediaF3_200Mb_512};
  584. //
  585. // Synopsis: Initializes the format dialog to a default state. Examines
  586. // the disk/partition to obtain default values.
  587. //
  588. // Arguments: [hDlg] -- Handle to the format dialog
  589. // [pFormatInfo] -- Describes current format session
  590. //
  591. // Returns: HRESULT
  592. //
  593. HRESULT InitializeFormatDlg(FORMATINFO *pFormatInfo)
  594. {
  595. HRESULT hr = S_OK;
  596. ULONG cMedia;
  597. HWND hCapacityCombo;
  598. HWND hFilesystemCombo;
  599. HWND hDlg = pFormatInfo->hDlg;
  600. WCHAR wszBuffer[256];
  601. ULONGLONG qwCapacity = 0;
  602. // Set up some typical default values
  603. pFormatInfo->fEnableComp = FALSE;
  604. pFormatInfo->dwClusterSize = 0;
  605. pFormatInfo->fIsFloppy = TRUE;
  606. pFormatInfo->fIsMemoryStick = FALSE;
  607. pFormatInfo->fIsNTFSBlocked = FALSE;
  608. pFormatInfo->fIs35HDFloppy = TRUE;
  609. pFormatInfo->fWasFAT = TRUE;
  610. pFormatInfo->fFinishedOK = FALSE;
  611. pFormatInfo->fErrorAlready = FALSE;
  612. pFormatInfo->wszVolName[0] = L'\0';
  613. // Initialize the Quick Format checkbox based on option passed to the SHFormatDrive() API
  614. Button_SetCheck(GetDlgItem(hDlg, IDC_QFCHECK), pFormatInfo->options & SHFMT_OPT_FULL);
  615. // Set the dialog title to indicate which drive we are dealing with
  616. PathBuildRootW(pFormatInfo->wszDriveName, pFormatInfo->drive);
  617. SetDriveWindowTitle(pFormatInfo->hDlg, pFormatInfo->wszDriveName, IDS_FMT_FORMAT);
  618. // Query the supported media types for the drive in question
  619. if (!pFormatInfo->fmifs.QuerySupportedMedia(pFormatInfo->wszDriveName,
  620. pFormatInfo->rgMedia,
  621. ARRAYSIZE(pFormatInfo->rgMedia),
  622. &cMedia))
  623. {
  624. hr = HRESULT_FROM_WIN32(GetLastError());
  625. }
  626. // For each of the formats that the drive can handle, add a selection
  627. // to the capcity combobox.
  628. if (S_OK == hr)
  629. {
  630. UINT olderror;
  631. ULONG i;
  632. ULONG j;
  633. hCapacityCombo = GetDlgItem(hDlg, IDC_CAPCOMBO);
  634. hFilesystemCombo = GetDlgItem(hDlg, IDC_FSCOMBO);
  635. ASSERT(hCapacityCombo && hFilesystemCombo);
  636. FMIFS_DEVICE_INFORMATION fmifsdeviceinformation;
  637. BOOL fOk = pFormatInfo->fmifs.QueryDeviceInformation(
  638. pFormatInfo->wszDriveName,
  639. &fmifsdeviceinformation,
  640. sizeof(fmifsdeviceinformation));
  641. if (fOk)
  642. {
  643. if (fmifsdeviceinformation.Flags & FMIFS_SONY_MS)
  644. {
  645. pFormatInfo->fIsMemoryStick = TRUE;
  646. }
  647. if (fmifsdeviceinformation.Flags & FMIFS_NTFS_NOT_SUPPORTED)
  648. {
  649. pFormatInfo->fIsNTFSBlocked = TRUE;
  650. }
  651. }
  652. // Allow only certain media types
  653. j = 0;
  654. for (i = 0; i < cMedia; i++)
  655. {
  656. for (int k = 0; k < ARRAYSIZE(rgFmtSupported); k++)
  657. {
  658. if (pFormatInfo->rgMedia[i] == rgFmtSupported[k])
  659. {
  660. pFormatInfo->rgMedia[j] = pFormatInfo->rgMedia[i];
  661. j++;
  662. break;
  663. }
  664. }
  665. }
  666. cMedia = j;
  667. if (0 == cMedia)
  668. {
  669. hr = ERROR_UNRECOGNIZED_MEDIA;
  670. }
  671. else
  672. {
  673. for (i = 0; i < cMedia; i++)
  674. {
  675. // If we find any non-floppy format, clear the fIsFloppy flag
  676. if (FmMediaFixed == pFormatInfo->rgMedia[i] || FmMediaRemovable == pFormatInfo->rgMedia[i])
  677. {
  678. pFormatInfo->fIsFloppy = FALSE;
  679. }
  680. // if we find any non-3.5" HD floppy format, clear the fIs35HDFloppy flag
  681. if (FmMediaF3_1Pt44_512 != pFormatInfo->rgMedia[i])
  682. {
  683. pFormatInfo->fIs35HDFloppy = FALSE;
  684. }
  685. // For fixed media we query the size, for floppys we present
  686. // a set of options supported by the drive
  687. if (FmMediaFixed == pFormatInfo->rgMedia[i] || (FmMediaRemovable == pFormatInfo->rgMedia[i]))
  688. {
  689. DWORD dwSectorsPerCluster,
  690. dwBytesPerSector,
  691. dwFreeClusters,
  692. dwClusters;
  693. if (SUCCEEDED(GetPartitionSizeInBytes(pFormatInfo->drive, &qwCapacity)))
  694. {
  695. // Add a capacity desciption to the combobox
  696. ShortSizeFormat64(qwCapacity, wszBuffer, ARRAYSIZE(wszBuffer));
  697. }
  698. else
  699. {
  700. // Couldn't get the free space... prob. not fatal
  701. LoadString(HINST_THISDLL, IDS_FMT_CAPUNKNOWN, wszBuffer, ARRAYSIZE(wszBuffer));
  702. }
  703. ComboBox_AddString(hCapacityCombo, wszBuffer);
  704. if (GetDiskFreeSpace(pFormatInfo->wszDriveName,
  705. &dwSectorsPerCluster,
  706. &dwBytesPerSector,
  707. &dwFreeClusters,
  708. &dwClusters))
  709. {
  710. pFormatInfo->dwClusterSize = dwBytesPerSector * dwSectorsPerCluster;
  711. }
  712. }
  713. else
  714. {
  715. // removable media:
  716. //
  717. // add a capacity desciption to the combo baseed on the sequential list of
  718. // media format descriptors
  719. LoadString(HINST_THISDLL, IDS_FMT_MEDIA0 + pFormatInfo->rgMedia[i], wszBuffer, ARRAYSIZE(wszBuffer));
  720. ComboBox_AddString(hCapacityCombo, wszBuffer);
  721. }
  722. }
  723. // set capacity to default
  724. ComboBox_SetCurSel(hCapacityCombo, 0);
  725. // Add the appropriate filesystem selections to the combobox
  726. // We now prioritize NTFS
  727. if (FormatAvailable(e_NTFS, pFormatInfo, &qwCapacity))
  728. {
  729. _AddFSString(hFilesystemCombo, FS_STR_NTFS, e_NTFS);
  730. }
  731. if (FormatAvailable(e_FAT32, pFormatInfo, &qwCapacity))
  732. {
  733. _AddFSString(hFilesystemCombo, FS_STR_FAT32, e_FAT32);
  734. }
  735. if (FormatAvailable(e_FAT, pFormatInfo, &qwCapacity))
  736. {
  737. _AddFSString(hFilesystemCombo, FS_STR_FAT, e_FAT);
  738. }
  739. // By default, pick the 0-th entry in the _nonsorted_ combobox.
  740. // NOTE: this can be overwritten below
  741. ComboBox_SetCurSel(hFilesystemCombo, 0);
  742. // If we can determine something other than FAT is being used,
  743. // select it as the default in the combobox
  744. olderror = SetErrorMode(SEM_FAILCRITICALERRORS);
  745. if (GetVolumeInformation(pFormatInfo->wszDriveName,
  746. pFormatInfo->wszVolName,
  747. ARRAYSIZE(pFormatInfo->wszVolName),
  748. NULL,
  749. NULL,
  750. NULL,
  751. wszBuffer,
  752. ARRAYSIZE(wszBuffer)))
  753. {
  754. // If we got a current volume label, stuff it in the edit control
  755. if (pFormatInfo->wszVolName[0] != L'\0')
  756. {
  757. SetWindowText(GetDlgItem(pFormatInfo->hDlg, IDC_VLABEL), pFormatInfo->wszVolName);
  758. }
  759. // for non-floppies we default to keeping the FS the same as the current one
  760. if (!pFormatInfo->fIsFloppy)
  761. {
  762. if (0 == lstrcmpi(FS_STR_NTFS, wszBuffer))
  763. {
  764. ComboBox_SelectString(hFilesystemCombo, -1, FS_STR_NTFS);
  765. pFormatInfo->fWasFAT = FALSE;
  766. }
  767. else if (0 == lstrcmpi(FS_STR_FAT32, wszBuffer))
  768. {
  769. ComboBox_SelectString(hFilesystemCombo, -1, FS_STR_FAT32);
  770. pFormatInfo->fWasFAT = TRUE;
  771. pFormatInfo->dwClusterSize = 0;
  772. }
  773. else
  774. {
  775. ComboBox_SelectString(hFilesystemCombo, -1, FS_STR_FAT);
  776. pFormatInfo->fWasFAT = TRUE;
  777. pFormatInfo->dwClusterSize = 0;
  778. }
  779. }
  780. // FEATURE - What about specialized file-systems? Don't care for now.
  781. }
  782. #ifndef _WIN64
  783. // if not WIN64, enable boot-disk creation if we are a 3.5" HD floppy
  784. EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_BTCHECK), pFormatInfo->fIs35HDFloppy);
  785. #else
  786. // if WIN64, hide this option, since we can't use these boot floppies on WIN64
  787. ShowWindow(GetDlgItem(pFormatInfo->hDlg, IDC_BTCHECK), FALSE);
  788. #endif
  789. // restore the old errormode
  790. SetErrorMode(olderror);
  791. // set the state of the chkboxes properly based on the FS chosen
  792. FileSysChange((FILESYSENUM)ComboBox_GetItemData(hFilesystemCombo, ComboBox_GetCurSel(hFilesystemCombo)), pFormatInfo);
  793. }
  794. }
  795. // If the above failed due to disk not in drive, notify the user
  796. if (FAILED(hr))
  797. {
  798. switch (HRESULT_CODE(hr))
  799. {
  800. case ERROR_UNRECOGNIZED_MEDIA:
  801. ShellMessageBox(HINST_THISDLL,
  802. hDlg,
  803. MAKEINTRESOURCE(IDS_UNFORMATTABLE_DISK),
  804. NULL,
  805. MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK,
  806. NULL);
  807. break;
  808. case ERROR_NOT_READY:
  809. ShellMessageBox(HINST_THISDLL,
  810. hDlg,
  811. MAKEINTRESOURCE(IDS_DRIVENOTREADY),
  812. NULL,
  813. MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK,
  814. pFormatInfo->wszDriveName[0]);
  815. break;
  816. case ERROR_ACCESS_DENIED:
  817. ShellMessageBox(HINST_THISDLL,
  818. hDlg,
  819. MAKEINTRESOURCE(IDS_ACCESSDENIED),
  820. NULL,
  821. MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK,
  822. pFormatInfo->wszDriveName[0]);
  823. break;
  824. case ERROR_WRITE_PROTECT:
  825. ShellMessageBox(HINST_THISDLL,
  826. hDlg,
  827. MAKEINTRESOURCE(IDS_WRITEPROTECTED),
  828. NULL,
  829. MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK,
  830. pFormatInfo->wszDriveName[0]);
  831. break;
  832. }
  833. }
  834. return hr;
  835. }
  836. // Synopsis: Called from within the FMIFS DLL's Format function, this
  837. // updates the format dialog's status bar and responds to
  838. // format completion/error notifications.
  839. //
  840. // Arguments: [PacketType] -- Type of packet (ie: % complete, error, etc)
  841. // [PacketLength] -- Size, in bytes, of the packet
  842. // [pPacketData] -- Pointer to the packet
  843. //
  844. // Returns: BOOLEAN continuation value
  845. //
  846. BOOLEAN FormatCallback(FMIFS_PACKET_TYPE PacketType, ULONG PacketLength, void *pPacketData)
  847. {
  848. UINT iMessageID = IDS_FORMATFAILED;
  849. BOOL fFailed = FALSE;
  850. FORMATINFO* pFormatInfo = GetFormatInfoPtr();
  851. ASSERT(g_iTLSFormatInfo);
  852. // Grab the FORMATINFO structure for this thread
  853. if (pFormatInfo)
  854. {
  855. if (!pFormatInfo->fShouldCancel)
  856. {
  857. switch(PacketType)
  858. {
  859. case FmIfsIncompatibleFileSystem:
  860. fFailed = TRUE;
  861. iMessageID = IDS_INCOMPATIBLEFS;
  862. break;
  863. case FmIfsIncompatibleMedia:
  864. fFailed = TRUE;
  865. iMessageID = IDS_INCOMPATIBLEMEDIA;
  866. break;
  867. case FmIfsAccessDenied:
  868. fFailed = TRUE;
  869. iMessageID = IDS_ACCESSDENIED;
  870. break;
  871. case FmIfsMediaWriteProtected:
  872. fFailed = TRUE;
  873. iMessageID = IDS_WRITEPROTECTED;
  874. break;
  875. case FmIfsCantLock:
  876. fFailed = TRUE;
  877. iMessageID = IDS_CANTLOCK;
  878. break;
  879. case FmIfsCantQuickFormat:
  880. fFailed = TRUE;
  881. iMessageID = IDS_CANTQUICKFORMAT;
  882. break;
  883. case FmIfsIoError:
  884. fFailed = TRUE;
  885. // display a different message if we're making a boot disk
  886. iMessageID = pFormatInfo->fMakeBootDisk ? IDS_NEEDFORMAT : IDS_IOERROR;
  887. // FUTURE Consider showing head/track etc where error was
  888. break;
  889. case FmIfsBadLabel:
  890. fFailed = TRUE;
  891. iMessageID = IDS_BADLABEL;
  892. break;
  893. case FmIfsPercentCompleted:
  894. {
  895. FMIFS_PERCENT_COMPLETE_INFORMATION * pPercent =
  896. (FMIFS_PERCENT_COMPLETE_INFORMATION *) pPacketData;
  897. SendDlgItemMessage(pFormatInfo->hDlg, IDC_FMTPROGRESS,
  898. PBM_SETPOS,
  899. pPercent->PercentCompleted, 0);
  900. }
  901. break;
  902. case FmIfsFinished:
  903. {
  904. // Format is done; check for failure or success
  905. FMIFS_FINISHED_INFORMATION* pFinishedInfo = (FMIFS_FINISHED_INFORMATION*)pPacketData;
  906. pFormatInfo->fFinishedOK = pFinishedInfo->Success;
  907. if (pFinishedInfo->Success)
  908. {
  909. // fmifs will "succeed" even if we already failed, so we need to double-check
  910. // that we haven't already put up error UI
  911. if (!pFormatInfo->fErrorAlready)
  912. {
  913. // If "Enable Compression" is checked, try to enable filesystem compression
  914. if (IsDlgButtonChecked(pFormatInfo->hDlg, IDC_ECCHECK))
  915. {
  916. if (pFormatInfo->fmifs.EnableVolumeCompression(pFormatInfo->wszDriveName,
  917. COMPRESSION_FORMAT_DEFAULT) == FALSE)
  918. {
  919. ShellMessageBox(HINST_THISDLL,
  920. pFormatInfo->hDlg,
  921. MAKEINTRESOURCE(IDS_CANTENABLECOMP),
  922. NULL,
  923. MB_SETFOREGROUND | MB_ICONINFORMATION | MB_OK);
  924. }
  925. }
  926. // Even though its a quick format, the progress meter should
  927. // show 100% when the "Format Complete" requester is up
  928. SendDlgItemMessage(pFormatInfo->hDlg, IDC_FMTPROGRESS,
  929. PBM_SETPOS,
  930. 100, // set %100 Complete
  931. 0);
  932. // FUTURE Consider showing format stats, ie: ser no, bytes, etc
  933. ShellMessageBox(HINST_THISDLL,
  934. pFormatInfo->hDlg,
  935. MAKEINTRESOURCE(IDS_FORMATCOMPLETE),
  936. NULL,
  937. MB_SETFOREGROUND | MB_ICONINFORMATION | MB_OK);
  938. }
  939. // Restore the dialog title, reset progress and flags
  940. SendDlgItemMessage(pFormatInfo->hDlg,
  941. IDC_FMTPROGRESS,
  942. PBM_SETPOS,
  943. 0, // Reset Percent Complete
  944. 0);
  945. // Set the focus onto the Close button
  946. pFormatInfo->fCancelled = FALSE;
  947. }
  948. else
  949. {
  950. fFailed = TRUE;
  951. }
  952. }
  953. break;
  954. }
  955. if (fFailed && !pFormatInfo->fErrorAlready)
  956. {
  957. // If we received any kind of failure information, put up a final
  958. // "Format Failed" message. UNLESS we've already put up some nice message
  959. ShellMessageBox(HINST_THISDLL,
  960. pFormatInfo->hDlg,
  961. MAKEINTRESOURCE(iMessageID),
  962. NULL,
  963. MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK);
  964. pFormatInfo->fErrorAlready = TRUE;
  965. }
  966. }
  967. else
  968. {
  969. // user hit cancel
  970. pFormatInfo->fCancelled = TRUE;
  971. fFailed = TRUE;
  972. }
  973. }
  974. else
  975. {
  976. // no pFormatInfo? we're screwed
  977. fFailed = TRUE;
  978. }
  979. return (BOOLEAN) (fFailed == FALSE);
  980. }
  981. //
  982. // Synopsis: Spun off as its own thread, this ghosts all controls in the
  983. // dialog except "Cancel", then does the actual format
  984. //
  985. // Arguments: [pIn] -- FORMATINFO structure pointer as a void *
  986. //
  987. // Returns: HRESULT thread exit code
  988. //
  989. DWORD WINAPI BeginFormat(void * pIn)
  990. {
  991. FORMATINFO *pFormatInfo = (FORMATINFO*)pIn;
  992. HRESULT hr = S_OK;
  993. // Save the FORAMTINFO ptr for this thread, to be used in the format
  994. // callback function
  995. hr = StuffFormatInfoPtr(pFormatInfo);
  996. if (hr == S_OK)
  997. {
  998. HWND hwndFileSysCB = GetDlgItem(pFormatInfo->hDlg, IDC_FSCOMBO);
  999. int iCurSel;
  1000. // Set the window title to indicate format in proress...
  1001. SetDriveWindowTitle(pFormatInfo->hDlg, pFormatInfo->wszDriveName, IDS_FMT_FORMATTING);
  1002. // Determine the user's choice of filesystem
  1003. iCurSel = ComboBox_GetCurSel(hwndFileSysCB);
  1004. if (iCurSel != CB_ERR)
  1005. {
  1006. LPCWSTR pwszFileSystemName;
  1007. FMIFS_MEDIA_TYPE MediaType;
  1008. LPITEMIDLIST pidlFormat;
  1009. BOOLEAN fQuickFormat;
  1010. FILESYSENUM fseType = (FILESYSENUM)ComboBox_GetItemData(hwndFileSysCB, iCurSel);
  1011. switch (fseType)
  1012. {
  1013. case e_FAT:
  1014. pwszFileSystemName = FS_STR_FAT;
  1015. break;
  1016. case e_FAT32:
  1017. pwszFileSystemName = FS_STR_FAT32;
  1018. break;
  1019. case e_NTFS:
  1020. pwszFileSystemName = FS_STR_NTFS;
  1021. break;
  1022. }
  1023. // Determine the user's choice of media formats
  1024. iCurSel = ComboBox_GetCurSel(GetDlgItem(pFormatInfo->hDlg, IDC_CAPCOMBO));
  1025. if (iCurSel == CB_ERR)
  1026. {
  1027. iCurSel = 0;
  1028. }
  1029. MediaType = pFormatInfo->rgMedia[iCurSel];
  1030. // Get the cluster size. First selection ("Use Default") yields a zero,
  1031. // while the next 4 select 512, 1024, 2048, or 4096
  1032. iCurSel = ComboBox_GetCurSel(GetDlgItem(pFormatInfo->hDlg, IDC_ASCOMBO));
  1033. if ((iCurSel == CB_ERR) || (iCurSel == 0))
  1034. {
  1035. pFormatInfo->dwClusterSize = 0;
  1036. }
  1037. else
  1038. {
  1039. pFormatInfo->dwClusterSize = 256 << iCurSel;
  1040. }
  1041. // Quickformatting?
  1042. fQuickFormat = Button_GetCheck(GetDlgItem(pFormatInfo->hDlg, IDC_QFCHECK));
  1043. // Clear the error state.
  1044. pFormatInfo->fErrorAlready = FALSE;
  1045. // Tell the shell to get ready... Announce that the media is no
  1046. // longer valid (so people who have active views on it will navigate
  1047. // away) and tell the shell to close its FindFirstChangeNotifications.
  1048. if (SUCCEEDED(SHILCreateFromPath(pFormatInfo->wszDriveName, &pidlFormat, NULL)))
  1049. {
  1050. SHChangeNotify(SHCNE_MEDIAREMOVED, SHCNF_IDLIST | SHCNF_FLUSH, pidlFormat, 0);
  1051. SHChangeNotifySuspendResume(TRUE, pidlFormat, TRUE, 0);
  1052. }
  1053. else
  1054. {
  1055. pidlFormat = NULL;
  1056. }
  1057. if (!pFormatInfo->fMakeBootDisk)
  1058. {
  1059. // Do the format.
  1060. pFormatInfo->fmifs.FormatEx(pFormatInfo->wszDriveName,
  1061. MediaType,
  1062. (PWSTR)pwszFileSystemName,
  1063. pFormatInfo->wszVolName,
  1064. fQuickFormat,
  1065. pFormatInfo->dwClusterSize,
  1066. FormatCallback);
  1067. }
  1068. else
  1069. {
  1070. pFormatInfo->diskcopy.MakeBootDisk(pFormatInfo->diskcopy.hDISKCOPY_DLL, pFormatInfo->drive, &pFormatInfo->fCancelled, FormatCallback);
  1071. }
  1072. // Wake the shell back up.
  1073. if (pidlFormat)
  1074. {
  1075. SHChangeNotifySuspendResume(FALSE, pidlFormat, TRUE, 0);
  1076. ILFree(pidlFormat);
  1077. }
  1078. // Success or failure, we should fire a notification on the disk
  1079. // since we don't really know the state after the format
  1080. SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATHW, (void *)pFormatInfo->wszDriveName, NULL);
  1081. }
  1082. else
  1083. {
  1084. // couldn't get the filesys CB selection
  1085. hr = E_FAIL;
  1086. }
  1087. // Release the TLS index
  1088. UnstuffFormatInfoPtr();
  1089. }
  1090. // Post a message back to the DialogProc thread to let it know
  1091. // the format is done. We post the message since otherwise the
  1092. // DialogProc thread will be too busy waiting for this thread
  1093. // to exit to be able to process the PWM_FORMATDONE message
  1094. // immediately.
  1095. PostMessage(pFormatInfo->hDlg, (UINT) PWM_FORMATDONE, 0, 0);
  1096. ReleaseFormatInfo(pFormatInfo);
  1097. return (DWORD)hr;
  1098. }
  1099. BOOL_PTR CALLBACK FormatDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
  1100. {
  1101. HRESULT hr = S_OK;
  1102. int iID = GET_WM_COMMAND_ID(wParam, lParam);
  1103. int iCMD = GET_WM_COMMAND_CMD(wParam, lParam);
  1104. // Grab our previously cached pointer to the FORMATINFO struct (see WM_INITDIALOG)
  1105. FORMATINFO *pFormatInfo = (FORMATINFO *) GetWindowLongPtr(hDlg, DWLP_USER);
  1106. switch (wMsg)
  1107. {
  1108. case PWM_FORMATDONE:
  1109. // Format is done. Reset the window title and clear the progress meter
  1110. SetDriveWindowTitle(pFormatInfo->hDlg, pFormatInfo->wszDriveName, IDS_FMT_FORMAT);
  1111. SendDlgItemMessage(pFormatInfo->hDlg, IDC_FMTPROGRESS, PBM_SETPOS, 0 /* Reset Percent Complete */, 0);
  1112. EnableControls(pFormatInfo, TRUE);
  1113. if (pFormatInfo->fCancelled)
  1114. {
  1115. // Don't put up UI if the background thread finally finished
  1116. // long after the user issued the cancel
  1117. if (!pFormatInfo->fShouldCancel)
  1118. {
  1119. ShellMessageBox(HINST_THISDLL,
  1120. pFormatInfo->hDlg,
  1121. MAKEINTRESOURCE(IDS_FORMATCANCELLED),
  1122. NULL,
  1123. MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK);
  1124. }
  1125. pFormatInfo->fCancelled = FALSE;
  1126. }
  1127. if (pFormatInfo->hThread)
  1128. {
  1129. CloseHandle(pFormatInfo->hThread);
  1130. pFormatInfo->hThread = NULL;
  1131. }
  1132. break;
  1133. case WM_INITDIALOG:
  1134. // Initialize the dialog and cache the FORMATINFO structure's pointer
  1135. // as our dialog's DWLP_USER data
  1136. pFormatInfo = (FORMATINFO *) lParam;
  1137. pFormatInfo->hDlg = hDlg;
  1138. if (FAILED(InitializeFormatDlg(pFormatInfo)))
  1139. {
  1140. EndDialog(hDlg, 0);
  1141. return -1;
  1142. }
  1143. SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  1144. break;
  1145. case WM_DESTROY:
  1146. if (pFormatInfo && pFormatInfo->hDlg)
  1147. {
  1148. pFormatInfo->hDlg = NULL;
  1149. }
  1150. break;
  1151. case WM_COMMAND:
  1152. if (iCMD == CBN_SELCHANGE)
  1153. {
  1154. // User made a selection in one of the combo boxes
  1155. if (iID == IDC_FSCOMBO)
  1156. {
  1157. // User selected a filesystem... update the rest of the dialog
  1158. // based on this choice
  1159. HWND hFilesystemCombo = (HWND)lParam;
  1160. int iCurSel = ComboBox_GetCurSel(hFilesystemCombo);
  1161. FileSysChange((FILESYSENUM)ComboBox_GetItemData(hFilesystemCombo, iCurSel), pFormatInfo);
  1162. }
  1163. }
  1164. else
  1165. {
  1166. // Codepath for controls other than combo boxes...
  1167. switch (iID)
  1168. {
  1169. case IDC_BTCHECK:
  1170. pFormatInfo->fMakeBootDisk = IsDlgButtonChecked(pFormatInfo->hDlg, IDC_BTCHECK);
  1171. EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_CAPCOMBO), !pFormatInfo->fMakeBootDisk);
  1172. EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_FSCOMBO), !pFormatInfo->fMakeBootDisk);
  1173. EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_ASCOMBO), !pFormatInfo->fMakeBootDisk);
  1174. EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_VLABEL), !pFormatInfo->fMakeBootDisk);
  1175. EnableWindow(GetDlgItem(pFormatInfo->hDlg, IDC_QFCHECK), !pFormatInfo->fMakeBootDisk);
  1176. break;
  1177. case IDC_ECCHECK:
  1178. pFormatInfo->fEnableComp = IsDlgButtonChecked(hDlg, IDC_ECCHECK);
  1179. break;
  1180. case IDOK:
  1181. {
  1182. // Get user verification for format, break out on CANCEL
  1183. if (IDCANCEL == ShellMessageBox(HINST_THISDLL,
  1184. hDlg,
  1185. MAKEINTRESOURCE(IDS_OKTOFORMAT),
  1186. NULL,
  1187. MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OKCANCEL))
  1188. {
  1189. break;
  1190. }
  1191. ASSERT(pFormatInfo->hThread == NULL);
  1192. DisableControls(pFormatInfo);
  1193. pFormatInfo->fCancelled = FALSE;
  1194. pFormatInfo->fShouldCancel = FALSE;
  1195. GetWindowText(GetDlgItem(pFormatInfo->hDlg, IDC_VLABEL), pFormatInfo->wszVolName, MAX_PATH);
  1196. AddRefFormatInfo(pFormatInfo);
  1197. pFormatInfo->hThread = CreateThread(NULL,
  1198. 0,
  1199. BeginFormat,
  1200. (void *)pFormatInfo,
  1201. 0,
  1202. NULL);
  1203. if (!pFormatInfo->hThread)
  1204. {
  1205. // ISSUE: we should probably do something...
  1206. ReleaseFormatInfo(pFormatInfo);
  1207. }
  1208. }
  1209. break;
  1210. case IDCANCEL:
  1211. // If the format thread is running, wait for it. If not,
  1212. // exit the dialog
  1213. pFormatInfo->fShouldCancel = TRUE;
  1214. if (pFormatInfo->hThread)
  1215. {
  1216. DWORD dwWait;
  1217. do
  1218. {
  1219. dwWait = WaitForSingleObject(pFormatInfo->hThread, 10000);
  1220. }
  1221. while ((WAIT_TIMEOUT == dwWait) &&
  1222. (IDRETRY == ShellMessageBox(HINST_THISDLL,
  1223. hDlg,
  1224. MAKEINTRESOURCE(IDS_CANTCANCELFMT),
  1225. NULL,
  1226. MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_RETRYCANCEL)));
  1227. // If the format doesn't admit to having been killed, it didn't
  1228. // give up peacefully. Just abandon it and let it clean up
  1229. // when it finally gets around to it, at which point we will
  1230. // enable the OK button to let the user take another stab.
  1231. //
  1232. // Careful: The format may have cleaned up while the dialog box
  1233. // was up, so revalidate.
  1234. if (pFormatInfo->hThread)
  1235. {
  1236. CloseHandle(pFormatInfo->hThread);
  1237. pFormatInfo->hThread = NULL;
  1238. pFormatInfo->fCancelled = TRUE;
  1239. EnableControls(pFormatInfo, FALSE);
  1240. }
  1241. }
  1242. else
  1243. {
  1244. EndDialog(hDlg, IDCANCEL);
  1245. }
  1246. break;
  1247. }
  1248. }
  1249. break;
  1250. case WM_HELP:
  1251. WinHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP, (ULONG_PTR) (LPSTR) FmtaIds);
  1252. break;
  1253. case WM_CONTEXTMENU:
  1254. WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU, (ULONG_PTR) (LPSTR) FmtaIds);
  1255. break;
  1256. default:
  1257. return FALSE;
  1258. }
  1259. return TRUE;
  1260. }
  1261. //
  1262. // Synopsis: The SHFormatDrive API provides access to the Shell
  1263. // format dialog. This allows apps which want to format disks
  1264. // to bring up the same dialog that the Shell does to do it.
  1265. //
  1266. // NOTE that the user can format as many diskettes in the
  1267. // specified drive, or as many times, as he/she wishes to.
  1268. //
  1269. // Arguments: [hwnd] -- Parent window (Must NOT be NULL)
  1270. // [drive] -- 0 = A:, 1 = B:, etc.
  1271. // [fmtID] -- see below
  1272. // [options] -- SHFMT_OPT_FULL overrised default quickformat
  1273. // SHFMT_OPT_SYSONLY not support for NT
  1274. //
  1275. // Returns: See Notes
  1276. //
  1277. DWORD WINAPI SHFormatDrive(HWND hwnd, UINT drive, UINT fmtID, UINT options)
  1278. {
  1279. INT_PTR ret;
  1280. FORMATINFO *pFormatInfo = (FORMATINFO *)LocalAlloc(LPTR, sizeof(*pFormatInfo));
  1281. ASSERT(drive < 26);
  1282. if (!pFormatInfo)
  1283. return SHFMT_ERROR;
  1284. HRESULT hrCoInit = SHCoInitialize();
  1285. pFormatInfo->cRef = 1;
  1286. pFormatInfo->drive = drive;
  1287. pFormatInfo->fmtID = fmtID;
  1288. pFormatInfo->options = options;
  1289. // It makes no sense for NT to "SYS" a disk
  1290. if (pFormatInfo->options & SHFMT_OPT_SYSONLY)
  1291. {
  1292. ret = 0;
  1293. goto done;
  1294. }
  1295. // Load FMIFS.DLL and DISKCOPY.DLL and open the Format dialog
  1296. if (S_OK == LoadFMIFS(&pFormatInfo->fmifs) &&
  1297. S_OK == LoadDISKCOPY(&pFormatInfo->diskcopy))
  1298. {
  1299. DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_FORMATDISK),
  1300. hwnd, FormatDlgProc, (LPARAM) pFormatInfo);
  1301. }
  1302. else
  1303. {
  1304. ASSERT(0 && "Can't load FMIFS.DLL");
  1305. ret = SHFMT_ERROR;
  1306. goto done;
  1307. }
  1308. // Since time immemorial it has been almost impossible to
  1309. // get SHFMT_CANCEL as a return code. Most of the time, you get
  1310. // SHFMT_ERROR if the user cancels.
  1311. if (pFormatInfo->fCancelled)
  1312. {
  1313. ret = SHFMT_CANCEL;
  1314. }
  1315. else if (pFormatInfo->fFinishedOK)
  1316. {
  1317. // APPCOMPAT: (stephstm) We used to say that we return the Serial
  1318. // Number but we never did. So keep on returning 0 for success.
  1319. // Furthermore, Serial number values could conflict SHFMT_*
  1320. // error codes.
  1321. ret = 0;
  1322. }
  1323. else
  1324. {
  1325. ret = SHFMT_ERROR;
  1326. }
  1327. done:
  1328. ReleaseFormatInfo(pFormatInfo);
  1329. SHCoUninitialize(hrCoInit);
  1330. return (DWORD)ret;
  1331. }
  1332. ////////////////////////////////////////////////////////////////////////////
  1333. //
  1334. // CHKDSK
  1335. //
  1336. ////////////////////////////////////////////////////////////////////////////
  1337. //
  1338. // This structure described the current chkdsk session
  1339. //
  1340. typedef struct
  1341. {
  1342. UINT lastpercent; // last percentage complete received
  1343. UINT currentphase; // current chkdsk phase
  1344. FMIFS fmifs; // ptr to FMIFS structure, above
  1345. BOOL fRecovery; // Attempt to recover bad sectors
  1346. BOOL fFixErrors; // Fix filesystem errors as found
  1347. BOOL fCancelled; // Was chkdsk terminated early?
  1348. BOOL fShouldCancel; // User has clicked cancel; pending abort
  1349. HWND hDlg; // handle to the chkdsk dialog
  1350. HANDLE hThread;
  1351. BOOL fNoFinalMsg; // Do not put up a final failure message
  1352. WCHAR wszDriveName[MAX_PATH]; // For example, "A:\", or "C:\folder\mountedvolume\"
  1353. LONG cRef; // reference count on this structure
  1354. } CHKDSKINFO;
  1355. void AddRefChkDskInfo(CHKDSKINFO *pChkDskInfo)
  1356. {
  1357. InterlockedIncrement(&pChkDskInfo->cRef);
  1358. }
  1359. void ReleaseChkDskInfo(CHKDSKINFO *pChkDskInfo)
  1360. {
  1361. ASSERT( 0 != pChkDskInfo->cRef );
  1362. if (InterlockedDecrement(&pChkDskInfo->cRef) == 0)
  1363. {
  1364. if (pChkDskInfo->fmifs.hFMIFS_DLL)
  1365. {
  1366. FreeLibrary(pChkDskInfo->fmifs.hFMIFS_DLL);
  1367. }
  1368. if (pChkDskInfo->hThread)
  1369. {
  1370. CloseHandle(pChkDskInfo->hThread);
  1371. }
  1372. LocalFree(pChkDskInfo);
  1373. }
  1374. }
  1375. static DWORD g_iTLSChkDskInfo = 0;
  1376. static LONG g_cTLSChkDskInfo = 0; // Usage count
  1377. //
  1378. // Synopsis: Allocates a thread-local index slot for this thread's
  1379. // CHKDSKINFO pointer, if the index doesn't already exist.
  1380. // In any event, stores the CHKDSKINFO pointer in the slot
  1381. // and increments the index's usage count.
  1382. //
  1383. // Arguments: [pChkDskInfo] -- The pointer to store
  1384. //
  1385. // Returns: HRESULT
  1386. //
  1387. //
  1388. // Thread-Local Storage index for our CHKDSKINFO structure pointer
  1389. //
  1390. HRESULT StuffChkDskInfoPtr(CHKDSKINFO *pChkDskInfo)
  1391. {
  1392. HRESULT hr = S_OK;
  1393. // Allocate an index slot for our thread-local CHKDSKINFO pointer, if one
  1394. // doesn't already exist, then stuff our CHKDSKINFO ptr at that index.
  1395. ENTERCRITICAL;
  1396. if (0 == g_iTLSChkDskInfo)
  1397. {
  1398. g_iTLSChkDskInfo = TlsAlloc();
  1399. if (g_iTLSChkDskInfo == (DWORD)-1)
  1400. {
  1401. hr = HRESULT_FROM_WIN32(GetLastError());
  1402. }
  1403. g_cTLSChkDskInfo = 0;
  1404. }
  1405. if (S_OK == hr)
  1406. {
  1407. if (TlsSetValue(g_iTLSChkDskInfo, (void *)pChkDskInfo))
  1408. {
  1409. g_cTLSChkDskInfo++;
  1410. }
  1411. else
  1412. {
  1413. hr = HRESULT_FROM_WIN32(GetLastError());
  1414. }
  1415. }
  1416. LEAVECRITICAL;
  1417. return hr;
  1418. }
  1419. //
  1420. // Synopsis: Decrements the usage count on our thread-local storage
  1421. // index, and if it goes to zero the index is free'd
  1422. //
  1423. // Arguments: [none]
  1424. //
  1425. // Returns: none
  1426. //
  1427. void UnstuffChkDskInfoPtr()
  1428. {
  1429. ENTERCRITICAL;
  1430. g_cTLSChkDskInfo--;
  1431. if (g_cTLSChkDskInfo == 0)
  1432. {
  1433. TlsFree(g_iTLSChkDskInfo);
  1434. g_iTLSChkDskInfo = 0;
  1435. }
  1436. LEAVECRITICAL;
  1437. }
  1438. //
  1439. // Synopsis: Retrieves this threads CHKDSKINFO ptr by grabbing the
  1440. // thread-local value previously stuff'd
  1441. //
  1442. // Arguments: [none]
  1443. //
  1444. // Returns: The pointer, of course
  1445. //
  1446. CHKDSKINFO *GetChkDskInfoPtr()
  1447. {
  1448. return (CHKDSKINFO *)TlsGetValue(g_iTLSChkDskInfo);
  1449. }
  1450. //
  1451. // Synopsis: Ghosts all controls except "Cancel", saving their
  1452. // previous state in the CHKDSKINFO structure
  1453. //
  1454. // Arguments: [pChkDskInfo] -- Describes a ChkDsk dialog session
  1455. //
  1456. // Notes: Also changes "Close" button text to read "Cancel"
  1457. //
  1458. void DisableChkDskControls(CHKDSKINFO *pChkDskInfo)
  1459. {
  1460. // We disable CANCEL because CHKDSK does not
  1461. // allow interruption at the filesystem level.
  1462. EnableWindow(GetDlgItem(pChkDskInfo->hDlg, IDC_FIXERRORS), FALSE);
  1463. EnableWindow(GetDlgItem(pChkDskInfo->hDlg, IDC_RECOVERY), FALSE);
  1464. EnableWindow(GetDlgItem(pChkDskInfo->hDlg, IDOK), FALSE);
  1465. EnableWindow(GetDlgItem(pChkDskInfo->hDlg, IDCANCEL), FALSE);
  1466. }
  1467. //
  1468. // Synopsis: Restores controls to the enabled/disabled state they were
  1469. // before a previous call to DisableControls().
  1470. //
  1471. // Arguments: [pChkDskInfo] -- Decribes a chkdsk dialog session
  1472. //
  1473. void EnableChkDskControls(CHKDSKINFO *pChkDskInfo)
  1474. {
  1475. EnableWindow(GetDlgItem(pChkDskInfo->hDlg, IDC_FIXERRORS), TRUE);
  1476. EnableWindow(GetDlgItem(pChkDskInfo->hDlg, IDC_RECOVERY), TRUE);
  1477. EnableWindow(GetDlgItem(pChkDskInfo->hDlg, IDOK), TRUE);
  1478. EnableWindow(GetDlgItem(pChkDskInfo->hDlg, IDCANCEL), TRUE);
  1479. // Erase the current phase text
  1480. SetWindowText(GetDlgItem(pChkDskInfo->hDlg, IDC_PHASE), TEXT(""));
  1481. pChkDskInfo->lastpercent = 101;
  1482. pChkDskInfo->currentphase = 0;
  1483. }
  1484. //
  1485. // Synopsis: Called from within the FMIFS DLL's ChkDsk function, this
  1486. // updates the ChkDsk dialog's status bar and responds to
  1487. // chkdsk completion/error notifications.
  1488. //
  1489. // Arguments: [PacketType] -- Type of packet (ie: % complete, error, etc)
  1490. // [PacketLength] -- Size, in bytes, of the packet
  1491. // [pPacketData] -- Pointer to the packet
  1492. //
  1493. // Returns: BOOLEAN continuation value
  1494. //
  1495. BOOLEAN ChkDskCallback(FMIFS_PACKET_TYPE PacketType, ULONG PacketLength, void *pPacketData)
  1496. {
  1497. UINT iMessageID = IDS_CHKDSKFAILED;
  1498. BOOL fFailed = FALSE;
  1499. CHKDSKINFO* pChkDskInfo = GetChkDskInfoPtr();
  1500. ASSERT(g_iTLSChkDskInfo);
  1501. // Grab the CHKDSKINFO structure for this thread
  1502. if (pChkDskInfo)
  1503. {
  1504. if (!pChkDskInfo->fShouldCancel)
  1505. {
  1506. switch(PacketType)
  1507. {
  1508. case FmIfsAccessDenied:
  1509. fFailed = TRUE;
  1510. iMessageID = IDS_CHKACCESSDENIED;
  1511. break;
  1512. case FmIfsCheckOnReboot:
  1513. {
  1514. FMIFS_CHECKONREBOOT_INFORMATION * pRebootInfo = (FMIFS_CHECKONREBOOT_INFORMATION *)pPacketData;
  1515. // Check to see whether or not the user wants to schedule this
  1516. // chkdsk for the next reboot, since the drive cannot be locked
  1517. // right now.
  1518. if (IDYES == ShellMessageBox(HINST_THISDLL,
  1519. pChkDskInfo->hDlg,
  1520. MAKEINTRESOURCE(IDS_CHKONREBOOT),
  1521. NULL,
  1522. MB_SETFOREGROUND | MB_ICONINFORMATION | MB_YESNO))
  1523. {
  1524. // Yes, have FMIFS schedule an autochk for us
  1525. pRebootInfo->QueryResult = TRUE;
  1526. pChkDskInfo->fNoFinalMsg = TRUE;
  1527. }
  1528. else
  1529. {
  1530. // Nope, just fail out with "cant lock drive"
  1531. fFailed = TRUE;
  1532. iMessageID = IDS_CHKDSKFAILED;
  1533. }
  1534. }
  1535. break;
  1536. case FmIfsMediaWriteProtected:
  1537. fFailed = TRUE;
  1538. iMessageID = IDS_WRITEPROTECTED;
  1539. break;
  1540. case FmIfsIoError:
  1541. fFailed = TRUE;
  1542. iMessageID = IDS_IOERROR;
  1543. // FUTURE Consider showing head/track etc where error was
  1544. break;
  1545. case FmIfsPercentCompleted:
  1546. {
  1547. FMIFS_PERCENT_COMPLETE_INFORMATION* pPercent = (FMIFS_PERCENT_COMPLETE_INFORMATION *)pPacketData;
  1548. SendMessage(GetDlgItem(pChkDskInfo->hDlg, IDC_CHKDSKPROGRESS),
  1549. PBM_SETPOS,
  1550. pPercent->PercentCompleted, // updatee % complete
  1551. 0);
  1552. if (pPercent->PercentCompleted < pChkDskInfo->lastpercent)
  1553. {
  1554. WCHAR wszTmp[100];
  1555. WCHAR wszFormat[100];
  1556. // If this % complete is less than the last one seen,
  1557. // we have completed a phase of the chkdsk and should
  1558. // advance to the next one.
  1559. LoadString(HINST_THISDLL, IDS_CHKPHASE, wszFormat, ARRAYSIZE(wszFormat));
  1560. StringCchPrintf(wszTmp, ARRAYSIZE(wszTmp), wszFormat, ++(pChkDskInfo->currentphase)); // ok to truncate
  1561. SetDlgItemText(pChkDskInfo->hDlg, IDC_PHASE, wszTmp);
  1562. }
  1563. pChkDskInfo->lastpercent = pPercent->PercentCompleted;
  1564. }
  1565. break;
  1566. case FmIfsFinished:
  1567. {
  1568. // ChkDsk is done; check for failure or success
  1569. FMIFS_FINISHED_INFORMATION * pFinishedInfo = (FMIFS_FINISHED_INFORMATION *) pPacketData;
  1570. // ChkDskEx now return the proper success value
  1571. if (pFinishedInfo->Success)
  1572. {
  1573. // Since we're done, force the progress gauge to 100%, so we
  1574. // don't sit here if the chkdsk code misled us
  1575. SendMessage(GetDlgItem(pChkDskInfo->hDlg, IDC_CHKDSKPROGRESS),
  1576. PBM_SETPOS,
  1577. 100, // Percent Complete
  1578. 0);
  1579. ShellMessageBox(HINST_THISDLL,
  1580. pChkDskInfo->hDlg,
  1581. MAKEINTRESOURCE(IDS_CHKDSKCOMPLETE),
  1582. NULL,
  1583. MB_SETFOREGROUND | MB_ICONINFORMATION | MB_OK);
  1584. SetDlgItemText(pChkDskInfo->hDlg, IDC_PHASE, TEXT(""));
  1585. SendMessage(GetDlgItem(pChkDskInfo->hDlg, IDC_CHKDSKPROGRESS),
  1586. PBM_SETPOS,
  1587. 0, // reset Percent Complete
  1588. 0);
  1589. }
  1590. else
  1591. {
  1592. iMessageID = IDS_CHKDSKFAILED;
  1593. fFailed = TRUE;
  1594. }
  1595. }
  1596. break;
  1597. }
  1598. // If we received any kind of failure information, put up a final
  1599. // "ChkDsk Failed" message.
  1600. if (fFailed && (pChkDskInfo->fNoFinalMsg == FALSE))
  1601. {
  1602. pChkDskInfo->fNoFinalMsg = TRUE;
  1603. ShellMessageBox(HINST_THISDLL,
  1604. pChkDskInfo->hDlg,
  1605. MAKEINTRESOURCE(iMessageID),
  1606. NULL,
  1607. MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK);
  1608. }
  1609. }
  1610. else
  1611. {
  1612. // If the user has signalled to abort the ChkDsk, return
  1613. // FALSE out of here right now
  1614. pChkDskInfo->fCancelled = TRUE;
  1615. fFailed = TRUE;
  1616. }
  1617. }
  1618. else
  1619. {
  1620. fFailed = TRUE;
  1621. }
  1622. return (BOOLEAN) (fFailed == FALSE);
  1623. }
  1624. void DoChkDsk(CHKDSKINFO* pChkDskInfo, LPWSTR pwszFileSystem)
  1625. {
  1626. TCHAR szVolumeGUID[50]; // 50: from doc
  1627. FMIFS_CHKDSKEX_PARAM param = {0};
  1628. param.Major = 1;
  1629. param.Minor = 0;
  1630. param.Flags = pChkDskInfo->fRecovery ? FMIFS_CHKDSK_RECOVER : 0;
  1631. GetVolumeNameForVolumeMountPoint(pChkDskInfo->wszDriveName,
  1632. szVolumeGUID,
  1633. ARRAYSIZE(szVolumeGUID));
  1634. // the backslash at the end means check for fragmentation.
  1635. PathRemoveBackslash(szVolumeGUID);
  1636. pChkDskInfo->fmifs.ChkDskEx(szVolumeGUID,
  1637. pwszFileSystem,
  1638. (BOOLEAN)pChkDskInfo->fFixErrors,
  1639. &param,
  1640. ChkDskCallback);
  1641. }
  1642. //
  1643. // Synopsis: Spun off as its own thread, this ghosts all controls in the
  1644. // dialog except "Cancel", then does the actual ChkDsk
  1645. //
  1646. // Arguments: [pIn] -- CHKDSKINFO structure pointer as a void *
  1647. //
  1648. // Returns: HRESULT thread exit code
  1649. //
  1650. DWORD WINAPI BeginChkDsk(void * pIn)
  1651. {
  1652. CHKDSKINFO *pChkDskInfo = (CHKDSKINFO *)pIn;
  1653. HRESULT hr;
  1654. // Save the CHKDSKINFO ptr for this thread, to be used in the ChkDsk
  1655. // callback function
  1656. hr = StuffChkDskInfoPtr(pChkDskInfo);
  1657. if (hr == S_OK)
  1658. {
  1659. WCHAR swzFileSystem[MAX_PATH];
  1660. // Get the filesystem in use on the device
  1661. if (GetVolumeInformationW(pChkDskInfo->wszDriveName,
  1662. NULL,
  1663. 0,
  1664. NULL,
  1665. NULL,
  1666. NULL,
  1667. swzFileSystem,
  1668. MAX_PATH))
  1669. {
  1670. // Set the window title to indicate ChkDsk in proress...
  1671. SetDriveWindowTitle(pChkDskInfo->hDlg, pChkDskInfo->wszDriveName, IDS_CHKINPROGRESS);
  1672. pChkDskInfo->fNoFinalMsg = FALSE;
  1673. // Should we try data recovery?
  1674. pChkDskInfo->fRecovery = IsDlgButtonChecked(pChkDskInfo->hDlg, IDC_RECOVERY);
  1675. // Should we fix filesystem errors?
  1676. pChkDskInfo->fFixErrors = IsDlgButtonChecked(pChkDskInfo->hDlg, IDC_FIXERRORS);
  1677. // just do it!
  1678. DoChkDsk(pChkDskInfo, swzFileSystem);
  1679. }
  1680. else
  1681. {
  1682. hr = HRESULT_FROM_WIN32(GetLastError());
  1683. }
  1684. // Release the TLS index
  1685. UnstuffChkDskInfoPtr();
  1686. }
  1687. PostMessage(pChkDskInfo->hDlg, (UINT) PWM_CHKDSKDONE, 0, 0);
  1688. ReleaseChkDskInfo(pChkDskInfo);
  1689. return (DWORD)hr;
  1690. }
  1691. //
  1692. // Synopsis: DLGPROC for the chkdsk dialog
  1693. //
  1694. // Arguments: [hDlg] -- Typical
  1695. // [wMsg] -- Typical
  1696. // [wParam] -- Typical
  1697. // [lParam] -- For WM_INIT, carries the CHKDSKINFO structure
  1698. // pointer passed to DialogBoxParam() when the
  1699. // dialog was created.
  1700. //
  1701. BOOL_PTR CALLBACK ChkDskDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
  1702. {
  1703. HRESULT hr = S_OK;
  1704. int iID = GET_WM_COMMAND_ID(wParam, lParam);
  1705. // Grab our previously cached pointer to the CHKDSKINFO struct (see WM_INITDIALOG)
  1706. CHKDSKINFO *pChkDskInfo = (CHKDSKINFO *) GetWindowLongPtr(hDlg, DWLP_USER);
  1707. switch (wMsg)
  1708. {
  1709. // done. Reset the window title and clear the progress meter
  1710. case PWM_CHKDSKDONE:
  1711. {
  1712. // chdsk is done. Reset the window title and clear the progress meter
  1713. SetDriveWindowTitle(pChkDskInfo->hDlg, pChkDskInfo->wszDriveName, IDS_CHKDISK);
  1714. SendMessage(GetDlgItem(pChkDskInfo->hDlg,
  1715. IDC_CHKDSKPROGRESS),
  1716. PBM_SETPOS,
  1717. 0, // Reset Percent Complete
  1718. 0);
  1719. EnableChkDskControls(pChkDskInfo);
  1720. if (pChkDskInfo->fCancelled)
  1721. {
  1722. ShellMessageBox(HINST_THISDLL,
  1723. pChkDskInfo->hDlg,
  1724. MAKEINTRESOURCE(IDS_CHKDSKCANCELLED),
  1725. NULL,
  1726. MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK);
  1727. }
  1728. if (pChkDskInfo->hThread)
  1729. {
  1730. CloseHandle(pChkDskInfo->hThread);
  1731. pChkDskInfo->hThread = NULL;
  1732. }
  1733. EndDialog(hDlg, 0);
  1734. }
  1735. break;
  1736. case WM_INITDIALOG:
  1737. // Initialize the dialog and cache the CHKDSKINFO structure's pointer
  1738. // as our dialog's DWLP_USER data
  1739. pChkDskInfo = (CHKDSKINFO *) lParam;
  1740. pChkDskInfo->hDlg = hDlg;
  1741. SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  1742. // Set the dialog title to indicate which drive we are dealing with
  1743. SetDriveWindowTitle(pChkDskInfo->hDlg, pChkDskInfo->wszDriveName, IDS_CHKDISK);
  1744. break;
  1745. case WM_DESTROY:
  1746. if (pChkDskInfo && pChkDskInfo->hDlg)
  1747. {
  1748. pChkDskInfo->hDlg = NULL;
  1749. }
  1750. break;
  1751. case WM_COMMAND:
  1752. {
  1753. switch (iID)
  1754. {
  1755. case IDC_FIXERRORS:
  1756. pChkDskInfo->fFixErrors = Button_GetCheck((HWND)lParam);
  1757. break;
  1758. case IDC_RECOVERY:
  1759. pChkDskInfo->fRecovery = Button_GetCheck((HWND)lParam);
  1760. break;
  1761. case IDOK:
  1762. {
  1763. // Get user verification for chkdsk, break out on CANCEL
  1764. DisableChkDskControls(pChkDskInfo);
  1765. pChkDskInfo->fShouldCancel = FALSE;
  1766. pChkDskInfo->fCancelled = FALSE;
  1767. AddRefChkDskInfo(pChkDskInfo);
  1768. pChkDskInfo->hThread = CreateThread(NULL,
  1769. 0,
  1770. BeginChkDsk,
  1771. (void *)pChkDskInfo,
  1772. 0,
  1773. NULL);
  1774. if (!pChkDskInfo->hThread)
  1775. {
  1776. // ISSUE: we should probably do something here...
  1777. ReleaseChkDskInfo(pChkDskInfo);
  1778. }
  1779. }
  1780. break;
  1781. case IDCANCEL:
  1782. {
  1783. // If the chdsk thread is running, wait for it. If not,
  1784. // exit the dialog
  1785. pChkDskInfo->fCancelled = TRUE;
  1786. pChkDskInfo->fShouldCancel = TRUE;
  1787. if (pChkDskInfo->hThread)
  1788. {
  1789. DWORD dwWait;
  1790. do
  1791. {
  1792. dwWait = WaitForSingleObject(pChkDskInfo->hThread, 10000);
  1793. }
  1794. while ((WAIT_TIMEOUT == dwWait) &&
  1795. (IDRETRY == ShellMessageBox(HINST_THISDLL,
  1796. hDlg,
  1797. MAKEINTRESOURCE(IDS_CANTCANCELCHKDSK),
  1798. NULL,
  1799. MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_RETRYCANCEL)));
  1800. // If the chkdsk doesn't admit to having been killed, it didn't
  1801. // give up peacefully. Just abandon it and let it clean up
  1802. // when it finally gets around to it, at which point we will
  1803. // enable the controls to let the user take another stab.
  1804. //
  1805. // Careful: The chkdsk may have cleaned up while the dialog box
  1806. // was up, so revalidate.
  1807. if (pChkDskInfo->hThread)
  1808. {
  1809. CloseHandle(pChkDskInfo->hThread);
  1810. pChkDskInfo->hThread = NULL;
  1811. pChkDskInfo->fCancelled = TRUE;
  1812. EnableChkDskControls(pChkDskInfo);
  1813. }
  1814. }
  1815. else
  1816. {
  1817. EndDialog(hDlg, IDCANCEL);
  1818. }
  1819. }
  1820. break;
  1821. }
  1822. }
  1823. break;
  1824. case WM_HELP:
  1825. WinHelp((HWND) ((LPHELPINFO) lParam)->hItemHandle, NULL, HELP_WM_HELP, (ULONG_PTR)(LPSTR)ChkaIds);
  1826. break;
  1827. case WM_CONTEXTMENU:
  1828. WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU, (ULONG_PTR)(LPSTR)ChkaIds);
  1829. break;
  1830. default:
  1831. return FALSE;
  1832. }
  1833. return TRUE;
  1834. }
  1835. #define GET_INTRESOURCE(r) (LOWORD((UINT_PTR)(r)))
  1836. static HDPA hpdaChkdskActive = NULL;
  1837. //
  1838. // Synopsis: Same as SHChkDskDrive but takes a path rather than a drive int ID
  1839. // Call this fct for both path and drive int ID to be protected
  1840. // against chkdsk'ing the same drive simultaneously
  1841. //
  1842. // Arguments: [hwnd] -- Parent window (Must NOT be NULL)
  1843. // [pszDrive] -- INTRESOURCE: string if mounted on folder, drive
  1844. // number if mounted on drive letter (0 based)
  1845. //
  1846. STDAPI_(DWORD) SHChkDskDriveEx(HWND hwnd, LPWSTR pszDrive)
  1847. {
  1848. HRESULT hr = SHFMT_ERROR;
  1849. WCHAR szUniqueID[50]; // 50: size of VolumeGUID, which can fit "A:\\" too
  1850. CHKDSKINFO *pChkDskInfo = (CHKDSKINFO *)LocalAlloc(LPTR, sizeof(*pChkDskInfo));
  1851. if (pChkDskInfo)
  1852. {
  1853. hr = S_OK;
  1854. // We use a last percentage-complete value of 101, to guarantee that the
  1855. // next one received will be less, indicating next (first) phase
  1856. pChkDskInfo->lastpercent = 101;
  1857. pChkDskInfo->cRef = 1;
  1858. hr = StringCchCopy(pChkDskInfo->wszDriveName, ARRAYSIZE(pChkDskInfo->wszDriveName), pszDrive);
  1859. if (SUCCEEDED(hr))
  1860. {
  1861. if (PathAddBackslash(pChkDskInfo->wszDriveName))
  1862. {
  1863. // Prevent multiple chkdsks of the same drive
  1864. GetVolumeNameForVolumeMountPoint(pChkDskInfo->wszDriveName, szUniqueID, ARRAYSIZE(szUniqueID));
  1865. // scoping ENTERCRITICAL's var definitions to make it cooperate with other ENTERCRITICAL
  1866. {
  1867. ENTERCRITICAL;
  1868. if (!hpdaChkdskActive)
  1869. {
  1870. hpdaChkdskActive = DPA_Create(1);
  1871. }
  1872. if (hpdaChkdskActive)
  1873. {
  1874. int i, n = DPA_GetPtrCount(hpdaChkdskActive);
  1875. // Go through the DPA of currently chkdsk'ed volumes, and check if we're already
  1876. // processing this volume
  1877. for (i = 0; i < n; ++i)
  1878. {
  1879. LPWSTR pszUniqueID = (LPWSTR)DPA_GetPtr(hpdaChkdskActive, i);
  1880. if (pszUniqueID)
  1881. {
  1882. if (!lstrcmpi(szUniqueID, pszUniqueID))
  1883. {
  1884. // we're already chkdsk'ing this drive
  1885. hr = E_FAIL;
  1886. break;
  1887. }
  1888. }
  1889. }
  1890. // Looks like we're currently not chkdsk'ing this volume, add it to the DPA of currently
  1891. // chkdsk'ed volumes
  1892. if (S_OK == hr)
  1893. {
  1894. LPWSTR pszUniqueID = StrDup(szUniqueID);
  1895. if (pszUniqueID)
  1896. {
  1897. if (-1 == DPA_AppendPtr(hpdaChkdskActive, pszUniqueID))
  1898. {
  1899. LocalFree((HLOCAL)pszUniqueID);
  1900. // if can't allocate room to store a pointer, pretty useless to go on
  1901. hr = E_FAIL;
  1902. }
  1903. }
  1904. }
  1905. }
  1906. LEAVECRITICAL;
  1907. }
  1908. }
  1909. else
  1910. {
  1911. hr = HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE);
  1912. }
  1913. }
  1914. // Load the FMIFS DLL and open the ChkDsk dialog
  1915. if (S_OK == hr)
  1916. {
  1917. if (S_OK == LoadFMIFS(&(pChkDskInfo->fmifs)))
  1918. {
  1919. INT_PTR ret;
  1920. INITCOMMONCONTROLSEX icc = {sizeof(icc), ICC_PROGRESS_CLASS};
  1921. InitCommonControlsEx(&icc);
  1922. ret = DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(DLG_CHKDSK),
  1923. hwnd, ChkDskDlgProc, (LPARAM) pChkDskInfo);
  1924. if (-1 == ret)
  1925. {
  1926. hr = E_UNEXPECTED;
  1927. }
  1928. else
  1929. {
  1930. if (IDCANCEL == ret)
  1931. {
  1932. hr = S_FALSE;
  1933. }
  1934. }
  1935. }
  1936. else
  1937. {
  1938. ASSERT(0 && "Can't load FMIFS.DLL");
  1939. hr = E_OUTOFMEMORY;
  1940. }
  1941. // We're finish for this volume, remove from the list of currently processed volumes
  1942. ENTERCRITICAL;
  1943. if (hpdaChkdskActive)
  1944. {
  1945. int i, n = DPA_GetPtrCount(hpdaChkdskActive);
  1946. for (i = 0; i < n; ++i)
  1947. {
  1948. LPWSTR pszUniqueID = (LPWSTR)DPA_GetPtr(hpdaChkdskActive, i);
  1949. if (pszUniqueID)
  1950. {
  1951. if (!lstrcmpi(szUniqueID, pszUniqueID))
  1952. {
  1953. LocalFree((HLOCAL)pszUniqueID);
  1954. DPA_DeletePtr(hpdaChkdskActive, i);
  1955. break;
  1956. }
  1957. }
  1958. }
  1959. }
  1960. LEAVECRITICAL;
  1961. }
  1962. // If the DPA is empty delete it
  1963. ENTERCRITICAL;
  1964. if (hpdaChkdskActive && !DPA_GetPtrCount(hpdaChkdskActive))
  1965. {
  1966. DPA_Destroy(hpdaChkdskActive);
  1967. hpdaChkdskActive = NULL;
  1968. }
  1969. LEAVECRITICAL;
  1970. ReleaseChkDskInfo(pChkDskInfo);
  1971. }
  1972. return (DWORD) hr;
  1973. }
  1974. //****************************************************************************
  1975. //
  1976. // Special hook for Win9x app compat
  1977. //
  1978. // Some Win9x apps like to WinExec("DEFRAG") or WinExec("SCANDSKW")
  1979. // even though those apps don't exist on Windows NT. When such apps
  1980. // are found, we can shim them to come here instead.
  1981. BOOL ScanDskW_OnInitDialog(HWND hdlg)
  1982. {
  1983. HICON hico;
  1984. HWND hwndList;
  1985. SHFILEINFO sfi;
  1986. HIMAGELIST himlSys;
  1987. RECT rc;
  1988. LVCOLUMN lvc;
  1989. int iDrive;
  1990. TCHAR szDrive[4];
  1991. hico = (HICON)SendDlgItemMessage(hdlg, IDC_SCANDSKICON, STM_GETICON, 0, 0);
  1992. SendMessage(hdlg, WM_SETICON, ICON_BIG, (LPARAM)hico);
  1993. SendMessage(hdlg, WM_SETICON, ICON_SMALL, (LPARAM)hico);
  1994. hwndList = GetDlgItem(hdlg, IDC_SCANDSKLV);
  1995. if (Shell_GetImageLists(NULL, &himlSys))
  1996. {
  1997. ListView_SetImageList(hwndList, himlSys, LVSIL_SMALL);
  1998. }
  1999. GetClientRect(hwndList, &rc);
  2000. lvc.mask = LVCF_WIDTH;
  2001. lvc.cx = rc.right;
  2002. lvc.iSubItem = 0;
  2003. ListView_InsertColumn(hwndList, 0, &lvc);
  2004. for (iDrive = 0; iDrive < 26; iDrive++)
  2005. {
  2006. PathBuildRoot(szDrive, iDrive);
  2007. switch (GetDriveType(szDrive))
  2008. {
  2009. case DRIVE_UNKNOWN:
  2010. case DRIVE_NO_ROOT_DIR:
  2011. case DRIVE_REMOTE:
  2012. case DRIVE_CDROM:
  2013. break; // Can't scan these drives
  2014. default:
  2015. if (SHGetFileInfo(szDrive, FILE_ATTRIBUTE_DIRECTORY, &sfi, sizeof(sfi),
  2016. SHGFI_USEFILEATTRIBUTES |
  2017. SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_DISPLAYNAME))
  2018. {
  2019. LVITEM lvi;
  2020. lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
  2021. lvi.iItem = MAXLONG;
  2022. lvi.iSubItem = 0;
  2023. lvi.pszText = sfi.szDisplayName;
  2024. lvi.iImage = sfi.iIcon;
  2025. lvi.lParam = iDrive;
  2026. ListView_InsertItem(hwndList, &lvi);
  2027. }
  2028. break;
  2029. }
  2030. }
  2031. return TRUE;
  2032. }
  2033. void ScanDskW_OnOk(HWND hdlg)
  2034. {
  2035. HWND hwndList = GetDlgItem(hdlg, IDC_SCANDSKLV);
  2036. LVITEM lvi;
  2037. lvi.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
  2038. if (lvi.iItem >= 0)
  2039. {
  2040. lvi.iSubItem = 0;
  2041. lvi.mask = LVIF_PARAM;
  2042. if (ListView_GetItem(hwndList, &lvi))
  2043. {
  2044. TCHAR szDrive[4];
  2045. PathBuildRoot(szDrive, (int)lvi.lParam);
  2046. SHChkDskDriveEx(hdlg, szDrive);
  2047. }
  2048. }
  2049. }
  2050. INT_PTR CALLBACK
  2051. ScanDskW_DlgProc(HWND hdlg, UINT wm, WPARAM wParam, LPARAM lParam)
  2052. {
  2053. switch (wm)
  2054. {
  2055. case WM_INITDIALOG:
  2056. return ScanDskW_OnInitDialog(hdlg);
  2057. case WM_COMMAND:
  2058. switch (GET_WM_COMMAND_ID(wParam, lParam))
  2059. {
  2060. case IDOK:
  2061. ScanDskW_OnOk(hdlg);
  2062. break;
  2063. case IDCANCEL:
  2064. EndDialog(hdlg, 0);
  2065. break;
  2066. }
  2067. break;
  2068. case WM_NOTIFY:
  2069. {
  2070. LPNMHDR pnm = (LPNMHDR)lParam;
  2071. if (pnm->code == LVN_ITEMCHANGED)
  2072. {
  2073. EnableWindow(GetDlgItem(hdlg, IDOK), ListView_GetSelectedCount(GetDlgItem(hdlg, IDC_SCANDSKLV)));
  2074. }
  2075. }
  2076. break;
  2077. }
  2078. return FALSE;
  2079. }
  2080. // Right now, we have only one app compat shim entry point (SCANDSKW)
  2081. // In the future we can add others to the command line.
  2082. STDAPI_(void) AppCompat_RunDLLW(HWND hwndStub, HINSTANCE hAppInstance, LPWSTR lpwszCmdLine, int nCmdShow)
  2083. {
  2084. TCHAR szCmd[MAX_PATH];
  2085. LPTSTR pszArgs;
  2086. HRESULT hr = StringCchCopy(szCmd, ARRAYSIZE(szCmd), lpwszCmdLine);
  2087. if (SUCCEEDED(hr))
  2088. {
  2089. pszArgs = PathGetArgs(szCmd);
  2090. PathRemoveArgs(szCmd);
  2091. if (lstrcmpi(szCmd, L"SCANDSKW") == 0) {
  2092. DialogBoxParam(g_hinst, MAKEINTRESOURCE(IDD_SCANDSKW), NULL,
  2093. ScanDskW_DlgProc, (LPARAM)pszArgs);
  2094. }
  2095. }
  2096. }