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.

1625 lines
42 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. #include <stdio.h>
  4. BOOL
  5. LoadInfs(
  6. IN HWND hdlg
  7. );
  8. BOOL
  9. BuildCopyList(
  10. IN HWND hdlg
  11. );
  12. BOOL
  13. LoadAndRunMigrationDlls (
  14. HWND hDlg
  15. );
  16. BOOL
  17. ProcessCompatibilityData(
  18. HWND hDlg
  19. );
  20. DWORD
  21. ProcessCompatibilitySection(
  22. LPVOID InfHandle,
  23. LPTSTR SectionName
  24. );
  25. DWORD
  26. InspectAndLoadThread(
  27. IN PVOID ThreadParam
  28. )
  29. {
  30. HWND hdlg;
  31. BOOL b;
  32. //
  33. // Thread parameter is the handle of the page in the wizard.
  34. //
  35. hdlg = ThreadParam;
  36. b = FALSE;
  37. //
  38. // If we're running the upgrade checker, fixup the title
  39. // right away.
  40. //
  41. if (CheckUpgradeOnly) {
  42. FixUpWizardTitle(GetParent(hdlg));
  43. PropSheet_SetTitle(GetParent(hdlg),0,UIntToPtr( IDS_APPTITLE_CHECKUPGRADE ));
  44. }
  45. //
  46. // Step 1: delete existing local sources.
  47. //
  48. CleanUpOldLocalSources(hdlg);
  49. #ifdef _X86_ //NEC98
  50. //
  51. // If NEC98, Backup NT4 files
  52. // boot.ini, NTLDR, NTDETECT
  53. //
  54. if (IsNEC98() && Floppyless)
  55. {
  56. SaveRestoreBootFiles_NEC98(NEC98SAVEBOOTFILES);
  57. }
  58. #endif //NEC98
  59. //
  60. // Step 2: inspect for HPFS, etc.
  61. //
  62. if(!InspectFilesystems(hdlg)) {
  63. Cancelled = TRUE;
  64. } else {
  65. //
  66. // Step 3: load inf(s).
  67. //
  68. if(LoadInfs(hdlg)) {
  69. //
  70. // Put in an "|| CheckUpgradeOnly" on these
  71. // function calls because if we're really only
  72. // checking the ability to upgrade, we want
  73. // to continue even if one of these guys fails.
  74. //
  75. //
  76. // Step 4: Check memory resources.
  77. //
  78. if( EnoughMemory( hdlg, FALSE ) || CheckUpgradeOnly ) {
  79. //
  80. // check for services to disable
  81. //
  82. ProcessCompatibilityData(hdlg);
  83. #if defined(UNICODE) && defined(_X86_)
  84. //
  85. // Run Migration DLLs.
  86. //
  87. LoadAndRunMigrationDlls (hdlg);
  88. #endif
  89. //
  90. // migrate any important data in boot.ini (like the countdown)
  91. //
  92. if (Upgrade) {
  93. if (IsArc()) {
  94. MigrateBootVarData();
  95. } else {
  96. #if defined(_AMD64_) || defined(_X86_)
  97. MigrateBootIniData();
  98. #endif
  99. }
  100. }
  101. //
  102. // Step 5: build the master file copy list.
  103. //
  104. if(CheckUpgradeOnly || BuildCopyList(hdlg)) {
  105. //
  106. // Step 6: look for a valid local source and check disk space.
  107. //
  108. if(FindLocalSourceAndCheckSpace(hdlg, FALSE, 0) || CheckUpgradeOnly) {
  109. //
  110. // Step 7:
  111. //
  112. // At this point we actually know everything we need to know
  113. // in order to pass parameters to text mode setup.
  114. //
  115. if( CheckUpgradeOnly ) {
  116. b = TRUE;
  117. } else {
  118. b = WriteParametersFile(hdlg);
  119. if (IsArc()) {
  120. #ifdef UNICODE // Always true for ARC, never true for Win9x upgrade
  121. if(b) {
  122. TCHAR Text[128];
  123. LoadString(hInst,IDS_SETTING_NVRAM,Text,sizeof(Text)/sizeof(TCHAR));
  124. SendMessage(hdlg,WMX_SETPROGRESSTEXT,0,(LPARAM)Text);
  125. b = SetUpNvRam(hdlg);
  126. }
  127. #endif // UNICODE
  128. } // if (IsArc())
  129. }
  130. #ifdef UNICODE
  131. #if defined(_AMD64_) || defined(_X86_)
  132. if( b && (Upgrade || BuildCmdcons) && Floppyless)
  133. #else
  134. if( b && Upgrade )
  135. #endif
  136. {
  137. //
  138. // Do the migration of unsupported NT drivers.
  139. // We can ignore the return code, since the fuction will inform the user if
  140. // migration could not be done.
  141. //
  142. MigrateUnsupportedNTDrivers( hdlg, TxtsetupSif );
  143. }
  144. #endif // UNICODE
  145. }
  146. }
  147. if(!b) {
  148. UnloadInfFile(MainInf);
  149. MainInf = NULL;
  150. if(TxtsetupSif) {
  151. UnloadInfFile(TxtsetupSif);
  152. TxtsetupSif = NULL;
  153. }
  154. }
  155. }
  156. }
  157. }
  158. PostMessage(hdlg,WMX_INSPECTRESULT,(CheckUpgradeOnly ? TRUE : b),0);
  159. return(0);
  160. }
  161. #if defined(UNICODE) && defined(_X86_)
  162. LIST_ENTRY g_HandledData;
  163. TCHAR g_MigDllAnswerFilePath[MAX_PATH];
  164. DWORD GlobalCompFlags;
  165. UINT g_MigDllIndex = 0;
  166. #define HANDLED_REGISTRY 1
  167. #define HANDLED_FILE 2
  168. #define HANDLED_SERVICE 3
  169. typedef struct {
  170. LIST_ENTRY ListEntry;
  171. LONG Type;
  172. PCTSTR RegKey;
  173. PCTSTR RegValue;
  174. PCTSTR File;
  175. PCTSTR Service;
  176. } HANDLED_DATA, *PHANDLED_DATA;
  177. BOOL
  178. ResolveHandledIncompatibilities (
  179. VOID
  180. )
  181. {
  182. //
  183. // At this point, all incompatibilities that will exist in the list are in place.
  184. // we can now compare this with our list of handled data and remove
  185. // anything a migration dll is taking care of.
  186. //
  187. PLIST_ENTRY nextHandled;
  188. PLIST_ENTRY nextCompData;
  189. PHANDLED_DATA handledData;
  190. PCOMPATIBILITY_DATA compData;
  191. BOOL remove;
  192. nextHandled = g_HandledData.Flink;
  193. if (!nextHandled) {
  194. return TRUE;
  195. }
  196. while ((ULONG_PTR)nextHandled != (ULONG_PTR)&g_HandledData) {
  197. handledData = CONTAINING_RECORD (nextHandled, HANDLED_DATA, ListEntry);
  198. nextHandled = handledData->ListEntry.Flink;
  199. nextCompData = CompatibilityData.Flink;
  200. if (!nextCompData) {
  201. return TRUE;
  202. }
  203. while ((ULONG_PTR)nextCompData != (ULONG_PTR)&CompatibilityData) {
  204. compData = CONTAINING_RECORD (nextCompData, COMPATIBILITY_DATA, ListEntry);
  205. nextCompData = compData->ListEntry.Flink;
  206. remove = FALSE;
  207. if (handledData->Type == HANDLED_REGISTRY && compData->RegKey && *compData->RegKey) {
  208. if (!lstrcmpi (compData->RegKey, handledData->RegKey)) {
  209. if (!handledData->RegValue || !lstrcmpi (compData->RegValue, handledData->RegValue)) {
  210. remove = TRUE;
  211. }
  212. }
  213. }
  214. if (handledData->Type == HANDLED_SERVICE && compData->ServiceName && *compData->ServiceName) {
  215. if (!lstrcmpi (compData->ServiceName, handledData->Service)) {
  216. remove = TRUE;
  217. }
  218. }
  219. if (handledData->Type == HANDLED_FILE && compData->FileName && *compData->FileName) {
  220. if (!lstrcmpi (compData->FileName, handledData->File)) {
  221. remove = TRUE;
  222. }
  223. }
  224. //
  225. // Migration dll has handled something. Remove it from the compatibility list.
  226. //
  227. if (remove) {
  228. RemoveEntryList (&compData->ListEntry);
  229. }
  230. }
  231. }
  232. return TRUE;
  233. }
  234. BOOL
  235. CallMigDllEntryPoints (
  236. PMIGDLLENUM Enum
  237. )
  238. {
  239. MIGRATIONDLL dll;
  240. BOOL b = FALSE;
  241. if (!MigDllOpen (&dll, Enum->Properties->DllPath, GATHERMODE, FALSE, SOURCEOS_WINNT)) {
  242. return FALSE;
  243. }
  244. __try {
  245. if (!MigDllInitializeSrc (
  246. &dll,
  247. Enum->Properties->WorkingDirectory,
  248. NativeSourcePaths[0],
  249. Enum->Properties->SourceMedia,
  250. NULL,
  251. 0
  252. )) {
  253. __leave;
  254. }
  255. if (!MigDllGatherSystemSettings (
  256. &dll,
  257. g_MigDllAnswerFilePath,
  258. NULL,
  259. 0
  260. )) {
  261. __leave;
  262. }
  263. b = TRUE;
  264. }
  265. __finally {
  266. MigDllClose (&dll);
  267. }
  268. return b;
  269. }
  270. BOOL
  271. ParseMigrateInf (
  272. PCWSTR MigInfPath
  273. )
  274. {
  275. PVOID migInf = NULL;
  276. LONG lineCount;
  277. LONG i;
  278. PCTSTR type;
  279. PHANDLED_DATA data;
  280. PCTSTR regKey;
  281. PCTSTR regValue;
  282. PCTSTR file;
  283. PCTSTR service;
  284. if (LoadInfFile (MigInfPath, FALSE, &migInf) != ERROR_SUCCESS) {
  285. return FALSE;
  286. }
  287. __try {
  288. //
  289. // Add any compatibility items to the list.
  290. //
  291. if( !CompatibilityData.Flink ) {
  292. InitializeListHead( &CompatibilityData );
  293. }
  294. GlobalCompFlags = COMPFLAG_STOPINSTALL;
  295. CompatibilityCount += ProcessCompatibilitySection (migInf, TEXT("ServicesToStopInstallation") );
  296. if (CompatibilityCount) {
  297. IncompatibilityStopsInstallation = TRUE;
  298. }
  299. GlobalCompFlags = 0;
  300. CompatibilityCount += ProcessCompatibilitySection (migInf, TEXT("ServicesToDisable") );
  301. //
  302. // Add Handled compatibility items to the list.
  303. //
  304. lineCount = InfGetSectionLineCount (migInf, TEXT("Handled"));
  305. if (lineCount && lineCount != -1) {
  306. for (i=0; i < lineCount; i++) {
  307. type = InfGetFieldByIndex (migInf, TEXT("Handled"), i, 0);
  308. if (!type) {
  309. continue;
  310. }
  311. if (!lstrcmpi (type, TEXT("Registry"))) {
  312. regKey = InfGetFieldByIndex (migInf, TEXT("Handled"), i, 1);
  313. regValue = InfGetFieldByIndex (migInf, TEXT("Handled"), i, 2);
  314. if (regKey && *regKey) {
  315. data = (PHANDLED_DATA) MALLOC (sizeof(HANDLED_DATA));
  316. if (data == NULL) {
  317. return FALSE;
  318. }
  319. ZeroMemory (data, sizeof (HANDLED_DATA));
  320. data->Type = HANDLED_REGISTRY;
  321. data->RegKey = regKey;
  322. data->RegValue = regValue;
  323. InsertTailList (&g_HandledData, &data->ListEntry);
  324. }
  325. }
  326. else if (!lstrcmpi (type, TEXT("File"))) {
  327. file = InfGetFieldByIndex (migInf, TEXT("Handled"), i, 1);
  328. if (file && *file) {
  329. data = (PHANDLED_DATA) MALLOC (sizeof(HANDLED_DATA));
  330. if (data == NULL) {
  331. return FALSE;
  332. }
  333. ZeroMemory (data, sizeof (HANDLED_DATA));
  334. data->Type = HANDLED_FILE;
  335. data->File = file;
  336. InsertTailList (&g_HandledData, &data->ListEntry);
  337. }
  338. }
  339. else if (!lstrcmpi (type, TEXT("Service"))) {
  340. service = InfGetFieldByIndex (migInf, TEXT("Handled"), i, 1);
  341. if (service && *service) {
  342. data = (PHANDLED_DATA) MALLOC (sizeof(HANDLED_DATA));
  343. if (data == NULL) {
  344. return FALSE;
  345. }
  346. ZeroMemory (data, sizeof (HANDLED_DATA));
  347. data->Type = HANDLED_SERVICE;
  348. data->Service = service;
  349. InsertTailList (&g_HandledData, &data->ListEntry);
  350. }
  351. }
  352. }
  353. }
  354. }
  355. __finally {
  356. UnloadInfFile (migInf);
  357. }
  358. return TRUE;
  359. }
  360. VOID
  361. SearchDirForMigDlls (
  362. PCTSTR SearchDir,
  363. PCTSTR BaseDir,
  364. DLLLIST List
  365. )
  366. {
  367. HANDLE findHandle;
  368. WIN32_FIND_DATA findData;
  369. MIGRATIONDLL dll;
  370. WCHAR path[MAX_PATH];
  371. PWSTR p;
  372. WCHAR searchPath[MAX_PATH];
  373. PMIGRATIONINFO migInfo;
  374. PMIGDLLPROPERTIES dllProps = NULL;
  375. WCHAR workingDir[MAX_PATH];
  376. if (FAILED(StringCchCopy(searchPath, ARRAYSIZE(searchPath), SearchDir)))
  377. {
  378. return;
  379. }
  380. if (!ConcatenatePaths (searchPath, TEXT("*"), MAX_PATH))
  381. {
  382. return;
  383. }
  384. findHandle = FindFirstFile (searchPath, &findData);
  385. if (findHandle != INVALID_HANDLE_VALUE) {
  386. if (SUCCEEDED(StringCchCopy(path, ARRAYSIZE(path), SearchDir))) {
  387. //
  388. //StringCchCopy return S_OK only when dest string null terminated
  389. //
  390. p = _tcschr (path, 0);
  391. MYASSERT(p);
  392. do {
  393. if (!lstrcmpi (findData.cFileName, TEXT("migrate.dll"))) {
  394. *p = 0;
  395. if (!ConcatenatePaths (path, findData.cFileName, MAX_PATH)) {
  396. continue;
  397. }
  398. if (!MigDllOpen (&dll, path, GATHERMODE, FALSE, SOURCEOS_WINNT)) {
  399. continue;
  400. }
  401. if (!MigDllQueryMigrationInfo (&dll, TEXT("c:\\"), &migInfo)) {
  402. MigDllClose (&dll);
  403. continue;
  404. }
  405. if (migInfo->SourceOs == OS_WINDOWS9X || migInfo->TargetOs != OS_WINDOWSWHISTLER) {
  406. continue;
  407. }
  408. //
  409. // Do we already have a version of this migration dll?
  410. //
  411. dllProps = MigDllFindDllInList (List, migInfo->StaticProductIdentifier);
  412. if (dllProps && dllProps->Info.DllVersion >= migInfo->DllVersion) {
  413. MigDllClose (&dll);
  414. continue;
  415. }
  416. else if (dllProps) {
  417. MigDllRemoveDllFromList (List, migInfo->StaticProductIdentifier);
  418. }
  419. //
  420. // Move dll locally.
  421. //
  422. StringCchPrintf(workingDir, ARRAYSIZE(workingDir), TEXT("%s\\mig%u"), BaseDir, g_MigDllIndex);
  423. g_MigDllIndex++;
  424. MigDllMoveDllLocally (&dll, workingDir);
  425. //
  426. // Add the dll to the list.
  427. //
  428. MigDllAddDllToList (List, &dll);
  429. MigDllClose (&dll);
  430. }
  431. else if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && *findData.cFileName != TEXT('.')) {
  432. *p = 0;
  433. //Don't want to infinitely recurse
  434. if (ConcatenatePaths (path, findData.cFileName, MAX_PATH))
  435. {
  436. SearchDirForMigDlls (path, BaseDir, List);
  437. }
  438. }
  439. } while (FindNextFile (findHandle, &findData));
  440. }
  441. FindClose (findHandle);
  442. }
  443. }
  444. #endif // UNICODE
  445. #if defined(UNICODE) && defined(_X86_)
  446. BOOL
  447. LoadAndRunMigrationDlls (
  448. HWND hDlg
  449. )
  450. {
  451. // HKEY regKey = NULL;
  452. // DWORD index;
  453. // DWORD nameSize;
  454. // DWORD valueSize;
  455. // DWORD type;
  456. // TCHAR valueName[MAX_PATH];
  457. // TCHAR value[MAX_PATH];
  458. // TCHAR workingDir[MAX_PATH];
  459. // LONG rc;
  460. TCHAR baseDir[MAX_PATH];
  461. PTSTR p;
  462. DLLLIST list = NULL;
  463. MIGRATIONDLL dll;
  464. PMIGDLLPROPERTIES dllProps = NULL;
  465. MIGDLLENUM e;
  466. PMIGRATIONINFO migInfo;
  467. TCHAR migInfPath[MAX_PATH];
  468. HANDLE migInf;
  469. TCHAR searchDir[MAX_PATH];
  470. TCHAR tempDir[MAX_PATH];
  471. *g_MigDllAnswerFilePath = 0;
  472. //
  473. // NT Upgrades only.
  474. //
  475. if (!ISNT() || !Upgrade) {
  476. return TRUE;
  477. }
  478. /*NTBUG9:394164
  479. //
  480. // Win2k > Upgrades only.
  481. //
  482. if (BuildNumber <= NT40) {
  483. return TRUE;
  484. }
  485. */
  486. __try {
  487. if (!MigDllInit ()) {
  488. return TRUE;
  489. }
  490. list = MigDllCreateList ();
  491. if (!list) {
  492. return TRUE;
  493. }
  494. InitializeListHead (&g_HandledData);
  495. MyGetWindowsDirectory (baseDir, MAX_PATH);
  496. ConcatenatePaths (baseDir, TEXT("Setup"), MAX_PATH);
  497. if (!CreateDirectoryW (baseDir, NULL) &&
  498. GetLastError() != ERROR_ALREADY_EXISTS){
  499. return FALSE;
  500. }
  501. //
  502. // ISSUE: we never delete this temp directory!
  503. //
  504. lstrcpy (g_MigDllAnswerFilePath, baseDir);
  505. lstrcpy (tempDir, baseDir);
  506. ConcatenatePaths (g_MigDllAnswerFilePath, TEXT("migdll.txt"), MAX_PATH);
  507. if(ActualParamFile[0]){
  508. CopyFile(ActualParamFile, g_MigDllAnswerFilePath, FALSE);
  509. }
  510. /* //
  511. // Scan registry for migration dlls and load them.
  512. //
  513. if (RegOpenKeyEx (
  514. HKEY_LOCAL_MACHINE,
  515. S_REGKEY_MIGRATION_DLLS_WINNT,
  516. 0,
  517. KEY_READ | KEY_WRITE,
  518. &regKey
  519. ) == ERROR_SUCCESS) {
  520. //
  521. // Enumerate Values.
  522. //
  523. index = 0;
  524. do {
  525. nameSize = MAX_PATH;
  526. valueSize = MAX_PATH * sizeof (TCHAR);
  527. rc = RegEnumValue (
  528. regKey,
  529. index,
  530. valueName,
  531. &nameSize,
  532. NULL,
  533. &type,
  534. (PBYTE) value,
  535. &valueSize
  536. );
  537. index++;
  538. if (rc == ERROR_MORE_DATA) {
  539. continue;
  540. }
  541. if (rc == ERROR_NO_MORE_ITEMS) {
  542. break;
  543. }
  544. if (rc != ERROR_SUCCESS) {
  545. return TRUE;
  546. }
  547. if (!MigDllOpen (&dll, value, GATHERMODE, FALSE, SOURCEOS_WINNT)) {
  548. continue;
  549. }
  550. if (!MigDllQueryMigrationInfo (&dll, tempDir, &migInfo)) {
  551. MigDllClose (&dll);
  552. continue;
  553. }
  554. if (migInfo->SourceOs == OS_WINDOWS9X || migInfo->TargetOs != OS_WINDOWSWHISTLER) {
  555. continue;
  556. }
  557. //
  558. // Do we already have a version of this migration dll?
  559. //
  560. dllProps = MigDllFindDllInList (list, migInfo->StaticProductIdentifier);
  561. if (dllProps && dllProps->Info.DllVersion >= migInfo->DllVersion) {
  562. MigDllClose (&dll);
  563. continue;
  564. }
  565. else {
  566. MigDllRemoveDllFromList (list, migInfo->StaticProductIdentifier);
  567. }
  568. //
  569. // Move dll locally.
  570. //
  571. wsprintf (workingDir, TEXT("%s\\mig%u"), baseDir, g_MigDllIndex);
  572. g_MigDllIndex++;
  573. MigDllMoveDllLocally (&dll, workingDir);
  574. //
  575. // Add the dll to the list.
  576. //
  577. MigDllAddDllToList (list, &dll);
  578. MigDllClose (&dll);
  579. } while (1);
  580. }*/
  581. //
  582. // Now, look for dlls shipped with the source.
  583. //
  584. if (!MyGetModuleFileName (NULL, searchDir, ARRAYSIZE(searchDir))) {
  585. __leave;
  586. }
  587. p = _tcsrchr (searchDir, TEXT('\\'));
  588. if (p) {
  589. p++;
  590. StringCchCopy (p, searchDir + ARRAYSIZE(searchDir) - p, TEXT("WINNTMIG"));
  591. }
  592. SearchDirForMigDlls (searchDir, baseDir, list);
  593. //
  594. // All dlls are now in the list. Lets run them.
  595. //
  596. ConcatenatePaths (baseDir, TEXT("dlls.inf"), MAX_PATH);
  597. if (MigDllEnumFirst (&e, list)) {
  598. WritePrivateProfileString (
  599. TEXT("Version"),
  600. TEXT("Signature"),
  601. TEXT("\"$Windows NT$\""),
  602. baseDir
  603. );
  604. do {
  605. StringCchPrintf (migInfPath, ARRAYSIZE(migInfPath), TEXT("%s\\migrate.inf"), e.Properties->WorkingDirectory);
  606. migInf = CreateFile (
  607. migInfPath,
  608. GENERIC_READ | GENERIC_WRITE,
  609. 0,
  610. NULL,
  611. CREATE_ALWAYS,
  612. FILE_ATTRIBUTE_NORMAL,
  613. NULL
  614. );
  615. if (migInf == INVALID_HANDLE_VALUE) {
  616. continue;
  617. }
  618. CloseHandle (migInf);
  619. WritePrivateProfileString (
  620. TEXT("Version"),
  621. TEXT("Signature"),
  622. TEXT("\"$Windows NT$\""),
  623. migInfPath
  624. );
  625. if (!CallMigDllEntryPoints (&e)) {
  626. MigDllRemoveDllInEnumFromList (list, &e);
  627. }
  628. else {
  629. ParseMigrateInf (migInfPath);
  630. WritePrivateProfileString (
  631. TEXT("DllsToLoad"),
  632. e.Properties->Info.StaticProductIdentifier,
  633. e.Properties->DllPath,
  634. baseDir
  635. );
  636. }
  637. } while (MigDllEnumNext (&e));
  638. WritePrivateProfileString (NULL, NULL, NULL, baseDir);
  639. //
  640. // Get rid of compatibility messages handled by migration dlls.
  641. //
  642. ResolveHandledIncompatibilities ();
  643. }
  644. }
  645. __finally {
  646. /*
  647. if (regKey) {
  648. RegCloseKey (regKey);
  649. }
  650. */
  651. if (list) {
  652. MigDllFreeList (list);
  653. }
  654. }
  655. return TRUE;
  656. }
  657. #endif
  658. VOID
  659. CleanUpOldLocalSources(
  660. IN HWND hdlg
  661. )
  662. /*++
  663. Routine Description:
  664. Locate and delete old local source trees. All local fixed drives
  665. are scanned for \$win_nt$.~ls, and if present, delnoded.
  666. On amd64/x86, we also check the system partition for \$win_nt$.~bt
  667. and give it the same treatment.
  668. Arguments:
  669. Return Value:
  670. --*/
  671. {
  672. TCHAR Drive;
  673. TCHAR Text[250];
  674. TCHAR Filename[128];
  675. LoadString(hInst,IDS_INSPECTING,Text,sizeof(Text)/sizeof(TCHAR));
  676. SendMessage(hdlg,WMX_SETPROGRESSTEXT,0,(LPARAM)Text);
  677. for(Drive=TEXT('A'); Drive<=TEXT('Z'); Drive++) {
  678. if(MyGetDriveType(Drive) != DRIVE_FIXED) {
  679. continue;
  680. }
  681. Filename[0] = Drive;
  682. Filename[1] = TEXT(':');
  683. Filename[2] = 0;
  684. ConcatenatePaths(Filename,LOCAL_SOURCE_DIR,sizeof(Filename)/sizeof(TCHAR));
  685. if(FileExists(Filename, NULL)) {
  686. LoadString(hInst,IDS_REMOVING_OLD_TEMPFILES,Text,sizeof(Text)/sizeof(TCHAR));
  687. SendMessage(hdlg,WMX_SETPROGRESSTEXT,0,(LPARAM)Text);
  688. MyDelnode(Filename);
  689. LoadString(hInst,IDS_INSPECTING,Text,sizeof(Text)/sizeof(TCHAR));
  690. SendMessage(hdlg,WMX_SETPROGRESSTEXT,0,(LPARAM)Text);
  691. }
  692. }
  693. if (!IsArc()) {
  694. #if defined(_AMD64_) || defined(_X86_)
  695. MYASSERT (SystemPartitionDriveLetter);
  696. Filename[0] = SystemPartitionDriveLetter;
  697. Filename[1] = TEXT(':');
  698. Filename[2] = TEXT('\\');
  699. StringCchCopy(Filename+3, ARRAYSIZE(Filename) - 3, LOCAL_BOOT_DIR);
  700. LoadString(hInst,IDS_REMOVING_OLD_TEMPFILES,Text,sizeof(Text)/sizeof(TCHAR));
  701. SendMessage(hdlg,WMX_SETPROGRESSTEXT,0,(LPARAM)Text);
  702. MyDelnode(Filename);
  703. //
  704. // Clean up backup directory, if it exists.
  705. //
  706. if(IsNEC98() && Floppyless) {
  707. Filename[0] = SystemPartitionDriveLetter;
  708. Filename[1] = TEXT(':');
  709. Filename[2] = TEXT('\\');
  710. StringCchCopy(Filename+3, ARRAYSIZE(Filename) - 3, LOCAL_BACKUP_DIR);
  711. MyDelnode(Filename);
  712. }
  713. #endif // defined(_AMD64_) || defined(_X86_)
  714. } // if (!IsArc())
  715. }
  716. BOOL
  717. InspectSources(
  718. HWND ParentWnd
  719. )
  720. /*++
  721. Routine Description:
  722. Check all sources given to ensure that they contain a valid
  723. windows NT distribution. We do this simply by looking for
  724. DOSNET.INF on each source.
  725. Arguments:
  726. ParentWnd - Specifies the handle of the parent window for any
  727. error messages.
  728. Return Value:
  729. None.
  730. --*/
  731. {
  732. UINT i,j;
  733. TCHAR Filename[MAX_PATH];
  734. TCHAR Text[512];
  735. UINT OriginalCount;
  736. HCURSOR OldCursor;
  737. BOOL b = TRUE;
  738. OldCursor = SetCursor (LoadCursor (NULL, IDC_WAIT));
  739. OriginalCount = SourceCount;
  740. //
  741. // if we have a good alternate path then there
  742. // is no need to verify the source paths
  743. //
  744. if (AlternateSourcePath[0]) {
  745. lstrcpy(Filename,AlternateSourcePath);
  746. ConcatenatePaths(Filename,InfName,MAX_PATH);
  747. if(FileExists (Filename, NULL)) {
  748. SetCursor (OldCursor);
  749. return TRUE;
  750. }
  751. }
  752. //
  753. // verify each path
  754. //
  755. for (i=0; i<SourceCount; ) {
  756. lstrcpy(Filename,NativeSourcePaths[i]);
  757. ConcatenatePaths(Filename,InfName,MAX_PATH);
  758. if(!FileExists (Filename, NULL)) {
  759. //
  760. // Source doesn't exist or isn't valid.
  761. // Adjust the list.
  762. //
  763. for(j=i+1; j<SourceCount; j++) {
  764. lstrcpy(NativeSourcePaths[j-1],NativeSourcePaths[j]);
  765. lstrcpy(SourcePaths[j-1],SourcePaths[j]);
  766. }
  767. SourceCount--;
  768. } else {
  769. i++;
  770. }
  771. }
  772. if (!SourceCount) {
  773. //
  774. // No sources are valid.
  775. //
  776. MessageBoxFromMessage(
  777. ParentWnd,
  778. (OriginalCount == 1) ? MSG_INVALID_SOURCE : MSG_INVALID_SOURCES,
  779. FALSE,
  780. AppTitleStringId,
  781. MB_OK | MB_ICONWARNING | MB_TASKMODAL,
  782. NativeSourcePaths[0]
  783. );
  784. //
  785. // Set it to look like one source that is the empty string,
  786. // so logic elsewhere will work correctly without special casing.
  787. //
  788. SourceCount = 1;
  789. NativeSourcePaths[0][0] = 0;
  790. SourcePaths[0][0] = 0;
  791. b = FALSE;
  792. }
  793. SetCursor (OldCursor);
  794. return b;
  795. }
  796. BOOL
  797. LoadInfs(
  798. IN HWND hdlg
  799. )
  800. /*++
  801. Routine Description:
  802. Load dosnet.inf from source 0. If upgrading and we're running
  803. on NT then also load txtsetup.sif. If running on NT, load ntcompat.inf
  804. Arguments:
  805. hdlg - supplies handle of dialog to which progress messages
  806. should be directed.
  807. Return Value:
  808. Boolean value indicating outcome. If FALSE then the user
  809. will have been informed.
  810. --*/
  811. {
  812. BOOL b;
  813. LPCTSTR p;
  814. TCHAR szPath[MAX_PATH];
  815. if (!MainInf) {
  816. b = LoadInfWorker(hdlg,InfName,&MainInf, TRUE);
  817. if(!b) {
  818. MessageBoxFromMessage(
  819. NULL,
  820. MSG_INVALID_INF_FILE,
  821. FALSE,
  822. AppTitleStringId,
  823. MB_OK | MB_ICONINFORMATION | MB_TASKMODAL,
  824. InfName
  825. );
  826. DebugLog( Winnt32LogError, TEXT("ERROR: Could not load dosnet.inf!"), 0);
  827. goto c0;
  828. }
  829. } else {
  830. b = TRUE;
  831. }
  832. if(p = InfGetFieldByKey(MainInf,TEXT("Miscellaneous"),TEXT("ProductType"),0)) {
  833. ProductFlavor = _tcstoul(p,NULL,10);
  834. Server = (ProductFlavor != PROFESSIONAL_PRODUCTTYPE && ProductFlavor != PERSONAL_PRODUCTTYPE);
  835. UpgradeProductType = Server ? NT_SERVER : NT_WORKSTATION;
  836. if( CheckUpgradeOnly ) {
  837. AppTitleStringId = IDS_APPTITLE_CHECKUPGRADE;
  838. } else if( ProductFlavor == PROFESSIONAL_PRODUCTTYPE ) {
  839. AppTitleStringId = IDS_APPTITLE_WKS;
  840. } else if( ProductFlavor == SERVER_PRODUCTTYPE ) {
  841. AppTitleStringId = IDS_APPTITLE_SRV;
  842. } else if( ProductFlavor == ADVANCEDSERVER_PRODUCTTYPE ) {
  843. AppTitleStringId = IDS_APPTITLE_ASRV;
  844. } else if( ProductFlavor == DATACENTER_PRODUCTTYPE ) {
  845. AppTitleStringId = IDS_APPTITLE_DAT;
  846. } else if( ProductFlavor == BLADESERVER_PRODUCTTYPE ) {
  847. AppTitleStringId = IDS_APPTITLE_BLADE;
  848. } else if( ProductFlavor == SMALLBUSINESS_PRODUCTTYPE )
  849. AppTitleStringId = IDS_APPTITLE_SBS;
  850. // AppTitleStringId = Server ? IDS_APPTITLE_SRV : IDS_APPTITLE_WKS;
  851. FixUpWizardTitle(GetParent(hdlg));
  852. PropSheet_SetTitle(GetParent(hdlg),0,UIntToPtr( AppTitleStringId ));
  853. }
  854. if((Upgrade || BuildCmdcons) && ISNT()) {
  855. //
  856. // If upgrading NT, pull in txtsetup.sif.
  857. //
  858. b = LoadInfWorker(hdlg,TEXTMODE_INF,&TxtsetupSif, FALSE);
  859. if(!b) {
  860. MessageBoxFromMessage(
  861. NULL,
  862. MSG_INVALID_INF_FILE,
  863. FALSE,
  864. AppTitleStringId,
  865. MB_OK | MB_ICONINFORMATION | MB_TASKMODAL,
  866. TEXTMODE_INF
  867. );
  868. TxtsetupSif = NULL;
  869. DebugLog( Winnt32LogError, TEXT("ERROR: Could not load txtsetup.sif!"), 0);
  870. goto c1;
  871. }
  872. }
  873. if( ISNT()) {
  874. b = FindPathToWinnt32File(NTCOMPAT_INF, szPath, MAX_PATH);
  875. if(!b) {
  876. NtcompatInf = NULL;
  877. DebugLog( Winnt32LogError, TEXT("ERROR: Could not find ntcompat.inf!"), 0);
  878. goto c2;
  879. }
  880. if(LoadInfFile( szPath,TRUE, &NtcompatInf) != NO_ERROR) {
  881. MessageBoxFromMessage(
  882. NULL,
  883. MSG_INVALID_INF_FILE,
  884. FALSE,
  885. AppTitleStringId,
  886. MB_OK | MB_ICONINFORMATION | MB_TASKMODAL,
  887. szPath
  888. );
  889. b = FALSE;
  890. NtcompatInf = NULL;
  891. DebugLog( Winnt32LogError, TEXT("ERROR: Could not load ntcompat.inf!"), 0);
  892. goto c2;
  893. }
  894. DebugLog (Winnt32LogInformation, TEXT("NTCOMPAT: Using %1"), 0, szPath);
  895. }
  896. return(b);
  897. c2:
  898. if( TxtsetupSif) {
  899. UnloadInfFile(TxtsetupSif);
  900. TxtsetupSif = NULL;
  901. }
  902. c1:
  903. UnloadInfFile(MainInf);
  904. MainInf = NULL;
  905. c0:
  906. return(b);
  907. }
  908. BOOL
  909. BuildCopyList(
  910. IN HWND hdlg
  911. )
  912. {
  913. TCHAR Text[256];
  914. LoadString(hInst,IDS_BUILDING_COPY_LIST,Text,sizeof(Text)/sizeof(TCHAR));
  915. SendMessage(hdlg,WMX_SETPROGRESSTEXT,0,(LPARAM)Text);
  916. SaveLanguageDirs();
  917. return(BuildCopyListWorker(hdlg));
  918. }
  919. BOOL
  920. FindLocalSourceAndCheckSpace(
  921. IN HWND hdlg,
  922. IN BOOL QuickTest,
  923. IN LONGLONG AdditionalPadding
  924. )
  925. {
  926. TCHAR Text[256];
  927. if (!QuickTest) {
  928. LoadString(hInst,IDS_CHECKING_SPACE,Text,sizeof(Text)/sizeof(TCHAR));
  929. SendMessage(hdlg,WMX_SETPROGRESSTEXT,0,(LPARAM)Text);
  930. }
  931. return FindLocalSourceAndCheckSpaceWorker(hdlg, QuickTest, AdditionalPadding);
  932. }
  933. BOOL
  934. EnoughMemory(
  935. IN HWND hdlg,
  936. IN BOOL QuickTest
  937. )
  938. {
  939. LPCTSTR p;
  940. MEMORYSTATUS MemoryStatus;
  941. DWORD RequiredMemory;
  942. SIZE_T RequiredMB, AvailableMB;
  943. TCHAR buffer[64];
  944. UpgRequiredMb = 0;
  945. UpgAvailableMb = 0;
  946. //
  947. // Load the minimum memory requirements from the inf
  948. //
  949. if(GetMainInfValue (TEXT("Miscellaneous"),TEXT("MinimumMemory"), 0, buffer, 64)) {
  950. RequiredMemory = _tcstoul(buffer,NULL,10);
  951. //
  952. // Got it. Now figure out how much we've got.
  953. //
  954. GlobalMemoryStatus( &MemoryStatus );
  955. //
  956. // Convert to MB, rounding up to nearest 4MB boundary...
  957. //
  958. RequiredMB = ((RequiredMemory + ((4*1024*1024)-1)) >> 22) << 2;
  959. AvailableMB = ((MemoryStatus.dwTotalPhys + ((4*1024*1024)-1)) >> 22) << 2;
  960. //
  961. // Allow for UMA machine which may reservce 8MB for video
  962. //
  963. if( AvailableMB < (RequiredMB-8) ) {
  964. if (!QuickTest) {
  965. UpgRequiredMb = (DWORD)RequiredMB;
  966. UpgAvailableMb = (DWORD)AvailableMB;
  967. //
  968. // Fail.
  969. //
  970. DebugLog( Winnt32LogInformation,
  971. NULL,
  972. MSG_NOT_ENOUGH_MEMORY,
  973. AvailableMB,
  974. RequiredMB );
  975. SendMessage(hdlg,WMX_ERRORMESSAGEUP,TRUE,0);
  976. MessageBoxFromMessage(
  977. hdlg,
  978. MSG_NOT_ENOUGH_MEMORY,
  979. FALSE,
  980. AppTitleStringId,
  981. MB_OK | MB_ICONWARNING,
  982. AvailableMB,
  983. RequiredMB );
  984. SendMessage(hdlg,WMX_ERRORMESSAGEUP,FALSE,0);
  985. }
  986. return( FALSE );
  987. } else {
  988. if (!QuickTest) {
  989. TCHAR Buffer[MAX_PATH];
  990. _stprintf( Buffer, TEXT("Detected %dMB of RAM.\n"), AvailableMB );
  991. DebugLog( Winnt32LogInformation,
  992. Buffer,
  993. 0 );
  994. }
  995. }
  996. }
  997. return( TRUE );
  998. }
  999. BOOL
  1000. LoadInfWorker(
  1001. IN HWND hdlg,
  1002. IN LPCTSTR FilenamePart,
  1003. OUT PVOID *InfHandle,
  1004. IN BOOL Winnt32File
  1005. )
  1006. {
  1007. DWORD d;
  1008. UINT u;
  1009. UINT Id;
  1010. TCHAR infPath[MAX_PATH];
  1011. TCHAR FormatString[128];
  1012. TCHAR Text[MAX_PATH+128];
  1013. BOOL b;
  1014. LoadString(hInst,IDS_LOADINGINF,Text,sizeof(Text)/sizeof(TCHAR));
  1015. SendMessage(hdlg,WMX_SETPROGRESSTEXT,0,(LPARAM)Text);
  1016. //
  1017. // use standard searching algorithm to get to the right INF
  1018. //
  1019. if (Winnt32File) {
  1020. b = FindPathToWinnt32File (FilenamePart, infPath, MAX_PATH);
  1021. } else {
  1022. b = FindPathToInstallationFile (FilenamePart, infPath, MAX_PATH);
  1023. }
  1024. if (b) {
  1025. d = LoadInfFile(infPath,TRUE,InfHandle);
  1026. if (d == NO_ERROR) {
  1027. return TRUE;
  1028. }
  1029. } else {
  1030. d = ERROR_FILE_NOT_FOUND;
  1031. }
  1032. switch(d) {
  1033. case NO_ERROR:
  1034. Id = 0;
  1035. break;
  1036. case ERROR_NOT_ENOUGH_MEMORY:
  1037. Id = MSG_OUT_OF_MEMORY;
  1038. break;
  1039. case ERROR_READ_FAULT:
  1040. //
  1041. // I/O error.
  1042. //
  1043. Id = MSG_CANT_LOAD_INF_IO;
  1044. break;
  1045. case ERROR_INVALID_DATA:
  1046. Id = MSG_CANT_LOAD_INF_SYNTAXERR;
  1047. break;
  1048. default:
  1049. Id = MSG_CANT_LOAD_INF_GENERIC;
  1050. break;
  1051. }
  1052. if(Id) {
  1053. SendMessage(hdlg,WMX_ERRORMESSAGEUP,TRUE,0);
  1054. MessageBoxFromMessage(
  1055. hdlg,
  1056. Id,
  1057. FALSE,
  1058. AppTitleStringId,
  1059. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  1060. infPath
  1061. );
  1062. SendMessage(hdlg,WMX_ERRORMESSAGEUP,FALSE,0);
  1063. return(FALSE);
  1064. }
  1065. return(TRUE);
  1066. }
  1067. BOOL
  1068. WriteFileToLog(
  1069. const PTCHAR pszFileMetaName,
  1070. const PTCHAR pszActualFileName
  1071. )
  1072. {
  1073. HANDLE hActualFile = INVALID_HANDLE_VALUE;
  1074. BOOL fResult = FALSE;
  1075. DWORD cbBootIniSize, cbReadBootIniSize;
  1076. PUCHAR pszBuffer = NULL;
  1077. PTCHAR pszActualBuffer = NULL;
  1078. //
  1079. // Open the boot.ini file, get its size, convert it to the proper
  1080. // string type internally, and then log it out.
  1081. //
  1082. hActualFile = CreateFile(
  1083. pszActualFileName,
  1084. GENERIC_READ,
  1085. FILE_SHARE_READ,
  1086. NULL,
  1087. OPEN_EXISTING,
  1088. 0,
  1089. NULL);
  1090. if ( hActualFile == INVALID_HANDLE_VALUE )
  1091. goto Exit;
  1092. cbBootIniSize = GetFileSize( hActualFile, NULL );
  1093. //
  1094. // Buffer we'll be reading the boot.ini into
  1095. //
  1096. if ((pszBuffer = MALLOC(cbBootIniSize)) == NULL) {
  1097. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1098. goto Exit;
  1099. }
  1100. if ( !ReadFile( hActualFile, pszBuffer, cbBootIniSize, &cbReadBootIniSize, NULL ) )
  1101. goto Exit;
  1102. //
  1103. // Ensure that we read as much as we really wanted.
  1104. //
  1105. if ( cbBootIniSize != cbReadBootIniSize ) {
  1106. DebugLog( Winnt32LogError,
  1107. TEXT("Error: %1 unable to be read entirely.\n"),
  1108. 0,
  1109. pszFileMetaName);
  1110. goto Exit;
  1111. }
  1112. #ifdef UNICODE
  1113. pszActualBuffer = MALLOC( (cbBootIniSize + 3) * sizeof(TCHAR) );
  1114. MultiByteToWideChar(
  1115. CP_ACP,
  1116. 0,
  1117. pszBuffer,
  1118. cbBootIniSize,
  1119. pszActualBuffer,
  1120. cbBootIniSize );
  1121. #else
  1122. pszActualBuffer = pszBuffer;
  1123. #endif
  1124. pszActualBuffer[cbBootIniSize] = 0;
  1125. //
  1126. // And write it out
  1127. //
  1128. DebugLog(
  1129. Winnt32LogInformation,
  1130. TEXT("%1 ----\n%2\n---- (from %3)\n"),
  1131. 0,
  1132. pszFileMetaName,
  1133. pszActualBuffer,
  1134. pszActualFileName);
  1135. fResult = TRUE;
  1136. SetLastError(ERROR_SUCCESS);
  1137. Exit:
  1138. if ( hActualFile != INVALID_HANDLE_VALUE )
  1139. {
  1140. CloseHandle( hActualFile );
  1141. hActualFile = INVALID_HANDLE_VALUE;
  1142. }
  1143. #ifdef UNICODE
  1144. if ( pszActualBuffer != NULL )
  1145. #else
  1146. if ( ( pszActualBuffer != pszBuffer ) && ( pszActualBuffer != NULL ) )
  1147. #endif
  1148. {
  1149. FREE(pszActualBuffer);
  1150. pszActualBuffer = NULL;
  1151. }
  1152. if ( pszBuffer != NULL ) {
  1153. FREE(pszBuffer);
  1154. pszBuffer = NULL;
  1155. }
  1156. return fResult;
  1157. }
  1158. BOOL
  1159. InspectFilesystems(
  1160. IN HWND hdlg
  1161. )
  1162. {
  1163. TCHAR DriveRoot[4];
  1164. BOOL b;
  1165. TCHAR VolumeName[MAX_PATH];
  1166. DWORD SerialNumber;
  1167. DWORD MaxComponent;
  1168. BOOL Bogus[26];
  1169. TCHAR Filesystem[100];
  1170. TCHAR Drive;
  1171. DWORD Flags;
  1172. int i;
  1173. DriveRoot[1] = TEXT(':');
  1174. DriveRoot[2] = TEXT('\\');
  1175. DriveRoot[3] = 0;
  1176. ZeroMemory(Bogus,sizeof(Bogus));
  1177. for(Drive=TEXT('A'); Drive<=TEXT('Z'); Drive++) {
  1178. if(MyGetDriveType(Drive) != DRIVE_FIXED) {
  1179. continue;
  1180. }
  1181. DriveRoot[0] = Drive;
  1182. b = GetVolumeInformation(
  1183. DriveRoot,
  1184. VolumeName,MAX_PATH,
  1185. &SerialNumber,
  1186. &MaxComponent,
  1187. &Flags,
  1188. Filesystem,
  1189. sizeof(Filesystem)/sizeof(TCHAR)
  1190. );
  1191. if(b) {
  1192. //
  1193. // On NT, we want to warn about HPFS.
  1194. // On Win9x, we want to warn about doublespace/drivespace.
  1195. //
  1196. if(ISNT()) {
  1197. if(!lstrcmpi(Filesystem,TEXT("HPFS"))) {
  1198. Bogus[Drive-TEXT('A')] = TRUE;
  1199. }
  1200. } else {
  1201. if(Flags & FS_VOL_IS_COMPRESSED) {
  1202. Bogus[Drive-TEXT('A')] = TRUE;
  1203. }
  1204. }
  1205. }
  1206. }
  1207. #if defined(_AMD64_) || defined(_X86_)
  1208. if(ISNT()) {
  1209. TCHAR BootIniName[16];
  1210. DWORD dwAttributes;
  1211. //
  1212. // Disallow HPFS system partition. If someone figured out how
  1213. // to get an HPFS system partition on an ARC machine, more power
  1214. // to 'em.
  1215. //
  1216. MYASSERT (SystemPartitionDriveLetter);
  1217. if(SystemPartitionDriveLetter && Bogus[SystemPartitionDriveLetter-TEXT('A')]) {
  1218. MessageBoxFromMessage(
  1219. hdlg,
  1220. MSG_SYSPART_IS_HPFS,
  1221. FALSE,
  1222. AppTitleStringId,
  1223. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  1224. SystemPartitionDriveLetter
  1225. );
  1226. return(FALSE);
  1227. }
  1228. /*
  1229. If we're upgrading NT, then log the existing boot.ini to the
  1230. logfiles for this pass. However, if that failed, then there
  1231. was something wrong - a missing boot.ini during an upgrade
  1232. is really a bad thing that should be snipped in the bud before
  1233. we go much further and copy files down, change system state,
  1234. etc.
  1235. */
  1236. #ifdef PRERELEASE
  1237. if (Upgrade)
  1238. {
  1239. _stprintf(BootIniName, TEXT("%c:\\BOOT.INI"), SystemPartitionDriveLetter);
  1240. if ( !WriteFileToLog( TEXT("Boot configuration file while inspecting filesystems"), BootIniName ) )
  1241. {
  1242. MessageBoxFromMessage(
  1243. hdlg,
  1244. MSG_UPGRADE_INSPECTION_MISSING_BOOT_INI,
  1245. FALSE,
  1246. AppTitleStringId,
  1247. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  1248. BootIniName );
  1249. return FALSE;
  1250. }
  1251. }
  1252. #endif
  1253. }
  1254. #endif
  1255. //
  1256. // User cannot upgrade a system on an HPFS/DriveSpace drive
  1257. //
  1258. MyGetWindowsDirectory(VolumeName,MAX_PATH);
  1259. if(Upgrade && Bogus[VolumeName[0]-TEXT('A')]) {
  1260. MessageBoxFromMessage(
  1261. hdlg,
  1262. ISNT() ? MSG_SYSTEM_ON_HPFS : MSG_SYSTEM_ON_CVF,
  1263. FALSE,
  1264. AppTitleStringId,
  1265. MB_OK | MB_ICONERROR | MB_TASKMODAL
  1266. );
  1267. return(FALSE);
  1268. }
  1269. //
  1270. // General case, HPFS data partition/compressed drive.
  1271. //
  1272. for(b=FALSE,Drive=0; !b && (Drive<26); Drive++) {
  1273. if(Bogus[Drive]) {
  1274. b = TRUE;
  1275. }
  1276. }
  1277. if(b) {
  1278. i = MessageBoxFromMessage(
  1279. hdlg,
  1280. ISNT() ? MSG_HPFS_DRIVES_EXIST : MSG_CVFS_EXIST,
  1281. FALSE,
  1282. AppTitleStringId,
  1283. MB_YESNO | MB_ICONQUESTION | MB_TASKMODAL
  1284. );
  1285. if(i == IDNO) {
  1286. return(FALSE);
  1287. }
  1288. }
  1289. return(TRUE);
  1290. }