Source code of Windows XP (NT5)
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.

599 lines
17 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // MAIN.C / ChkDskW
  4. //
  5. // Microsoft Confidential
  6. // Copyright (c) Microsoft Corporation 1998
  7. // All rights reserved
  8. //
  9. // 8/98 - Jason Cohen (JCOHEN)
  10. //
  11. //////////////////////////////////////////////////////////////////////////////
  12. // Include file(s).
  13. //
  14. #include "main.h"
  15. #include <stdlib.h>
  16. #include <shellapi.h>
  17. // Global variable(s).
  18. //
  19. HINSTANCE g_hInstance;
  20. DWORD g_dwDrives;
  21. DWORD g_dwFlags;
  22. TCHAR g_cSageId;
  23. // Internal function prototype(s).
  24. //
  25. static INT_PTR CALLBACK Dlg_Proc(HWND, UINT, WPARAM, LPARAM);
  26. static BOOL Dlg_OnInitDialog(HWND, HWND, LPARAM);
  27. static VOID Dlg_OnCommand(HWND, INT, HWND, UINT);
  28. static BOOL Dlg_OnDrawItem(HWND, const DRAWITEMSTRUCT *);
  29. static VOID SetSageSettings(HWND, TCHAR);
  30. static VOID RunSageSettings(HWND, TCHAR);
  31. static DWORD GetSelectedDrives(HWND, DWORD);
  32. static BOOL TanslateCommandLine(LPTSTR);
  33. static VOID ProcessCommandLine(VOID);
  34. static DWORD GetCommandLineOptions(LPTSTR **);
  35. // External function prototype(s).
  36. //
  37. HANDLE SpawnChkdsk(HWND, DWORD);
  38. WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
  39. {
  40. INT nReturn;
  41. g_hInstance = hInstance;
  42. g_dwFlags = 0;
  43. g_dwDrives = 0;
  44. ProcessCommandLine();
  45. nReturn = (INT)DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, (DLGPROC) Dlg_Proc);
  46. return nReturn;
  47. }
  48. static INT_PTR CALLBACK Dlg_Proc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  49. {
  50. switch (uMsg)
  51. {
  52. // Message cracking macros.
  53. //
  54. HANDLE_MSG(hDlg, WM_INITDIALOG, Dlg_OnInitDialog);
  55. HANDLE_MSG(hDlg, WM_COMMAND, Dlg_OnCommand);
  56. case WM_DRAWITEM:
  57. return Dlg_OnDrawItem(hDlg, (const DRAWITEMSTRUCT *) lParam);
  58. case WM_CLOSE:
  59. if ( g_dwFlags & SCANDISK_SCANNING )
  60. g_dwFlags |= SCANDISK_CANCELSCAN;
  61. else
  62. EndDialog(hDlg, 0);
  63. default:
  64. return FALSE;
  65. }
  66. return TRUE;
  67. }
  68. static BOOL Dlg_OnInitDialog(HWND hDlg, HWND hwndFocus, LPARAM lParam)
  69. {
  70. TCHAR szBuffer[256];
  71. LPTSTR lpBuffer;
  72. INT nIndex;
  73. UINT uDriveType;
  74. DWORD dwMask,
  75. dwDefault;
  76. TCHAR chDrive[] = _T("A:\\");
  77. SHFILEINFO SHFileInfo;
  78. // Init the common control library (for the progress bar).
  79. //
  80. InitCommonControls();
  81. // Set the icon for the dialog.
  82. //
  83. SetClassLongPtr(hDlg, GCLP_HICON, (LONG_PTR) LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_MAIN)));
  84. // Load any SAGERUN settings.
  85. //
  86. if ( g_dwFlags & SCANDISK_SAGERUN )
  87. RunSageSettings(hDlg, g_cSageId);
  88. // Get the system drive so we know what to default to if there
  89. // are not already default drives specified in g_dwDrives.
  90. //
  91. if ( g_dwDrives )
  92. dwDefault = g_dwDrives;
  93. else
  94. {
  95. szBuffer[0] = _T('\0');
  96. if ( GetEnvironmentVariable(_T("SystemDrive"), szBuffer, sizeof(szBuffer)) && szBuffer[0] )
  97. dwDefault = 1 << (UPPER(szBuffer[0]) - _T('A'));
  98. else
  99. dwDefault = 4; // Default to the C: drive.
  100. }
  101. // Populate the list box with the drives to scan.
  102. //
  103. g_dwDrives = GetLogicalDrives();
  104. for (dwMask = 1; g_dwDrives & ~(dwMask - 1); dwMask <<= 1)
  105. {
  106. // Is there a logical drive?
  107. //
  108. if ( g_dwDrives & dwMask )
  109. {
  110. // Reset this bit, we will or it back in if it gets
  111. // added to the list box.
  112. //
  113. g_dwDrives &= ~dwMask;
  114. // Check the drive type and it is
  115. // removable or fixed, add it to the
  116. // list box along with the icon.
  117. //
  118. uDriveType = GetDriveType(chDrive);
  119. if ( ( uDriveType == DRIVE_FIXED ) ||
  120. ( uDriveType == DRIVE_REMOVABLE ) )
  121. {
  122. SHGetFileInfo(chDrive, 0, &SHFileInfo, sizeof(SHFILEINFO), SHGFI_ICON | SHGFI_SMALLICON | SHGFI_DISPLAYNAME | SHGFI_TYPENAME);
  123. if ( (nIndex = (INT)SendDlgItemMessage(hDlg, IDC_DRIVES, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) SHFileInfo.szDisplayName)) >= 0 )
  124. {
  125. // Or back in this bit because we successfully added
  126. // the drive to the list box.
  127. //
  128. g_dwDrives |= dwMask;
  129. SendDlgItemMessage(hDlg, IDC_DRIVES, LB_SETITEMDATA, nIndex, (LPARAM) SHFileInfo.hIcon);
  130. // If this is the boot drive, we want to selecte it.
  131. //
  132. if (dwMask & dwDefault)
  133. SendDlgItemMessage(hDlg, IDC_DRIVES, LB_SETSEL, TRUE, (LPARAM) nIndex);
  134. }
  135. }
  136. }
  137. // Go look at the next drive
  138. //
  139. chDrive[0]++;
  140. }
  141. // Check for if we are in the SAGESET mode.
  142. //
  143. if ( g_dwFlags & SCANDISK_SAGESET )
  144. {
  145. if ( lpBuffer = AllocateString(NULL, IDS_OK) )
  146. {
  147. SetDlgItemText(hDlg, IDOK, lpBuffer);
  148. FREE(lpBuffer);
  149. }
  150. if ( lpBuffer = AllocateString(NULL, IDS_CANCEL) )
  151. {
  152. SetDlgItemText(hDlg, IDCANCEL, lpBuffer);
  153. FREE(lpBuffer);
  154. }
  155. ShowWindow(GetDlgItem(hDlg, IDC_PROGRESS), SW_HIDE);
  156. }
  157. // Set the estimated time.
  158. //
  159. srand(GetTickCount());
  160. wsprintf(szBuffer, _T("%d hour(s) %d minute(s)"), RANDOM(0, 1), RANDOM(1, 59));
  161. SetDlgItemText(hDlg, IDC_ESTIMATED, szBuffer);
  162. // Set the default option.
  163. //
  164. CheckRadioButton(hDlg, IDC_FIX, IDC_REMIND, IDC_FIX);
  165. EnableWindow(GetDlgItem(hDlg, IDC_TIME), FALSE);
  166. // Set the default remind time.
  167. //
  168. SetDlgItemText(hDlg, IDC_TIME, _T("5:00 PM"));
  169. // Set the focus to the default button.
  170. //
  171. SetFocus(GetDlgItem(hDlg, IDOK));
  172. // If we are in SAGERUN mode, start the scan automatically.
  173. //
  174. if ( g_dwFlags & SCANDISK_SAGERUN )
  175. {
  176. if ( SpawnChkdsk(hDlg, g_dwDrives) == NULL )
  177. EndDialog(hDlg, 0);
  178. }
  179. return FALSE;
  180. }
  181. static VOID Dlg_OnCommand(HWND hDlg, INT id, HWND hwndCtl, UINT codeNotify)
  182. {
  183. switch (id)
  184. {
  185. case IDOK:
  186. if ( g_dwFlags & SCANDISK_SAGESET )
  187. {
  188. // Just save the settings and end the dialog.
  189. //
  190. SetSageSettings(hDlg, g_cSageId);
  191. EndDialog(hDlg, 0);
  192. }
  193. else
  194. {
  195. // Run chkdsk on the drive(s).
  196. //
  197. if ( SpawnChkdsk(hDlg, g_dwDrives) == NULL )
  198. EndDialog(hDlg, 0);
  199. }
  200. break;
  201. case IDCANCEL:
  202. if ( g_dwFlags & SCANDISK_SCANNING )
  203. g_dwFlags |= SCANDISK_CANCELSCAN;
  204. else
  205. EndDialog(hDlg, 0);
  206. break;
  207. case IDC_RESTART:
  208. case IDC_SKIP:
  209. case IDC_REMIND:
  210. EnableWindow(GetDlgItem(hDlg, IDC_TIME), id == IDC_REMIND);
  211. break;
  212. }
  213. }
  214. static BOOL Dlg_OnDrawItem(HWND hWnd, const DRAWITEMSTRUCT * lpDrawItem)
  215. {
  216. HICON hIcon;
  217. TCHAR szBuffer[MAX_PATH];
  218. BOOL bRestore = FALSE;
  219. COLORREF crText,
  220. crBk;
  221. DWORD dwColor;
  222. RECT rect;
  223. HBRUSH hbrBack;
  224. // Make sure we are drawing the right control and an item.
  225. //
  226. if ( lpDrawItem->CtlID != IDC_DRIVES )
  227. return FALSE;
  228. switch ( lpDrawItem->itemAction )
  229. {
  230. case ODA_SELECT:
  231. case ODA_DRAWENTIRE:
  232. if (lpDrawItem->itemState & ODS_SELECTED)
  233. {
  234. // Set new text/background colors and store the old ones away.
  235. //
  236. crText = SetTextColor(lpDrawItem->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
  237. crBk = SetBkColor(lpDrawItem->hDC, GetSysColor(COLOR_HIGHLIGHT));
  238. // Restore the text and background colors when we are finished.
  239. //
  240. bRestore = TRUE;
  241. // Get the hightlight color to fill in the listbox item.
  242. //
  243. dwColor = GetSysColor(COLOR_HIGHLIGHT);
  244. }
  245. else
  246. {
  247. // Get the window color so we can clear the listbox item.
  248. //
  249. dwColor = GetSysColor(COLOR_WINDOW);
  250. }
  251. // Fill entire item rectangle with the appropriate color
  252. //
  253. hbrBack = CreateSolidBrush(dwColor);
  254. FillRect(lpDrawItem->hDC, &(lpDrawItem->rcItem), hbrBack);
  255. DeleteObject(hbrBack);
  256. // Display the icon associated with the item.
  257. //
  258. if ( hIcon = (HICON) SendMessage(lpDrawItem->hwndItem, LB_GETITEMDATA, lpDrawItem->itemID, (LPARAM) 0) )
  259. {
  260. DrawIconEx( lpDrawItem->hDC,
  261. lpDrawItem->rcItem.left + 2,
  262. lpDrawItem->rcItem.top,
  263. hIcon,
  264. lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top,
  265. lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top,
  266. 0,
  267. 0,
  268. DI_NORMAL);
  269. }
  270. // Display the text associated with the item.
  271. //
  272. if ( SendMessage(lpDrawItem->hwndItem, LB_GETTEXT, lpDrawItem->itemID, (LPARAM) szBuffer) >= 0 )
  273. {
  274. TextOut( lpDrawItem->hDC,
  275. lpDrawItem->rcItem.left + lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top + 4,
  276. lpDrawItem->rcItem.top + 1,
  277. szBuffer,
  278. lstrlen(szBuffer));
  279. }
  280. if (bRestore)
  281. {
  282. // Restore original text and background colors.
  283. //
  284. SetTextColor(lpDrawItem->hDC, crText);
  285. SetBkColor(lpDrawItem->hDC, crBk);
  286. }
  287. break;
  288. case ODA_FOCUS:
  289. // Get rectangle coordinates for listbox item.
  290. //
  291. SendMessage(lpDrawItem->hwndItem, LB_GETITEMRECT, lpDrawItem->itemID, (LPARAM) &rect);
  292. DrawFocusRect(lpDrawItem->hDC, &rect);
  293. break;
  294. }
  295. return TRUE;
  296. }
  297. static VOID SetSageSettings(HWND hDlg, TCHAR cSageId)
  298. {
  299. TCHAR szRegKey[MAX_PATH + 1];
  300. wsprintf(szRegKey, _T("%s\\%c"), SCANDISK_REGKEY_SAGE, cSageId);
  301. RegSetDword(HKCU, szRegKey, SCANDISK_REGVAL_DRIVES, GetSelectedDrives(hDlg, g_dwDrives));
  302. RegSetString(HKCU, szRegKey, SCANDISK_REGVAL_FIX, IsDlgButtonChecked(hDlg, IDC_AUTOFIX) ? _T("1") : _T("0"));
  303. RegSetString(HKCU, szRegKey, SCANDISK_REGVAL_SURFACE, IsDlgButtonChecked(hDlg, IDC_SURFACE) ? _T("1") : _T("0"));
  304. }
  305. static VOID RunSageSettings(HWND hDlg, TCHAR cSageId)
  306. {
  307. TCHAR szRegKey[MAX_PATH + 1];
  308. wsprintf(szRegKey, _T("%s\\%c"), SCANDISK_REGKEY_SAGE, cSageId);
  309. g_dwDrives = RegGetDword(HKCU, szRegKey, SCANDISK_REGVAL_DRIVES);
  310. CheckDlgButton(hDlg, IDC_AUTOFIX, RegCheck(HKCU, szRegKey, SCANDISK_REGVAL_FIX) ? BST_CHECKED : BST_UNCHECKED);
  311. CheckDlgButton(hDlg, IDC_SURFACE, RegCheck(HKCU, szRegKey, SCANDISK_REGVAL_SURFACE) ? BST_CHECKED : BST_UNCHECKED);
  312. }
  313. static DWORD GetSelectedDrives(HWND hDlg, DWORD dwDrives)
  314. {
  315. TCHAR szDrive[] = _T("A:\\");
  316. INT nCount,
  317. nIndex;
  318. LPINT lpnSelected,
  319. lpnIndex;
  320. DWORD dwMask;
  321. // Get the number of selected items and allocate a buffer to hold all the indexs.
  322. //
  323. if ( ( (nCount = (INT)SendDlgItemMessage(hDlg, IDC_DRIVES, LB_GETSELCOUNT, 0, 0L)) > 0 ) &&
  324. ( lpnSelected = (LPINT) MALLOC(nCount * sizeof(INT)) ) )
  325. {
  326. // Now get the list of selected items.
  327. //
  328. if ( (nCount = (INT)SendDlgItemMessage(hDlg, IDC_DRIVES, LB_GETSELITEMS, nCount, (LPARAM) lpnSelected)) > 0 )
  329. {
  330. // Loop through all the drives in the list box to see if they
  331. // are selected.
  332. //
  333. lpnIndex = lpnSelected;
  334. nIndex = 0;
  335. for (dwMask = 1; (DWORD) dwDrives & ~(dwMask - 1); dwMask <<= 1)
  336. {
  337. // Is this drive in the list box.
  338. //
  339. if ( (DWORD) dwDrives & dwMask )
  340. {
  341. // Test to see if this item is the
  342. // next selected one.
  343. //
  344. if ( *lpnIndex == nIndex )
  345. lpnIndex++;
  346. else
  347. // It isn't selected so set
  348. // the bit to zero.
  349. //
  350. dwDrives &= ~dwMask;
  351. // Keep an index of what list box
  352. // item this should be.
  353. //
  354. nIndex++;
  355. }
  356. // Go look at the next drive
  357. //
  358. szDrive[0]++;
  359. }
  360. }
  361. else
  362. dwDrives = 0;
  363. FREE(lpnSelected);
  364. }
  365. else
  366. dwDrives = 0;
  367. // Return drives selected (zero of failure).
  368. //
  369. return dwDrives;
  370. }
  371. static BOOL TanslateCommandLine(LPTSTR lpArg)
  372. {
  373. DWORD dwStrLen = lstrlen(lpArg);
  374. BOOL bTranslated = TRUE;
  375. // First check for the slash options.
  376. //
  377. if ( *lpArg == _T('/') )
  378. {
  379. // Get rid of the slash.
  380. //
  381. lpArg++;
  382. // Check for /SAGESET:#
  383. //
  384. if ( _tcsncicmp(_T("SAGESET:"), lpArg, 8) == 0 )
  385. {
  386. if ( !(g_dwFlags & (SCANDISK_SAGESET | SCANDISK_SAGERUN) ) )
  387. {
  388. g_dwFlags |= SCANDISK_SAGESET;
  389. g_cSageId = *(lpArg + 8);
  390. }
  391. }
  392. // Check for /SAGERUN:#
  393. //
  394. else if ( _tcsncicmp(_T("SAGERUN:"), lpArg, 8) == 0 )
  395. {
  396. if ( !(g_dwFlags & (SCANDISK_SAGESET | SCANDISK_SAGERUN) ) )
  397. {
  398. g_dwFlags |= SCANDISK_SAGERUN;
  399. g_cSageId = *(lpArg + 8);
  400. }
  401. }
  402. // Unknown option.
  403. //
  404. else
  405. bTranslated = FALSE;
  406. }
  407. else
  408. {
  409. // Check to see if it is a drive letter to auto select.
  410. //
  411. if ( ( UPPER(*lpArg) >= _T('A') ) && ( UPPER(*lpArg) <= _T('Z') ) && // Make sure the first character is a letter.
  412. ( ( dwStrLen == 1) || ( ( dwStrLen > 1 ) && ( *(lpArg + 1) == _T(':') ) ) ) ) // Make sure it is one character or the second is a colon.
  413. {
  414. g_dwDrives |= 1 << (UPPER(*lpArg) - _T('A'));
  415. }
  416. // Unknown option.
  417. //
  418. else
  419. bTranslated = FALSE;
  420. }
  421. return bTranslated;
  422. }
  423. static VOID ProcessCommandLine()
  424. {
  425. LPTSTR *lpArgs = NULL;
  426. DWORD dwArgs,
  427. dwIndex;
  428. dwArgs = GetCommandLineOptions(&lpArgs);
  429. for (dwIndex = 1; dwIndex < dwArgs; dwIndex++)
  430. TanslateCommandLine((LPTSTR) *(lpArgs + dwIndex));
  431. FREE(lpArgs);
  432. }
  433. static DWORD GetCommandLineOptions(LPTSTR **lpArgs)
  434. {
  435. TCHAR cParse;
  436. LPTSTR lpSearch,
  437. lpCommandLine;
  438. DWORD dwArgs = 0,
  439. dwMaxArgs = 0xFFFFFFFF;
  440. // Make sure we get the command line.
  441. //
  442. if ( (lpSearch = lpCommandLine = GetCommandLine()) == NULL )
  443. return 0;
  444. // Get the number of arguments so we can allocate
  445. // the memory for the array of command line options.
  446. //
  447. if ( lpArgs )
  448. {
  449. if ( (dwMaxArgs = GetCommandLineOptions(NULL)) == 0 )
  450. return 0;
  451. if ( (*lpArgs = (LPTSTR *) MALLOC(sizeof(LPTSTR) * dwMaxArgs)) == NULL )
  452. return 0;
  453. }
  454. // Now lets parse the arguments.
  455. //
  456. while ( *lpSearch && (dwArgs < dwMaxArgs) )
  457. {
  458. // Eat all preceeding spaces.
  459. //
  460. while ( *lpSearch == _T(' ') )
  461. lpSearch++;
  462. // Check to see if we need to look for a space or a quote
  463. // to separate the next argument.
  464. //
  465. if ( *lpSearch == _T('"') )
  466. cParse = *lpSearch++;
  467. else
  468. cParse = _T(' ');
  469. // This is be the beginning of the next argument, but
  470. // it isn't NULL terminated yet.
  471. //
  472. if ( lpArgs )
  473. *(*lpArgs + dwArgs) = lpSearch;
  474. dwArgs++;
  475. // Go through all the characters until we hit a separator.
  476. //
  477. do
  478. {
  479. // Once we get to a quote, we just want to keep going
  480. // until we get to a space.
  481. //
  482. if ( *lpSearch == _T('"') )
  483. cParse = _T(' ');
  484. // Only end when we reach the parsing character, which will
  485. // always be the space by this time (but the space won't trigger
  486. // the end until we hit a quote, if that is what we were originally
  487. // looking for). We also need to make sure that we don't increment
  488. // past the NULL terminator.
  489. //
  490. }
  491. while ( ( *lpSearch != cParse ) && ( *lpSearch ) && ( *lpSearch++ ) );
  492. // If the preceeding character is a quote, that is were we want to
  493. // place the NULL terminator.
  494. //
  495. if ( ( lpSearch > lpCommandLine ) &&
  496. ( *(lpSearch - 1) == _T('"') ) )
  497. lpSearch--;
  498. // Set and increment past the NULL terminator only if we aren't already at
  499. // the end if the string.
  500. //
  501. if ( lpArgs && *lpSearch )
  502. *lpSearch++ = _T('\0');
  503. else
  504. if ( *lpSearch ) lpSearch++;
  505. }
  506. return dwArgs;
  507. }