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.

3589 lines
84 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. migdll9x.c
  5. Abstract:
  6. Implements migration DLL interface for the Win9x side of the upgrade.
  7. Author:
  8. Jim Schmidt (jimschm) 13-Jan-1998
  9. Revision History:
  10. jimschm 23-Sep-1998 Updated for new IPC mechanism
  11. --*/
  12. #include "pch.h"
  13. #include "plugin.h"
  14. #include "migdllp.h"
  15. #include "dbattrib.h"
  16. #include <ntverp.h>
  17. // This file has mixed mbcs and tchar code; this was because
  18. // some code was ported from the original MikeCo implementation,
  19. // and it is now clear that this file will always be an ANSI compile.
  20. #ifdef UNICODE
  21. #error UNICODE cannot be defined
  22. #endif
  23. #define DBG_MIGDLLS "MigDLLs"
  24. //
  25. // Globals
  26. //
  27. PVOID g_DllTable;
  28. PVOID g_DllFileTable;
  29. POOLHANDLE g_MigDllPool;
  30. PSTR g_MessageBuf;
  31. PMIGRATION_DLL_PROPS g_HeadDll;
  32. CHAR g_MigDllAnswerFile[MAX_MBCHAR_PATH];
  33. CHAR g_MigrateInfTemplate[MAX_MBCHAR_PATH];
  34. GROWBUFFER g_SourceDirList = GROWBUF_INIT;
  35. UINT g_MigDllsAlive;
  36. HANDLE g_AbortDllEvent;
  37. BOOL g_ProgressBarExists;
  38. WINVERIFYTRUST WinVerifyTrustApi;
  39. HANDLE g_WinTrustDll;
  40. UINT g_TotalDllsToProcess;
  41. BOOL g_MediaDllsQueried;
  42. HASHTABLE g_ExcludedMigDlls = NULL;
  43. GROWLIST g_ExcludedMigDllsByInfo = GROWLIST_INIT;
  44. #define MAX_MESSAGE 8192
  45. #define S_HARDWARE_IN_WACKS "\\Hardware\\"
  46. #define S_HARDWARE_CHARS 10
  47. typedef struct {
  48. UINT MsgId;
  49. PCSTR Variable;
  50. PCSTR LocalizedName;
  51. } MSG_VARIABLE, *PMSG_VARIABLE;
  52. MSG_VARIABLE g_MsgVarTable[] = {
  53. { 0, "%OriginalOsName%", g_Win95Name },
  54. { MSG_SHORT_OS_NAME, "%ShortTargetOsName%", NULL },
  55. { MSG_NORMAL_OS_NAME, "%TargetOsName%", NULL },
  56. { MSG_FULL_OS_NAME, "%CompleteOsName%", NULL },
  57. { 0, NULL, NULL }
  58. };
  59. #define MESSAGE_VARIABLES ((sizeof (g_MsgVarTable) / sizeof (g_MsgVarTable[0])) - 1)
  60. PMAPSTRUCT g_MsgVariableMap;
  61. //
  62. // Implementation
  63. //
  64. BOOL
  65. WINAPI
  66. MigDll9x_Entry (
  67. IN HINSTANCE DllInstance,
  68. IN DWORD Reason,
  69. IN PVOID Reserved
  70. )
  71. /*++
  72. Routine Description:
  73. This is a DllMain-like init funciton, called at process attach and detach.
  74. Arguments:
  75. DllInstance - (OS-supplied) instance handle for the DLL
  76. Reason - (OS-supplied) indicates attach or detatch from process or
  77. thread
  78. Reserved - unused
  79. Return Value:
  80. TRUE if initialization succeeded, or FALSE if it failed.
  81. --*/
  82. {
  83. TCHAR PathBuf[16384];
  84. TCHAR CurDir[MAX_TCHAR_PATH];
  85. PTSTR p;
  86. if (g_ToolMode) {
  87. return TRUE;
  88. }
  89. switch (Reason) {
  90. case DLL_PROCESS_ATTACH:
  91. if(!pSetupInitializeUtils()) {
  92. return FALSE;
  93. }
  94. g_DllTable = pSetupStringTableInitializeEx (sizeof (PMIGRATION_DLL_PROPS), 0);
  95. if (!g_DllTable) {
  96. return FALSE;
  97. }
  98. g_DllFileTable = pSetupStringTableInitializeEx (sizeof (PMIGRATION_DLL_PROPS), 0);
  99. if (!g_DllFileTable) {
  100. return FALSE;
  101. }
  102. g_MigDllPool = PoolMemInitNamedPool ("Migration DLLs - 95 side");
  103. if (!g_MigDllPool) {
  104. return FALSE;
  105. }
  106. g_MessageBuf = PoolMemGetMemory (g_MigDllPool, MAX_MESSAGE);
  107. if (!g_MessageBuf) {
  108. return FALSE;
  109. }
  110. g_HeadDll = NULL;
  111. g_WinTrustDll = LoadLibrary ("wintrust.dll");
  112. if (g_WinTrustDll) {
  113. (FARPROC) WinVerifyTrustApi = GetProcAddress (g_WinTrustDll, "WinVerifyTrust");
  114. }
  115. GetModuleFileName (g_hInst, CurDir, MAX_TCHAR_PATH);
  116. p = _tcsrchr (CurDir, TEXT('\\'));
  117. MYASSERT (p);
  118. if (p) {
  119. MYASSERT (StringIMatch (p + 1, TEXT("w95upg.dll")));
  120. *p = 0;
  121. }
  122. if (!GetEnvironmentVariable (
  123. TEXT("Path"),
  124. PathBuf,
  125. sizeof (PathBuf) / sizeof (PathBuf[0])
  126. )) {
  127. StackStringCopy (PathBuf, CurDir);
  128. } else {
  129. p = (PTSTR) ((PBYTE) PathBuf + sizeof (PathBuf) - MAX_TCHAR_PATH);
  130. *p = 0;
  131. p = _tcsrchr (PathBuf, TEXT(';'));
  132. if (!p || p[1]) {
  133. StringCat (PathBuf, TEXT(";"));
  134. }
  135. StringCat (PathBuf, CurDir);
  136. }
  137. SetEnvironmentVariable (TEXT("Path"), PathBuf);
  138. break;
  139. case DLL_PROCESS_DETACH:
  140. if (g_DllTable) {
  141. pSetupStringTableDestroy (g_DllTable);
  142. g_DllTable = NULL;
  143. }
  144. if (g_DllFileTable) {
  145. pSetupStringTableDestroy (g_DllFileTable);
  146. g_DllFileTable = NULL;
  147. }
  148. if (g_MigDllPool) {
  149. PoolMemDestroyPool (g_MigDllPool);
  150. g_MigDllPool = NULL;
  151. }
  152. if (g_WinTrustDll) {
  153. FreeLibrary (g_WinTrustDll);
  154. g_WinTrustDll = NULL;
  155. }
  156. DestroyStringMapping (g_MsgVariableMap);
  157. pSetupUninitializeUtils();
  158. break;
  159. }
  160. return TRUE;
  161. }
  162. BOOL
  163. pTextToInt (
  164. IN PCTSTR Text,
  165. OUT PINT Number
  166. )
  167. {
  168. return _stscanf (Text, TEXT("%i"), Number) == 1;
  169. }
  170. BOOL
  171. BeginMigrationDllProcessing (
  172. VOID
  173. )
  174. /*++
  175. Routine Description:
  176. BeginMigrationDllProcessing initializes the global variables needed to
  177. implement the migration DLL spec. It is called during deferred init.
  178. Arguments:
  179. none
  180. Return Value:
  181. TRUE if init succeeded, or FALSE if an error occurred.
  182. --*/
  183. {
  184. HANDLE h;
  185. CHAR Buffer[4096];
  186. UINT i;
  187. PGROWBUFFER MsgAllocTable;
  188. INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
  189. PTSTR productId, versionStr;
  190. UINT version;
  191. #ifdef PRERELEASE
  192. if (g_ConfigOptions.DiffMode) {
  193. TakeSnapShot();
  194. }
  195. #endif
  196. if (InfFindFirstLine (g_Win95UpgInf, S_EXCLUDEDMIGRATIONDLLS, NULL, &is)) {
  197. g_ExcludedMigDlls = HtAllocWithData (sizeof (UINT));
  198. if (!g_ExcludedMigDlls) {
  199. return FALSE;
  200. }
  201. do {
  202. productId = InfGetStringField (&is, 1);
  203. versionStr = InfGetStringField (&is, 2);
  204. if (!productId || !*productId ||
  205. !versionStr || !(version = _ttol (versionStr))
  206. ) {
  207. DEBUGMSG ((DBG_ERROR, "Error in win95upg.inf section %s", S_EXCLUDEDMIGRATIONDLLS));
  208. continue;
  209. }
  210. HtAddStringAndData (g_ExcludedMigDlls, productId, &version);
  211. } while (InfFindNextLine (&is));
  212. InfCleanUpInfStruct (&is);
  213. }
  214. if (InfFindFirstLine (g_Win95UpgInf, S_EXCLUDEDMIGDLLSBYATTR, NULL, &is)) {
  215. do {
  216. PCTSTR Attributes;
  217. PMIGDB_ATTRIB migDbAttrib = NULL;
  218. Attributes = InfGetMultiSzField(&is, 1);
  219. if (!Attributes) {
  220. DEBUGMSG ((DBG_ERROR, "Error in win95upg.inf section %s line %u", S_EXCLUDEDMIGDLLSBYATTR, is.Context.Line));
  221. continue;
  222. }
  223. migDbAttrib = LoadAttribData(Attributes, g_MigDllPool);
  224. if(!migDbAttrib){
  225. MYASSERT(FALSE);
  226. continue;
  227. }
  228. GrowListAppend (&g_ExcludedMigDllsByInfo, (PBYTE)&migDbAttrib, sizeof(PMIGDB_ATTRIB));
  229. } while (InfFindNextLine (&is));
  230. InfCleanUpInfStruct (&is);
  231. }
  232. //
  233. // Fill in all the resource strings
  234. //
  235. g_MsgVariableMap = CreateStringMapping();
  236. MsgAllocTable = CreateAllocTable();
  237. MYASSERT (MsgAllocTable);
  238. for (i = 0 ; g_MsgVarTable[i].Variable ; i++) {
  239. if (g_MsgVarTable[i].MsgId) {
  240. MYASSERT (!g_MsgVarTable[i].LocalizedName);
  241. g_MsgVarTable[i].LocalizedName = GetStringResourceEx (
  242. MsgAllocTable,
  243. g_MsgVarTable[i].MsgId
  244. );
  245. MYASSERT (g_MsgVarTable[i].LocalizedName);
  246. if (g_MsgVarTable[i].LocalizedName) {
  247. AddStringMappingPair (
  248. g_MsgVariableMap,
  249. g_MsgVarTable[i].Variable,
  250. g_MsgVarTable[i].LocalizedName
  251. );
  252. }
  253. } else {
  254. AddStringMappingPair (
  255. g_MsgVariableMap,
  256. g_MsgVarTable[i].Variable,
  257. g_MsgVarTable[i].LocalizedName
  258. );
  259. }
  260. }
  261. DestroyAllocTable (MsgAllocTable);
  262. //
  263. // Global init
  264. //
  265. g_MigDllsAlive = 0;
  266. //
  267. // Build source dirs
  268. //
  269. for (i = 0 ; i < SOURCEDIRECTORYCOUNT(); i++) {
  270. MultiSzAppend (&g_SourceDirList, SOURCEDIRECTORY(i));
  271. }
  272. //
  273. // Generate a private copy of the answer file
  274. //
  275. wsprintf (g_MigDllAnswerFile, "%s\\unattend.tmp", g_TempDir);
  276. if (g_UnattendScriptFile && *g_UnattendScriptFile && **g_UnattendScriptFile) {
  277. if (!CopyFile (*g_UnattendScriptFile, g_MigDllAnswerFile, FALSE)) {
  278. LOG ((LOG_ERROR, "Can't copy %s to %s", *g_UnattendScriptFile, g_MigDllAnswerFile));
  279. return FALSE;
  280. }
  281. } else {
  282. h = CreateFile (
  283. g_MigDllAnswerFile,
  284. GENERIC_READ|GENERIC_WRITE,
  285. 0,
  286. NULL,
  287. CREATE_ALWAYS,
  288. FILE_ATTRIBUTE_NORMAL,
  289. NULL
  290. );
  291. if (h == INVALID_HANDLE_VALUE) {
  292. LOG ((LOG_ERROR, "Unable to create %s", g_MigDllAnswerFile));
  293. return FALSE;
  294. }
  295. WriteFileString (h, "[Version]\r\nSignature = $Windows NT$\r\n\r\n");
  296. CloseHandle (h);
  297. }
  298. //
  299. // Generate stub of migrate.inf
  300. //
  301. wsprintf (g_MigrateInfTemplate, "%s\\migrate.tmp", g_TempDir);
  302. h = CreateFile (
  303. g_MigrateInfTemplate,
  304. GENERIC_READ|GENERIC_WRITE,
  305. 0,
  306. NULL,
  307. CREATE_ALWAYS,
  308. FILE_ATTRIBUTE_NORMAL,
  309. NULL
  310. );
  311. if (h == INVALID_HANDLE_VALUE) {
  312. LOG ((LOG_ERROR, "Unable to create %s", g_MigrateInfTemplate));
  313. return FALSE;
  314. }
  315. //
  316. // Generate header of migrate.inf
  317. //
  318. MYASSERT (g_ProductFlavor);
  319. wsprintf (
  320. Buffer,
  321. "[Version]\r\n"
  322. "Signature = $Windows NT$\r\n"
  323. "SetupOS = %s\r\n"
  324. "SetupPlatform = %s\r\n"
  325. "SetupSKU = %s\r\n"
  326. "SetupBuild = %u\r\n"
  327. ,
  328. VER_PRODUCTNAME_STR,
  329. S_WORKSTATIONA,
  330. *g_ProductFlavor == PERSONAL_PRODUCTTYPE ? S_PERSONALA : S_PROFESSIONALA,
  331. VER_PRODUCTBUILD
  332. );
  333. WriteFileString (h, Buffer);
  334. CloseHandle (h);
  335. return TRUE;
  336. }
  337. BOOL
  338. pEndMigrationDllProcessing (
  339. VOID
  340. )
  341. /*++
  342. Routine Description:
  343. EndMigrationDllProcessing cleans up all the resources used to process
  344. migration DLLs. It is called before the incompatibility report is
  345. displayed, and after all DLLs have been processed.
  346. Arguments:
  347. none
  348. Return Value:
  349. TRUE if processing completed, or FALSE if an error occurred.
  350. --*/
  351. {
  352. MIGDLL_ENUM e;
  353. CHAR FullPath[MAX_MBCHAR_PATH];
  354. UINT Sequencer = 0;
  355. CHAR SeqStr[16];
  356. BOOL b = FALSE;
  357. PCTSTR group;
  358. INT i;
  359. PMIGDB_ATTRIB * ppMigDBattrib;
  360. __try {
  361. g_ProgressBarExists = TRUE;
  362. if (g_ExcludedMigDlls) {
  363. HtFree (g_ExcludedMigDlls);
  364. g_ExcludedMigDlls = NULL;
  365. }
  366. for(i = GrowListGetSize(&g_ExcludedMigDllsByInfo) - 1; i >= 0; i--){
  367. ppMigDBattrib = (PMIGDB_ATTRIB *)GrowListGetItem(&g_ExcludedMigDllsByInfo, i);
  368. MYASSERT(ppMigDBattrib);
  369. FreeAttribData(g_MigDllPool, *ppMigDBattrib);
  370. }
  371. FreeGrowList (&g_ExcludedMigDllsByInfo);
  372. //
  373. // Write list of DLLs to memdb
  374. //
  375. if (EnumFirstMigrationDll (&e)) {
  376. do {
  377. if (e.AllDllProps->WantsToRunOnNt) {
  378. wsprintf (FullPath, "%s\\migrate.dll", e.AllDllProps->WorkingDir);
  379. wsprintf (SeqStr, "%u", Sequencer);
  380. Sequencer++;
  381. MemDbSetValueEx (
  382. MEMDB_CATEGORY_MIGRATION_DLL,
  383. SeqStr,
  384. MEMDB_FIELD_DLL,
  385. FullPath,
  386. 0,
  387. NULL
  388. );
  389. MemDbSetValueEx (
  390. MEMDB_CATEGORY_MIGRATION_DLL,
  391. SeqStr,
  392. MEMDB_FIELD_WD,
  393. e.AllDllProps->WorkingDir,
  394. 0,
  395. NULL
  396. );
  397. MemDbSetValueEx (
  398. MEMDB_CATEGORY_MIGRATION_DLL,
  399. SeqStr,
  400. MEMDB_FIELD_DESC,
  401. e.AllDllProps->ProductId,
  402. 0,
  403. NULL
  404. );
  405. MemDbSetValueEx (
  406. MEMDB_CATEGORY_MIGRATION_DLL,
  407. SeqStr,
  408. MEMDB_FIELD_COMPANY_NAME,
  409. e.AllDllProps->VendorInfo->CompanyName,
  410. 0,
  411. NULL
  412. );
  413. if (*e.AllDllProps->VendorInfo->SupportNumber) {
  414. MemDbSetValueEx (
  415. MEMDB_CATEGORY_MIGRATION_DLL,
  416. SeqStr,
  417. MEMDB_FIELD_SUPPORT_PHONE,
  418. e.AllDllProps->VendorInfo->SupportNumber,
  419. 0,
  420. NULL
  421. );
  422. }
  423. if (*e.AllDllProps->VendorInfo->SupportUrl) {
  424. MemDbSetValueEx (
  425. MEMDB_CATEGORY_MIGRATION_DLL,
  426. SeqStr,
  427. MEMDB_FIELD_SUPPORT_URL,
  428. e.AllDllProps->VendorInfo->SupportUrl,
  429. 0,
  430. NULL
  431. );
  432. }
  433. if (*e.AllDllProps->VendorInfo->InstructionsToUser) {
  434. MemDbSetValueEx (
  435. MEMDB_CATEGORY_MIGRATION_DLL,
  436. SeqStr,
  437. MEMDB_FIELD_SUPPORT_INSTRUCTIONS,
  438. e.AllDllProps->VendorInfo->InstructionsToUser,
  439. 0,
  440. NULL
  441. );
  442. }
  443. if (g_ConfigOptions.ShowPacks) {
  444. //
  445. // Add a message in the incompatibility report for the pack.
  446. //
  447. group = BuildMessageGroup (
  448. MSG_INSTALL_NOTES_ROOT,
  449. MSG_RUNNING_MIGRATION_DLLS_SUBGROUP,
  450. e.AllDllProps->ProductId
  451. );
  452. if (group) {
  453. MsgMgr_ObjectMsg_Add (
  454. e.AllDllProps->ProductId,
  455. group,
  456. S_EMPTY
  457. );
  458. FreeText (group);
  459. }
  460. }
  461. }
  462. } while (EnumNextMigrationDll (&e));
  463. }
  464. if (!MergeMigrationDllInf (g_MigDllAnswerFile)) {
  465. __leave;
  466. }
  467. b = TRUE;
  468. }
  469. __finally {
  470. DeleteFile (g_MigDllAnswerFile);
  471. DeleteFile (g_MigrateInfTemplate);
  472. FreeGrowBuffer (&g_SourceDirList);
  473. g_ProgressBarExists = FALSE;
  474. }
  475. #ifdef PRERELEASE
  476. if (g_ConfigOptions.DiffMode) {
  477. CHAR szMigdllDifPath[] = "c:\\migdll.dif";
  478. if (ISPC98()) {
  479. szMigdllDifPath[0] = (CHAR)g_SystemDir[0];
  480. }
  481. GenerateDiffOutputA (szMigdllDifPath, NULL, FALSE);
  482. }
  483. #endif
  484. return b;
  485. }
  486. DWORD
  487. EndMigrationDllProcessing (
  488. IN DWORD Request
  489. )
  490. {
  491. switch (Request) {
  492. case REQUEST_QUERYTICKS:
  493. return TICKS_END_MIGRATION_DLL_PROCESSING;
  494. case REQUEST_RUN:
  495. if (!pEndMigrationDllProcessing ()) {
  496. return GetLastError ();
  497. }
  498. else {
  499. return ERROR_SUCCESS;
  500. }
  501. default:
  502. DEBUGMSG ((DBG_ERROR, "Bad parameter in EndMigrationDllProcessing"));
  503. }
  504. return 0;
  505. }
  506. BOOL
  507. pIsPathLegal (
  508. PCTSTR Path
  509. )
  510. {
  511. UINT Chars;
  512. CHARTYPE ch;
  513. static UINT TempDirLen = 0;
  514. // loop optimization, relies on fact that we never change g_TempDir
  515. if (!TempDirLen) {
  516. TempDirLen = CharCount (g_TempDir);
  517. }
  518. //
  519. // Determine if path is a containment case of the setup temp dir
  520. //
  521. Chars = min (CharCount (Path), TempDirLen);
  522. if (StringIMatchCharCount (Path, g_TempDir, Chars)) {
  523. ch = _tcsnextc (CharCountToPointer (Path, Chars));
  524. if (!ch || ch == TEXT('\\')) {
  525. return FALSE;
  526. }
  527. }
  528. return TRUE;
  529. }
  530. UINT
  531. ScanPathForMigrationDlls (
  532. IN PCSTR PathSpec,
  533. IN HANDLE CancelEvent, OPTIONAL
  534. OUT PBOOL MatchFound OPTIONAL
  535. )
  536. /*++
  537. Routine Description:
  538. ScanPathForMigrationDlls searches the specified path, including all
  539. subdirectories, for migrate.dll. If found, the entry points are
  540. verified, and if all exist, QueryVersion is called. When Queryversion
  541. succeeds, the DLL is added to the list of DLLs and is moved to
  542. local storage.
  543. Arguments:
  544. PathSpec - Specifies the directory to search. Must be a complete
  545. path.
  546. CancelEvent - Specifies the handle of an event that causes migration DLL
  547. searching to be canceled.
  548. MatchFound - Receives TRUE if a migrate.dll was found and QueryVersion
  549. was called, or FALSE if no migrate.dll was found. This is
  550. used to distinguish between loaded DLLs and unneeded DLLs.
  551. Return Value:
  552. The number of migrate.dll modules successfully loaded.
  553. --*/
  554. {
  555. TREE_ENUMA e;
  556. UINT DllsFound = 0;
  557. DWORD rc = ERROR_SUCCESS;
  558. g_AbortDllEvent = CancelEvent;
  559. if (MatchFound) {
  560. *MatchFound = FALSE;
  561. }
  562. if (EnumFirstFileInTree (&e, PathSpec, "migrate.dll", FALSE)) {
  563. do {
  564. //
  565. // Check for user cancel
  566. //
  567. if (CancelEvent) {
  568. if (WaitForSingleObject (CancelEvent, 0) == WAIT_OBJECT_0) {
  569. rc = ERROR_CANCELLED;
  570. break;
  571. }
  572. }
  573. if (CANCELLED()) {
  574. rc = ERROR_CANCELLED;
  575. break;
  576. }
  577. if (e.Directory) {
  578. continue;
  579. }
  580. //
  581. // Don't allow scan of our temp dir!
  582. //
  583. if (!pIsPathLegal (e.FullPath)) {
  584. continue;
  585. }
  586. //
  587. // Found DLL -- see if it's real, then move it to local
  588. // storage.
  589. //
  590. DEBUGMSG ((DBG_MIGDLLS, "Found DLL: %hs", e.FullPath));
  591. if (pValidateAndMoveDll (e.FullPath, MatchFound)) {
  592. DllsFound++;
  593. if (g_ProgressBarExists) {
  594. TickProgressBar ();
  595. }
  596. } else {
  597. rc = GetLastError();
  598. if (rc != ERROR_SUCCESS) {
  599. break;
  600. }
  601. }
  602. } while (EnumNextFileInTree (&e));
  603. if (rc != ERROR_SUCCESS) {
  604. AbortEnumFileInTree (&e);
  605. }
  606. }
  607. g_AbortDllEvent = NULL;
  608. if (g_ProgressBarExists) {
  609. TickProgressBar ();
  610. }
  611. SetLastError (rc);
  612. return DllsFound;
  613. }
  614. BOOL
  615. pProcessAllLocalDlls (
  616. VOID
  617. )
  618. /*++
  619. Routine Description:
  620. ProcessAllLocalDlls processes all the DLLs that were moved to local
  621. storage. It enumerates each DLL, then calls ProcessDll. This
  622. function also allows the user to cancel Setup in the middle of
  623. processing.
  624. Arguments:
  625. none
  626. Return Value:
  627. Returns TRUE if all DLLs were processed, or FALSE if an error occurred.
  628. If FALSE is returned, call GetLastError to determine the reason for
  629. failure.
  630. --*/
  631. {
  632. MIGDLL_ENUM e;
  633. UINT DllsProcessed = 0;
  634. g_ProgressBarExists = TRUE;
  635. if (EnumFirstMigrationDll (&e)) {
  636. do {
  637. if (!ProgressBar_SetSubComponent (e.ProductId)) {
  638. SetLastError (ERROR_CANCELLED);
  639. return FALSE;
  640. }
  641. if (!ProcessDll (&e)) {
  642. e.AllDllProps->WantsToRunOnNt = FALSE;
  643. if (GetLastError() != ERROR_SUCCESS) {
  644. return FALSE;
  645. }
  646. }
  647. TickProgressBarDelta (TICKS_MIGDLL_DELTA);
  648. DllsProcessed++;
  649. } while (EnumNextMigrationDll (&e));
  650. }
  651. // Adjust for difference of DLLs on media that were not processed
  652. TickProgressBarDelta ((g_TotalDllsToProcess - DllsProcessed) * TICKS_MIGDLL_DELTA);
  653. g_ProgressBarExists = FALSE;
  654. return TRUE;
  655. }
  656. DWORD
  657. ProcessAllLocalDlls (
  658. IN DWORD Request
  659. )
  660. {
  661. switch (Request) {
  662. case REQUEST_QUERYTICKS:
  663. g_TotalDllsToProcess = GetTotalMigrationDllCount();
  664. return (g_TotalDllsToProcess * TICKS_MIGDLL_DELTA);
  665. case REQUEST_RUN:
  666. if (!pProcessAllLocalDlls ()) {
  667. return GetLastError ();
  668. }
  669. else {
  670. return ERROR_SUCCESS;
  671. }
  672. default:
  673. DEBUGMSG ((DBG_ERROR, "Bad parameter in ProcessAllLocalDlls"));
  674. }
  675. return 0;
  676. }
  677. BOOL
  678. pEnumPreLoadedDllWorker (
  679. IN OUT PPRELOADED_DLL_ENUM e
  680. )
  681. {
  682. PCTSTR Data;
  683. BOOL b = FALSE;
  684. PTSTR p;
  685. //
  686. // Suppressed?
  687. //
  688. MemDbBuildKey (
  689. e->Node,
  690. MEMDB_CATEGORY_DISABLED_MIGDLLS,
  691. NULL, // no item
  692. NULL, // no field
  693. e->eValue.ValueName
  694. );
  695. if (!MemDbGetValue (e->Node, NULL)) {
  696. //
  697. // Not suppressed. Contains legal path?
  698. //
  699. Data = GetRegValueString (e->Key, e->eValue.ValueName);
  700. if (Data) {
  701. _tcssafecpy (e->Path, Data, MAX_TCHAR_PATH);
  702. p = _tcsrchr (e->Path, TEXT('\\'));
  703. if (p && StringIMatch (_tcsinc (p), TEXT("migrate.dll"))) {
  704. *p = 0;
  705. }
  706. MemFree (g_hHeap, 0, Data);
  707. b = pIsPathLegal (e->Path);
  708. }
  709. }
  710. return b;
  711. }
  712. BOOL
  713. EnumFirstPreLoadedDll (
  714. OUT PPRELOADED_DLL_ENUM e
  715. )
  716. {
  717. ZeroMemory (e, sizeof (PRELOADED_DLL_ENUM));
  718. e->Key = OpenRegKeyStr (S_PREINSTALLED_MIGRATION_DLLS);
  719. if (!e->Key) {
  720. return FALSE;
  721. }
  722. if (!EnumFirstRegValue (&e->eValue, e->Key)) {
  723. AbortPreLoadedDllEnum (e);
  724. return FALSE;
  725. }
  726. //
  727. // Find first reg value that has a legal path
  728. //
  729. while (!pEnumPreLoadedDllWorker (e)) {
  730. if (!EnumNextRegValue (&e->eValue)) {
  731. AbortPreLoadedDllEnum (e);
  732. return FALSE;
  733. }
  734. }
  735. return TRUE;
  736. }
  737. BOOL
  738. EnumNextPreLoadedDll (
  739. IN OUT PPRELOADED_DLL_ENUM e
  740. )
  741. {
  742. do {
  743. if (!EnumNextRegValue (&e->eValue)) {
  744. AbortPreLoadedDllEnum (e);
  745. return FALSE;
  746. }
  747. } while (!pEnumPreLoadedDllWorker (e));
  748. return TRUE;
  749. }
  750. VOID
  751. AbortPreLoadedDllEnum (
  752. IN OUT PPRELOADED_DLL_ENUM e
  753. )
  754. {
  755. if (e->Key) {
  756. CloseRegKey (e->Key);
  757. }
  758. ZeroMemory (e, sizeof (PRELOADED_DLL_ENUM));
  759. }
  760. BOOL
  761. pProcessDllsOnCd (
  762. VOID
  763. )
  764. /*++
  765. Routine Description:
  766. ProcessDllsOnCd scans all source directories for migration DLLs.
  767. Each one found is moved to local storage.
  768. Arguments:
  769. none
  770. Return Value:
  771. TRUE if processing was successful, or FALSE if an error occurred.
  772. --*/
  773. {
  774. UINT u;
  775. CHAR Path[MAX_MBCHAR_PATH];
  776. PCSTR p;
  777. BOOL b = FALSE;
  778. PRELOADED_DLL_ENUM e;
  779. INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
  780. PTSTR Subdir = NULL;
  781. #ifdef PRERELEASE
  782. if (g_ConfigOptions.DiffMode) {
  783. return TRUE;
  784. }
  785. #endif
  786. //
  787. // Build path for each source dir, scan the dir for migration DLLs,
  788. // and watch for any failures.
  789. //
  790. g_ProgressBarExists = TRUE;
  791. __try {
  792. //
  793. // Process cmdline DLLs the very first
  794. //
  795. p = g_ConfigOptions.MigrationDlls;
  796. if (p) {
  797. while (*p) {
  798. if (CANCELLED()) {
  799. SetLastError (ERROR_CANCELLED);
  800. __leave;
  801. }
  802. ScanPathForMigrationDlls (p, NULL, NULL);
  803. if (GetLastError() != ERROR_SUCCESS) {
  804. __leave;
  805. }
  806. p = GetEndOfString (p) + 1;
  807. }
  808. }
  809. //
  810. // Process pre-loaded DLLs first to give them a chance to register stuff
  811. // before "standard" migdlls run
  812. //
  813. if (EnumFirstPreLoadedDll (&e)) {
  814. do {
  815. if (CANCELLED()) {
  816. SetLastError (ERROR_CANCELLED);
  817. __leave;
  818. }
  819. ScanPathForMigrationDlls (e.Path, NULL, NULL);
  820. if (GetLastError() != ERROR_SUCCESS) {
  821. __leave;
  822. }
  823. } while (EnumNextPreLoadedDll (&e));
  824. }
  825. for (u = 0 ; u < SOURCEDIRECTORYCOUNT() ; u++) {
  826. if (CANCELLED()) {
  827. SetLastError (ERROR_CANCELLED);
  828. __leave;
  829. }
  830. //
  831. // We look for migration dlls in all of the directories listed in
  832. // win95upg.inf [MigrationDllPaths].
  833. //
  834. if (InfFindFirstLine (g_Win95UpgInf, S_CD_MIGRATION_DLLS, NULL, &is)) {
  835. do {
  836. Subdir = InfGetStringField (&is, 0);
  837. if (!Subdir) {
  838. continue;
  839. }
  840. wsprintf (Path, "%s\\%s", SOURCEDIRECTORY(u), Subdir);
  841. if (GetFileAttributes (Path) == INVALID_ATTRIBUTES) {
  842. //
  843. // Try the non-cd layout.
  844. //
  845. wsprintf (Path, "%s\\WINNT32\\%s", SOURCEDIRECTORY(u), Subdir);
  846. if (GetFileAttributes (Path) == INVALID_ATTRIBUTES) {
  847. continue;
  848. }
  849. }
  850. SetLastError (ERROR_SUCCESS);
  851. ScanPathForMigrationDlls (Path, NULL, NULL);
  852. } while (InfFindNextLine (&is));
  853. }
  854. if (GetLastError() != ERROR_SUCCESS && GetLastError() != ERROR_LINE_NOT_FOUND) {
  855. __leave;
  856. }
  857. }
  858. InfCleanUpInfStruct (&is);
  859. b = TRUE;
  860. }
  861. __finally {
  862. g_ProgressBarExists = FALSE;
  863. g_MediaDllsQueried = TRUE;
  864. }
  865. return b;
  866. }
  867. DWORD
  868. ProcessDllsOnCd (
  869. IN DWORD Request
  870. )
  871. {
  872. switch (Request) {
  873. case REQUEST_QUERYTICKS:
  874. #ifdef PRERELEASE
  875. if (g_ConfigOptions.DiffMode) {
  876. return 0;
  877. }
  878. #endif
  879. return (GetMediaMigrationDllCount() * TICKS_MIGDLL_QUERYVERSION);
  880. case REQUEST_RUN:
  881. if (!pProcessDllsOnCd ()) {
  882. return GetLastError ();
  883. }
  884. else {
  885. return ERROR_SUCCESS;
  886. }
  887. default:
  888. DEBUGMSG ((DBG_ERROR, "Bad parameter in ProcessDllsOnCd"));
  889. }
  890. return 0;
  891. }
  892. UINT
  893. pCountMigrateDllsInPath (
  894. IN PCSTR Path
  895. )
  896. /*++
  897. Routine Description:
  898. pCountMigrateDllsInPath scans a path for files named migrate.dll
  899. and returns the number found.
  900. Arguments:
  901. Path - Specifies root of the path to search
  902. Return Value:
  903. The number of migrate.dll modules found in the path.
  904. --*/
  905. {
  906. TREE_ENUM e;
  907. UINT Count = 0;
  908. if (EnumFirstFileInTree (&e, Path, "migrate.dll", FALSE)) {
  909. do {
  910. if (CANCELLED()) {
  911. return 0;
  912. }
  913. if (!e.Directory) {
  914. Count++;
  915. }
  916. } while (EnumNextFileInTree (&e));
  917. }
  918. return Count;
  919. }
  920. UINT
  921. GetMediaMigrationDllCount (
  922. VOID
  923. )
  924. /*++
  925. Routine Description:
  926. GetMediaMigrationDllCount scans all the source directories, registry and
  927. unattended directories and returns the number of migrate.dll files found.
  928. Arguments:
  929. none
  930. Return Value:
  931. The number of migrate.dll modules found in the source directories and
  932. directories supplied by the answer file.
  933. --*/
  934. {
  935. UINT u;
  936. CHAR Path[MAX_MBCHAR_PATH];
  937. PCSTR p;
  938. BOOL TurnItOff = FALSE;
  939. PRELOADED_DLL_ENUM e;
  940. static UINT MediaDlls = 0;
  941. if (MediaDlls) {
  942. return MediaDlls;
  943. }
  944. //
  945. // Build path for each source dir, scan the dir for migration DLLs,
  946. // and watch for any failures.
  947. //
  948. __try {
  949. p = g_ConfigOptions.MigrationDlls;
  950. if (SOURCEDIRECTORYCOUNT() > 1 || (p && *p)) {
  951. TurnOnWaitCursor();
  952. TurnItOff = TRUE;
  953. }
  954. for (u = 0 ; u < SOURCEDIRECTORYCOUNT() ; u++) {
  955. if (CANCELLED()) {
  956. SetLastError (ERROR_CANCELLED);
  957. __leave;
  958. }
  959. wsprintf (Path, "%s\\win9xmig", SOURCEDIRECTORY(u));
  960. MediaDlls += pCountMigrateDllsInPath (Path);
  961. }
  962. if (p) {
  963. while (*p) {
  964. if (CANCELLED()) {
  965. SetLastError (ERROR_CANCELLED);
  966. __leave;
  967. }
  968. MediaDlls += pCountMigrateDllsInPath (p);
  969. p = GetEndOfString (p) + 1;
  970. }
  971. }
  972. //
  973. // Count pre-loaded DLLs
  974. //
  975. if (EnumFirstPreLoadedDll (&e)) {
  976. do {
  977. if (CANCELLED()) {
  978. SetLastError (ERROR_CANCELLED);
  979. __leave;
  980. }
  981. MediaDlls += pCountMigrateDllsInPath (e.Path);
  982. } while (EnumNextPreLoadedDll (&e));
  983. }
  984. }
  985. __finally {
  986. if (TurnItOff) {
  987. TurnOffWaitCursor();
  988. }
  989. }
  990. return MediaDlls;
  991. }
  992. UINT
  993. GetMigrationDllCount (
  994. VOID
  995. )
  996. /*++
  997. Routine Description:
  998. GetMigrationDllCount returns the number of migration DLLs in local storage.
  999. Arguments:
  1000. none
  1001. Return Value:
  1002. The number of migrate.dll modules successfully moved to local storage.
  1003. --*/
  1004. {
  1005. return g_MigDllsAlive;
  1006. }
  1007. UINT
  1008. GetTotalMigrationDllCount (
  1009. VOID
  1010. )
  1011. /*++
  1012. Routine Description:
  1013. GetTotalMigrationDllCount returns the number of DLLs that will be
  1014. processed. This includes media-based DLLs, DLLs supplied by the wizard
  1015. page UI, DLLs specified in the registry, and DLLs specified in the answer file.
  1016. Arguments:
  1017. None.
  1018. Return Value:
  1019. The total number of DLLs to be processed.
  1020. --*/
  1021. {
  1022. UINT DllCount;
  1023. if (g_MediaDllsQueried) {
  1024. DllCount = 0;
  1025. } else {
  1026. DllCount = GetMediaMigrationDllCount();
  1027. }
  1028. DllCount += g_MigDllsAlive;
  1029. return DllCount;
  1030. }
  1031. BOOL
  1032. pVerifyDllIsTrusted (
  1033. IN PCSTR DllPath
  1034. )
  1035. /*++
  1036. Routine Description:
  1037. pVerifyDllIsTrusted determines if the specified DLL is digitally signed
  1038. and is trusted by the system.
  1039. Arguments:
  1040. none
  1041. Return Value:
  1042. The number of migrate.dll modules successfully moved to local storage.
  1043. The caller uses GetLastError when the return value is FALSE to determine
  1044. if Setup was cancelled via UI.
  1045. --*/
  1046. {
  1047. static BOOL TrustAll = FALSE;
  1048. UINT Status;
  1049. if (TrustAll) {
  1050. return TRUE;
  1051. }
  1052. if (!IsDllSigned (WinVerifyTrustApi, DllPath)) {
  1053. Status = UI_UntrustedDll (DllPath);
  1054. if (Status == IDC_TRUST_IT) {
  1055. return TRUE;
  1056. } else if (Status == IDC_TRUST_ANY) {
  1057. TrustAll = TRUE;
  1058. return TRUE;
  1059. } else if (Status == IDCANCEL) {
  1060. SetLastError (ERROR_CANCELLED);
  1061. return FALSE;
  1062. }
  1063. SetLastError (ERROR_SUCCESS);
  1064. return FALSE;
  1065. }
  1066. return TRUE;
  1067. }
  1068. BOOL
  1069. pMatchAttributes(
  1070. IN DBATTRIB_PARAMS * pdbAttribParams,
  1071. IN MIGDB_ATTRIB * pMigDbAttrib
  1072. )
  1073. {
  1074. BOOL bResult = TRUE;
  1075. while (pMigDbAttrib != NULL) {
  1076. pdbAttribParams->ExtraData = pMigDbAttrib->ExtraData;
  1077. if (!CallAttribute (pMigDbAttrib, pdbAttribParams)) {
  1078. bResult = FALSE;
  1079. break;
  1080. }
  1081. pMigDbAttrib = pMigDbAttrib->Next;
  1082. }
  1083. return bResult;
  1084. }
  1085. BOOL
  1086. pValidateAndMoveDll (
  1087. IN PCSTR DllPath,
  1088. IN OUT PBOOL MatchFound OPTIONAL
  1089. )
  1090. /*++
  1091. Routine Description:
  1092. pValidateAndMoveDll calls the DLL's QueryVersion function, and if the DLL
  1093. returns success, it is moved to local storage, along with all the files
  1094. associated with it.
  1095. Arguments:
  1096. DllPath - Specifies full path to the migrate.dll to process
  1097. MatchFound - Specifies an initialized BOOL, which may be either TRUE or
  1098. FALSE depending on whether another valid migration DLL has
  1099. been processed by the caller. Receives TRUE if the
  1100. migrate.dll is valid, otherwise the value is not changed.
  1101. Return Value:
  1102. TRUE if the DLL specified by DllPath is valid and needs to run, or FALSE
  1103. if not. GetLastError is used by the caller to detect fatal errors.
  1104. --*/
  1105. {
  1106. PCSTR ProductId = NULL;
  1107. UINT DllVersion = 0;
  1108. PCSTR ExeNamesBuf = NULL;
  1109. CHAR WorkingDir[MAX_MBCHAR_PATH];
  1110. PVENDORINFO VendorInfo = NULL;
  1111. UINT SizeNeeded;
  1112. CHAR QueryVersionDir[MAX_MBCHAR_PATH];
  1113. PSTR p;
  1114. BOOL b;
  1115. LONG rc;
  1116. PMIGRATION_DLL_PROPS ExistingDll;
  1117. UINT version;
  1118. UINT i;
  1119. UINT listSize;
  1120. //
  1121. // Verify trust of DLL
  1122. //
  1123. if (!pVerifyDllIsTrusted (DllPath)) {
  1124. DEBUGMSG ((DBG_WARNING, "DLL %s is not trusted and will not be processed", DllPath));
  1125. //
  1126. // Implicit: SetLastError (ERROR_SUCCESS); (may be ERROR_CANCELLED if user
  1127. // cancelled via UI)
  1128. //
  1129. return FALSE;
  1130. }
  1131. //
  1132. // verify if this is one of the excluded migdlls, based on their file characteristics
  1133. //
  1134. if (GrowListGetSize (&g_ExcludedMigDllsByInfo)) {
  1135. WIN32_FIND_DATA fd;
  1136. HANDLE h;
  1137. FILE_HELPER_PARAMS params;
  1138. DBATTRIB_PARAMS dbAttribParams;
  1139. PMIGDB_ATTRIB * ppMigDBattrib;
  1140. h = FindFirstFile (DllPath, &fd);
  1141. if (h != INVALID_HANDLE_VALUE) {
  1142. CloseHandle (h);
  1143. ZeroMemory (&params, sizeof(params));
  1144. params.FindData = &fd;
  1145. params.FullFileSpec = DllPath;
  1146. ZeroMemory (&dbAttribParams, sizeof(dbAttribParams));
  1147. dbAttribParams.FileParams = &params;
  1148. for(i = 0, listSize = GrowListGetSize(&g_ExcludedMigDllsByInfo); i < listSize; i++){
  1149. ppMigDBattrib = (PMIGDB_ATTRIB *)GrowListGetItem(&g_ExcludedMigDllsByInfo, i);
  1150. MYASSERT(ppMigDBattrib);
  1151. if(pMatchAttributes(&dbAttribParams, *ppMigDBattrib)){
  1152. LOG ((
  1153. LOG_INFORMATION,
  1154. TEXT("Found upgrade pack %s, but it is excluded from processing [%s]"),
  1155. DllPath,
  1156. S_EXCLUDEDMIGDLLSBYATTR
  1157. ));
  1158. SetLastError (ERROR_SUCCESS);
  1159. return FALSE;
  1160. }
  1161. }
  1162. }
  1163. }
  1164. //
  1165. // Copy base of DLL to QueryVersionDir, and trim off migrate.dll
  1166. //
  1167. StackStringCopyA (QueryVersionDir, DllPath);
  1168. p = _mbsrchr (QueryVersionDir, '\\');
  1169. MYASSERT (StringIMatch (p, "\\migrate.dll"));
  1170. if (p) {
  1171. *p = 0;
  1172. }
  1173. SizeNeeded = pCalculateSizeOfTree (QueryVersionDir);
  1174. if (!pCreateWorkingDir (WorkingDir, QueryVersionDir, SizeNeeded)) {
  1175. return FALSE;
  1176. }
  1177. //
  1178. // Call QueryVersion directly from the suppling media
  1179. //
  1180. b = OpenMigrationDll (DllPath, WorkingDir);
  1181. if (b) {
  1182. rc = CallQueryVersion (
  1183. WorkingDir,
  1184. &ProductId,
  1185. &DllVersion,
  1186. &ExeNamesBuf,
  1187. &VendorInfo
  1188. );
  1189. if (g_ProgressBarExists) {
  1190. TickProgressBarDelta (TICKS_MIGDLL_QUERYVERSION);
  1191. }
  1192. if (rc != ERROR_SUCCESS) {
  1193. b = FALSE;
  1194. if (rc == ERROR_NOT_INSTALLED) {
  1195. if (MatchFound) {
  1196. *MatchFound = TRUE;
  1197. }
  1198. rc = ERROR_SUCCESS;
  1199. } else if (rc != ERROR_SUCCESS) {
  1200. if (rc == RPC_S_CALL_FAILED) {
  1201. rc = ERROR_NOACCESS;
  1202. }
  1203. pMigrationDllFailedMsg (
  1204. NULL,
  1205. DllPath,
  1206. 0,
  1207. MSG_MIGDLL_QV_FAILED_LOG,
  1208. rc
  1209. );
  1210. rc = ERROR_SUCCESS;
  1211. }
  1212. } else {
  1213. //
  1214. // QueryVersion was called and it returned success (it wants to run)
  1215. // but first check if this migration dll is intentionally excluded
  1216. //
  1217. if (g_ExcludedMigDlls &&
  1218. HtFindStringAndData (g_ExcludedMigDlls, ProductId, &version) &&
  1219. DllVersion <= version
  1220. ) {
  1221. LOG ((
  1222. LOG_INFORMATION,
  1223. TEXT("Found upgrade pack %s (ProductId=%s, Version=%u), but it is excluded from processing"),
  1224. DllPath,
  1225. ProductId,
  1226. DllVersion
  1227. ));
  1228. b = FALSE;
  1229. } else {
  1230. if (MatchFound) {
  1231. *MatchFound = TRUE;
  1232. }
  1233. }
  1234. }
  1235. } else {
  1236. //
  1237. // Don't pass errors on.
  1238. //
  1239. if (g_ProgressBarExists) {
  1240. TickProgressBarDelta (TICKS_MIGDLL_QUERYVERSION); // early out, account for DLL not being processed
  1241. } // (see similar case below in finally block)
  1242. rc = ERROR_SUCCESS;
  1243. }
  1244. if (!b) {
  1245. DEBUGMSG ((DBG_MIGDLLS, "%hs will not be processed", DllPath));
  1246. CloseMigrationDll();
  1247. pDestroyWorkingDir (WorkingDir);
  1248. SetLastError (rc);
  1249. return FALSE;
  1250. }
  1251. //
  1252. // We have found a DLL that wants to run. Try moving it to local storage.
  1253. //
  1254. DEBUGMSG ((DBG_MIGDLLS, "Moving DLL for %s to local storage: %s", ProductId, DllPath));
  1255. __try {
  1256. b = FALSE;
  1257. //
  1258. // Look for existing version of DLL
  1259. //
  1260. ExistingDll = pFindMigrationDll (ProductId);
  1261. if (ExistingDll && ExistingDll->Version >= DllVersion) {
  1262. DEBUGMSG_IF ((
  1263. ExistingDll->Version > DllVersion,
  1264. DBG_MIGDLLS,
  1265. "%hs will not be processed because it is an older version",
  1266. DllPath
  1267. ));
  1268. SetLastError (ERROR_SUCCESS);
  1269. __leave;
  1270. }
  1271. if (ExistingDll) {
  1272. RemoveDllFromList (ExistingDll->Id);
  1273. }
  1274. //
  1275. // Add the DLL to the list of loaded DLLs, and move all of the files
  1276. //
  1277. if (!pAddDllToList (
  1278. QueryVersionDir,
  1279. WorkingDir,
  1280. ProductId,
  1281. DllVersion,
  1282. ExeNamesBuf,
  1283. VendorInfo
  1284. )) {
  1285. pDestroyWorkingDir (WorkingDir);
  1286. __leave;
  1287. }
  1288. //
  1289. // DLL is now on a local drive and has returned success from QueryVersion.
  1290. //
  1291. b = TRUE;
  1292. }
  1293. __finally {
  1294. DEBUGMSG ((DBG_MIGDLLS, "Done with %s", ProductId));
  1295. CloseMigrationDll();
  1296. }
  1297. return b;
  1298. }
  1299. BOOL
  1300. pCreateWorkingDir (
  1301. OUT PSTR WorkingDir,
  1302. IN PCSTR QueryVersionDir,
  1303. IN UINT SizeNeeded
  1304. )
  1305. /*++
  1306. Routine Description:
  1307. pCreateWorkingDir generates a working directory name and creates it.
  1308. The directory will have enough space to hold the size requested.
  1309. Arguments:
  1310. WorkingDir - Receives the full path to the working directory
  1311. QueryVersionDir - Specifies the version where the migration DLL is
  1312. when QueryVersion is called
  1313. SizeNeeded - Specifies the number of bytes, rounded up to the next
  1314. cluster size, indicating the total space to be occupied
  1315. by migration DLL files
  1316. Return Value:
  1317. TRUE if processing was successful, or FALSE if an error occurred.
  1318. --*/
  1319. {
  1320. static UINT Sequencer = 1;
  1321. //
  1322. // For now, just put the files in %windir%\setup\temp
  1323. //
  1324. wsprintf (WorkingDir, "%s\\dll%05u", g_PlugInTempDir, Sequencer);
  1325. Sequencer++;
  1326. //
  1327. // Establish the directory
  1328. //
  1329. if (CreateEmptyDirectory (WorkingDir) != ERROR_SUCCESS) {
  1330. LOG ((LOG_ERROR, "pCreateWorkingDir: Can't create %hs", WorkingDir));
  1331. return FALSE;
  1332. }
  1333. return TRUE;
  1334. }
  1335. VOID
  1336. pDestroyWorkingDir (
  1337. IN PCSTR WorkingDir
  1338. )
  1339. /*++
  1340. Routine Description:
  1341. pDestroyWorkingDir cleans up the specified working directory
  1342. Arguments:
  1343. WorkingDir - Specifies the name of the directory to clean up
  1344. Return Value:
  1345. none
  1346. --*/
  1347. {
  1348. BOOL b;
  1349. BOOL TurnItOff = FALSE;
  1350. UINT Files = 0;
  1351. TREE_ENUM e;
  1352. //
  1353. // Count the number of things that will be deleted, and if there
  1354. // are more than 20, turn on the wait cursor. (This keeps the
  1355. // UI responsive.)
  1356. //
  1357. if (EnumFirstFileInTree (&e, WorkingDir, NULL, FALSE)) {
  1358. do {
  1359. Files++;
  1360. if (Files > 30) {
  1361. AbortEnumFileInTree (&e);
  1362. TurnOnWaitCursor();
  1363. TurnItOff = TRUE;
  1364. break;
  1365. }
  1366. } while (EnumNextFileInTree (&e));
  1367. }
  1368. b = DeleteDirectoryContents (WorkingDir);
  1369. b &= RemoveDirectory (WorkingDir);
  1370. if (!b) {
  1371. LOG ((LOG_ERROR, "Unable to delete %hs", WorkingDir));
  1372. }
  1373. if (TurnItOff) {
  1374. TurnOffWaitCursor();
  1375. }
  1376. }
  1377. PMIGRATION_DLL_PROPS
  1378. pFindMigrationDll (
  1379. IN PCSTR ProductId
  1380. )
  1381. /*++
  1382. Routine Description:
  1383. pFindMigrationDll searches the private data structures for the specified
  1384. ProductId. The ProductId is in a string table, so lookup is fast.
  1385. Arguments:
  1386. ProductId - Specifies the ID of the DLL to find
  1387. Return Value:
  1388. A pointer to the DLL's property struct, or NULL if the product ID does
  1389. not match any of the DLLs.
  1390. --*/
  1391. {
  1392. PMIGRATION_DLL_PROPS Props;
  1393. LONG rc;
  1394. rc = pSetupStringTableLookUpStringEx (
  1395. g_DllTable,
  1396. (PTSTR) ProductId,
  1397. STRTAB_CASE_INSENSITIVE,
  1398. &Props,
  1399. sizeof (Props)
  1400. );
  1401. if (rc == -1) {
  1402. return NULL;
  1403. }
  1404. return Props;
  1405. }
  1406. PMIGRATION_DLL_PROPS
  1407. pFindMigrationDllById (
  1408. IN LONG Id
  1409. )
  1410. /*++
  1411. Routine Description:
  1412. pFindMigrationDllById returns the migration DLL property structure for
  1413. a DLL ID. The ID is the same ID returned by the DLL enumeration routines.
  1414. Arguments:
  1415. Id - Specifies the ID to find properties for
  1416. Return Value:
  1417. A pointer to the DLL's property struct, or NULL if the ID is not valid.
  1418. --*/
  1419. {
  1420. PMIGRATION_DLL_PROPS Props;
  1421. if (Id == -1) {
  1422. return NULL;
  1423. }
  1424. if (!pSetupStringTableGetExtraData (
  1425. g_DllTable,
  1426. Id,
  1427. &Props,
  1428. sizeof (Props)
  1429. )) {
  1430. return NULL;
  1431. }
  1432. return Props;
  1433. }
  1434. UINT
  1435. pGetMaxClusterSize (
  1436. VOID
  1437. )
  1438. /*++
  1439. Routine Description:
  1440. pGetMaxClusterSize determines the maximum cluster size of all disks
  1441. that are candidates for working directories.
  1442. Arguments:
  1443. none
  1444. Return Value:
  1445. The number of bytes per cluster.
  1446. --*/
  1447. {
  1448. ACCESSIBLE_DRIVE_ENUM e;
  1449. static DWORD MaxSize = 0;
  1450. if (MaxSize) {
  1451. return MaxSize;
  1452. }
  1453. if (GetFirstAccessibleDriveEx (&e, TRUE)) {
  1454. do {
  1455. MaxSize = max (MaxSize, e->ClusterSize);
  1456. } while (GetNextAccessibleDrive (&e));
  1457. }
  1458. MYASSERT (MaxSize);
  1459. return MaxSize;
  1460. }
  1461. UINT
  1462. pCalculateSizeOfTree (
  1463. IN PCSTR PathSpec
  1464. )
  1465. /*++
  1466. Routine Description:
  1467. pCalculateSizeOfTree enumerates the specified path and calculates
  1468. the number of physical bytes occupied by the files and directory
  1469. structures.
  1470. Arguments:
  1471. PathSpec - Specifies root of path to find
  1472. Return Value:
  1473. The number of bytes physically occupied by the path
  1474. --*/
  1475. {
  1476. TREE_ENUM e;
  1477. UINT Size = 0;
  1478. UINT ClusterSize;
  1479. ClusterSize = pGetMaxClusterSize();
  1480. if (EnumFirstFileInTree (&e, PathSpec, NULL, FALSE)) {
  1481. do {
  1482. //
  1483. // We assume the migrate.dll will never pack more than 4G of
  1484. // files.
  1485. //
  1486. if (!e.Directory) {
  1487. MYASSERT (Size + e.FindData->nFileSizeLow >= Size);
  1488. MYASSERT (!e.FindData->nFileSizeHigh);
  1489. Size += e.FindData->nFileSizeLow + ClusterSize -
  1490. (e.FindData->nFileSizeLow % ClusterSize);
  1491. } else {
  1492. // Add a fudge factor here, we don't know the exact size
  1493. e.Directory += ClusterSize;
  1494. }
  1495. } while (EnumNextFileInTree (&e));
  1496. }
  1497. return Size;
  1498. }
  1499. BOOL
  1500. pEnumMigrationDllWorker (
  1501. IN OUT PMIGDLL_ENUM EnumPtr,
  1502. IN PMIGRATION_DLL_PROPS Props
  1503. )
  1504. /*++
  1505. Routine Description:
  1506. pEnumMigrationDllWorker is a common routine that completes the
  1507. enumeration of a DLL. It fills in the EnumPtr data members
  1508. and returns TRUE. Also, it screens out invalid DLL structures
  1509. (those that have been disabled by RemoveDllFromList).
  1510. Arguments:
  1511. EnumPtr - Specifies the partially completed enumeration structure,
  1512. receives the complete information.
  1513. Props - Specifies the properties of the item that was enumerated.
  1514. Return Value:
  1515. FALSE if all remaining of the properties are invalid, or TRUE otherwise
  1516. --*/
  1517. {
  1518. while (Props && Props->Id == -1) {
  1519. Props = Props->Next;
  1520. }
  1521. if (!Props) {
  1522. return FALSE;
  1523. }
  1524. EnumPtr->ProductId = Props->ProductId;
  1525. EnumPtr->VendorInfo = Props->VendorInfo;
  1526. EnumPtr->CurrentDir = Props->WorkingDir;
  1527. EnumPtr->AllDllProps = Props;
  1528. EnumPtr->Id = Props->Id;
  1529. return TRUE;
  1530. }
  1531. BOOL
  1532. EnumFirstMigrationDll (
  1533. OUT PMIGDLL_ENUM EnumPtr
  1534. )
  1535. /*++
  1536. Routine Description:
  1537. EnumFirstMigrationDll begins an enumeration of migration DLLs.
  1538. Callers can then use the enumerated information to fill list
  1539. boxes or any other processing.
  1540. Arguments:
  1541. EnumPtr - Receives the first enumerated DLL's properties
  1542. Return Value:
  1543. TRUE if a DLL was enumerated, or FALSE if not.
  1544. --*/
  1545. {
  1546. ZeroMemory (EnumPtr, sizeof (MIGDLL_ENUM));
  1547. return pEnumMigrationDllWorker (EnumPtr, g_HeadDll);
  1548. }
  1549. BOOL
  1550. EnumNextMigrationDll (
  1551. IN OUT PMIGDLL_ENUM EnumPtr
  1552. )
  1553. /*++
  1554. Routine Description:
  1555. EnumNextMigrationDll continues enumeration started by EnumFirstMigrationDll.
  1556. Arguments:
  1557. EnumPtr - Specifies the last enumerated item, receives the next enumerated
  1558. item.
  1559. Return Value:
  1560. TRUE if another DLL was enumerated, or FALSE if not.
  1561. --*/
  1562. {
  1563. if (EnumPtr->AllDllProps->Next) {
  1564. return pEnumMigrationDllWorker (EnumPtr, EnumPtr->AllDllProps->Next);
  1565. }
  1566. return FALSE;
  1567. }
  1568. BOOL
  1569. pAddDllToList (
  1570. IN PCSTR MediaDir,
  1571. IN PCSTR WorkingDir,
  1572. IN PCSTR ProductId,
  1573. IN UINT Version,
  1574. IN PCSTR ExeNamesBuf, OPTIONAL
  1575. IN PVENDORINFO VendorInfo
  1576. )
  1577. /*++
  1578. Routine Description:
  1579. pAddDllToList adds the supplied properties to the private data structures
  1580. used to organize the migration DLLs. The ProductId is placed in a string
  1581. table, the ExeNamesBuf is put in a list of files, and the rest of the
  1582. members are duplciated into a memory pool.
  1583. Arguments:
  1584. MediaDir - Specifies the directory containing the migration DLL
  1585. WorkingDir - Specifies the working directory assigned to the DLL on local
  1586. storage
  1587. ProductId - Specifies the display name of the migration DLL
  1588. Version - Specifies the DLL's version number
  1589. ExeNamesBuf - Specifies a multi-sz listing file names that need to
  1590. be located
  1591. VendorInfo - Specifies the vendor info provided by the migration DLL
  1592. Return Value:
  1593. TRUE if processing was successful, or FALSE if an error occurred.
  1594. --*/
  1595. {
  1596. PMIGRATION_DLL_PROPS Props;
  1597. CHAR MigrateInfPath[MAX_MBCHAR_PATH];
  1598. PCSTR p;
  1599. HANDLE File;
  1600. //
  1601. // Copy the DLL into the working directory
  1602. //
  1603. if (!CopyTree (
  1604. MediaDir,
  1605. WorkingDir,
  1606. 0,
  1607. COPYTREE_DOCOPY | COPYTREE_NOOVERWRITE,
  1608. ENUM_ALL_LEVELS,
  1609. FILTER_ALL,
  1610. NULL,
  1611. NULL,
  1612. NULL
  1613. )) {
  1614. LOG ((LOG_ERROR, "Error while copying files for migration.dll."));
  1615. return FALSE;
  1616. }
  1617. //
  1618. // Generate a new DLL struct
  1619. //
  1620. Props = (PMIGRATION_DLL_PROPS) PoolMemGetMemory (g_MigDllPool, sizeof (MIGRATION_DLL_PROPS));
  1621. //
  1622. // Link props to list of all DLLs
  1623. //
  1624. Props->Next = g_HeadDll;
  1625. g_HeadDll = Props;
  1626. //
  1627. // Add product ID to string table for quick lookup
  1628. //
  1629. Props->Id = pSetupStringTableAddStringEx (
  1630. g_DllTable,
  1631. (PTSTR) ProductId,
  1632. STRTAB_CASE_INSENSITIVE|STRTAB_NEW_EXTRADATA,
  1633. &Props,
  1634. sizeof (Props)
  1635. );
  1636. if (Props->Id == -1) {
  1637. LOG ((LOG_ERROR, "Error adding migration.dll to list."));
  1638. return FALSE;
  1639. }
  1640. //
  1641. // Fill in the rest of the DLL properties
  1642. //
  1643. Props->ProductId = PoolMemDuplicateString (g_MigDllPool, ProductId);
  1644. Props->VendorInfo = (PVENDORINFO) PoolMemDuplicateMemory (g_MigDllPool, (PBYTE) VendorInfo, sizeof (VENDORINFO));
  1645. Props->WorkingDir = PoolMemDuplicateString (g_MigDllPool, WorkingDir);
  1646. Props->Version = Version;
  1647. Props->OriginalDir = PoolMemDuplicateString (g_MigDllPool, MediaDir);
  1648. wsprintf (MigrateInfPath, "%s\\migrate.inf", Props->WorkingDir);
  1649. Props->MigrateInfPath = PoolMemDuplicateString (g_MigDllPool, MigrateInfPath);
  1650. Props->WantsToRunOnNt = FALSE; // MigrateUser9x or MigrateSystem9x must return success for this to be TRUE
  1651. Props->MigInfAppend = INVALID_HANDLE_VALUE;
  1652. //
  1653. // Dump vendor info to log
  1654. //
  1655. LOG ((
  1656. LOG_INFORMATION,
  1657. "Upgrade Pack: %s\n"
  1658. "Version: %u\n"
  1659. "Company Name: %s\n"
  1660. "Support Number: %s\n"
  1661. "Support URL: %s\n"
  1662. "Instructions: %s\n",
  1663. Props->ProductId,
  1664. Props->Version,
  1665. VendorInfo->CompanyName,
  1666. VendorInfo->SupportNumber,
  1667. VendorInfo->SupportUrl,
  1668. VendorInfo->InstructionsToUser
  1669. ));
  1670. //
  1671. // Add all search files to string table
  1672. //
  1673. p = ExeNamesBuf;
  1674. if (p) {
  1675. while (*p) {
  1676. pAddFileToSearchTable (p, Props);
  1677. p = GetEndOfStringA (p) + 1;
  1678. }
  1679. }
  1680. //
  1681. // Copy migrate.inf to DLL dir
  1682. //
  1683. SetFileAttributes (Props->MigrateInfPath, FILE_ATTRIBUTE_NORMAL);
  1684. CopyFile (g_MigrateInfTemplate, Props->MigrateInfPath, FALSE);
  1685. File = CreateFile (Props->MigrateInfPath, GENERIC_READ|GENERIC_WRITE, 0, NULL,
  1686. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1687. if (File != INVALID_HANDLE_VALUE) {
  1688. SetFilePointer (File, 0, NULL, FILE_END);
  1689. WriteFileString (File, TEXT("\r\n; "));
  1690. WriteFileString (File, Props->ProductId);
  1691. WriteFileString (File, TEXT("\r\n"));
  1692. CloseHandle (File);
  1693. } else {
  1694. LOG ((LOG_ERROR, "Cannot open %s", Props->MigrateInfPath));
  1695. }
  1696. g_MigDllsAlive++;
  1697. return TRUE;
  1698. }
  1699. VOID
  1700. RemoveDllFromList (
  1701. IN LONG ItemId
  1702. )
  1703. /*++
  1704. Routine Description:
  1705. RemoveDllFromList disables the data structures for the specified DLL and
  1706. removes it from local storage.
  1707. Arguments:
  1708. ItemId - Specifies the ID of the migration DLL to remove
  1709. Return Value:
  1710. none
  1711. --*/
  1712. {
  1713. PMIGRATION_DLL_PROPS Prev, This;
  1714. PMIGRATION_DLL_PROPS Props;
  1715. Props = pFindMigrationDllById (ItemId);
  1716. if (!Props) {
  1717. DEBUGMSG ((DBG_WHOOPS, "Cannot remove migration DLL id %i", ItemId));
  1718. return;
  1719. }
  1720. //
  1721. // Delete the linkage
  1722. //
  1723. Prev = NULL;
  1724. This = g_HeadDll;
  1725. while (This && This != Props) {
  1726. Prev = This;
  1727. This = This->Next;
  1728. }
  1729. if (Prev) {
  1730. Prev->Next = Props->Next;
  1731. } else {
  1732. g_HeadDll = Props->Next;
  1733. }
  1734. //
  1735. // Delete the string table entry by making the item data NULL
  1736. //
  1737. This = NULL;
  1738. pSetupStringTableSetExtraData (
  1739. g_DllTable,
  1740. ItemId,
  1741. &This,
  1742. sizeof (This)
  1743. );
  1744. //
  1745. // Set Id to -1 so any search files are ignored
  1746. //
  1747. Props->Id = -1;
  1748. pDestroyWorkingDir (Props->WorkingDir);
  1749. g_MigDllsAlive--;
  1750. }
  1751. BOOL
  1752. pAddFileToSearchTable (
  1753. IN PCSTR File,
  1754. IN PMIGRATION_DLL_PROPS Props
  1755. )
  1756. /*++
  1757. Routine Description:
  1758. pAddFileToSearchTable adds the specified file name to the global lookup
  1759. table used to quickly find the DLL (or DLLs) that want the location
  1760. of the file.
  1761. Arguments:
  1762. File - Specifies the long file name of the file to find
  1763. Props - Specifies the properties of the DLL that wants the location of
  1764. File
  1765. Return Value:
  1766. TRUE if processing was successful, or FALSE if an error occurred.
  1767. --*/
  1768. {
  1769. PFILETOFIND IndexedFile;
  1770. PFILETOFIND NewFile;
  1771. LONG rc;
  1772. LONG Offset;
  1773. //
  1774. // Allocate a new file struct
  1775. //
  1776. NewFile = (PFILETOFIND) PoolMemGetMemory (g_MigDllPool, sizeof (FILETOFIND));
  1777. if (!NewFile) {
  1778. return FALSE;
  1779. }
  1780. NewFile->Next = NULL;
  1781. NewFile->Dll = Props;
  1782. //
  1783. // Does a struct already exist in string table?
  1784. //
  1785. Offset = pSetupStringTableLookUpStringEx (
  1786. g_DllFileTable,
  1787. (PTSTR) File,
  1788. STRTAB_CASE_INSENSITIVE,
  1789. &IndexedFile,
  1790. sizeof (IndexedFile)
  1791. );
  1792. if (Offset == -1) {
  1793. //
  1794. // No, add it now
  1795. //
  1796. rc = pSetupStringTableAddStringEx (
  1797. g_DllFileTable,
  1798. (PTSTR) File,
  1799. STRTAB_CASE_INSENSITIVE,
  1800. &NewFile,
  1801. sizeof (NewFile)
  1802. );
  1803. } else {
  1804. //
  1805. // Yes, put it at the head of the list
  1806. //
  1807. rc = pSetupStringTableSetExtraData (
  1808. g_DllFileTable,
  1809. Offset,
  1810. &NewFile,
  1811. sizeof (NewFile)
  1812. );
  1813. IndexedFile->Next = NewFile;
  1814. }
  1815. return rc != -1;
  1816. }
  1817. BOOL
  1818. pWriteStringToEndOfInf (
  1819. IN OUT PMIGRATION_DLL_PROPS Dll,
  1820. IN PCSTR String,
  1821. IN PCSTR HeaderString, OPTIONAL
  1822. IN BOOL WriteLineFeed
  1823. )
  1824. /*++
  1825. Routine Description:
  1826. pWriteStringToEndOfInf writes the specified string to migrate.inf.
  1827. This routine also opens migrate.inf if it has not already been
  1828. opened.
  1829. If HeaderString is provided and migrate.inf needs to be opened,
  1830. the header string is written to the file, ahead of String.
  1831. Arguments:
  1832. Dll - Specifies the DLL associated with the migrate.inf
  1833. String - Specifies the string to write
  1834. HeaderString - Specifies text that is written when migrate.inf is
  1835. opened for writing for the first time.
  1836. WriteLineFeed - Specifies TRUE if a \r\n sequence should be written
  1837. after String, or FALSE if not.
  1838. Return Value:
  1839. TRUE if processing was successful, or FALSE if an error occurred.
  1840. --*/
  1841. {
  1842. if (Dll->MigInfAppend == INVALID_HANDLE_VALUE) {
  1843. //
  1844. // Flush the profile APIs
  1845. //
  1846. WritePrivateProfileString(
  1847. NULL,
  1848. NULL,
  1849. NULL,
  1850. Dll->MigrateInfPath
  1851. );
  1852. //
  1853. // Open the file for writing
  1854. //
  1855. Dll->MigInfAppend = CreateFile (
  1856. Dll->MigrateInfPath,
  1857. GENERIC_WRITE,
  1858. 0,
  1859. NULL,
  1860. OPEN_ALWAYS,
  1861. FILE_ATTRIBUTE_NORMAL,
  1862. NULL
  1863. );
  1864. } else {
  1865. HeaderString = NULL;
  1866. }
  1867. if (Dll->MigInfAppend == INVALID_HANDLE_VALUE) {
  1868. LOG ((LOG_ERROR, "Cannot open %s", Dll->MigrateInfPath));
  1869. return FALSE;
  1870. }
  1871. SetFilePointer (Dll->MigInfAppend, 0, NULL, FILE_END);
  1872. if (HeaderString) {
  1873. if (!WriteFileString (Dll->MigInfAppend, HeaderString)) {
  1874. return FALSE;
  1875. }
  1876. }
  1877. if (!WriteFileString (Dll->MigInfAppend, String)) {
  1878. return FALSE;
  1879. }
  1880. if (WriteLineFeed) {
  1881. if (!WriteFileString (Dll->MigInfAppend, "\r\n")) {
  1882. return FALSE;
  1883. }
  1884. }
  1885. return TRUE;
  1886. }
  1887. BOOL
  1888. UpdateFileSearch (
  1889. IN PCSTR FullFileSpec,
  1890. IN PCSTR FileOnly
  1891. )
  1892. /*++
  1893. Routine Description:
  1894. UpdateFileSearch is called for every file on the machine being upgraded,
  1895. and any file that the DLL wants the location file will receive its path
  1896. in the DLL's migrate.inf.
  1897. Arguments:
  1898. FullFileSpec - specifies the full path to the file, in long name format
  1899. FileOnly - Specifies only the file name and must match the file in
  1900. FullFileSpec.
  1901. Return Value:
  1902. TRUE if processing was successful, or FALSE if an error occurred.
  1903. --*/
  1904. {
  1905. PFILETOFIND FileWanted;
  1906. LONG rc;
  1907. //
  1908. // Look in string table for an indexed file, and if found, enumerate
  1909. // all the DLLs that want to know where the file is.
  1910. //
  1911. rc = pSetupStringTableLookUpStringEx (
  1912. g_DllFileTable,
  1913. (PTSTR) FileOnly,
  1914. STRTAB_CASE_INSENSITIVE,
  1915. &FileWanted,
  1916. sizeof (FileWanted)
  1917. );
  1918. if (rc == -1) {
  1919. return TRUE;
  1920. }
  1921. while (FileWanted) {
  1922. if (FileWanted->Dll->Id != -1) {
  1923. //
  1924. // Append path to the end of the file
  1925. //
  1926. if (!pWriteStringToEndOfInf (
  1927. FileWanted->Dll,
  1928. FullFileSpec,
  1929. "\r\n[Migration Paths]\r\n",
  1930. TRUE
  1931. )) {
  1932. return FALSE;
  1933. }
  1934. }
  1935. FileWanted = FileWanted->Next;
  1936. }
  1937. return TRUE;
  1938. }
  1939. VOID
  1940. pMigrationDllFailedMsg (
  1941. IN PMIGRATION_DLL_PROPS Dll, OPTIONAL
  1942. IN PCSTR Path, OPTIONAL
  1943. IN UINT PopupId, OPTIONAL
  1944. IN UINT LogId, OPTIONAL
  1945. IN LONG rc
  1946. )
  1947. /*++
  1948. Routine Description:
  1949. pMigrationDllFailedMsg presents a popup for DLLs that fail to run,
  1950. and also logs the failure to setuperr.log.
  1951. The system's last error is preserved. Also, no output is generated
  1952. if the user has chosen to cancel or if rc is ERROR_SUCCESS.
  1953. Arguments:
  1954. Dll - Specifies the DLL that failed. If Dll is not provided, PopupId
  1955. must be zero.
  1956. Path - Specifies the path to the DLL media
  1957. PopupId - Specifies the message ID for the popup dialog box
  1958. LogId - Specifies the message ID for the log
  1959. rc - Specifies the failure code
  1960. Return Value:
  1961. None.
  1962. --*/
  1963. {
  1964. CHAR ErrorCode[16];
  1965. PCTSTR FixupPhone;
  1966. PCTSTR FixupUrl;
  1967. PCTSTR FixupInstructions;
  1968. PCTSTR LineBreak = S_EMPTY;
  1969. PCTSTR ArgArray[1];
  1970. PushError();
  1971. if (!CANCELLED() && rc != ERROR_SUCCESS && rc != ERROR_CANCELLED) {
  1972. wsprintf (ErrorCode, "%u", rc);
  1973. if (Dll) {
  1974. //
  1975. // Generate fixup strings
  1976. //
  1977. if (Dll->VendorInfo->SupportNumber[0]) {
  1978. ArgArray[0] = Dll->VendorInfo->SupportNumber;
  1979. FixupPhone = ParseMessageID (MSG_MIGDLL_SUPPORT_PHONE_FIXUP, ArgArray);
  1980. LineBreak = TEXT("\n");
  1981. } else {
  1982. FixupPhone = S_EMPTY;
  1983. }
  1984. if (Dll->VendorInfo->SupportUrl[0]) {
  1985. ArgArray[0] = Dll->VendorInfo->SupportUrl;
  1986. FixupUrl = ParseMessageID (MSG_MIGDLL_SUPPORT_URL_FIXUP, ArgArray);
  1987. LineBreak = TEXT("\n");
  1988. } else {
  1989. FixupUrl = S_EMPTY;
  1990. }
  1991. if (Dll->VendorInfo->InstructionsToUser[0]) {
  1992. ArgArray[0] = Dll->VendorInfo->InstructionsToUser;
  1993. FixupInstructions = ParseMessageID (MSG_MIGDLL_INSTRUCTIONS_FIXUP, ArgArray);
  1994. LineBreak = TEXT("\n");
  1995. } else {
  1996. FixupInstructions = S_EMPTY;
  1997. }
  1998. LOG ((
  1999. LOG_ERROR,
  2000. (PCSTR) LogId,
  2001. Dll->WorkingDir,
  2002. Dll->ProductId,
  2003. ErrorCode,
  2004. Dll->LastFnName,
  2005. Dll->VendorInfo->CompanyName,
  2006. FixupPhone,
  2007. FixupUrl,
  2008. FixupInstructions,
  2009. LineBreak
  2010. ));
  2011. LOG ((
  2012. LOG_ERROR,
  2013. (PCSTR) PopupId,
  2014. Dll->WorkingDir,
  2015. Dll->ProductId,
  2016. ErrorCode,
  2017. Dll->LastFnName,
  2018. Dll->VendorInfo->CompanyName,
  2019. FixupPhone,
  2020. FixupUrl,
  2021. FixupInstructions,
  2022. LineBreak
  2023. ));
  2024. } else {
  2025. MYASSERT (!PopupId);
  2026. LOG ((
  2027. LOG_ERROR,
  2028. (PCSTR) LogId,
  2029. Path ? Path : S_EMPTY,
  2030. S_EMPTY,
  2031. ErrorCode,
  2032. TEXT("QueryVersion")
  2033. ));
  2034. }
  2035. }
  2036. PopError();
  2037. }
  2038. PCTSTR
  2039. pQuoteMe (
  2040. IN PCTSTR String
  2041. )
  2042. {
  2043. static TCHAR QuotedString[1024];
  2044. QuotedString[0] = TEXT('\"');
  2045. _tcssafecpy (&QuotedString[1], String, 1022);
  2046. StringCat (QuotedString, TEXT("\""));
  2047. return QuotedString;
  2048. }
  2049. BOOL
  2050. ProcessDll (
  2051. IN PMIGDLL_ENUM EnumPtr
  2052. )
  2053. /*++
  2054. Routine Description:
  2055. ProcessDll calls the Initialize9x, MigrateUser9x and MigrateSystem9x
  2056. entry points of the DLL. The DLL's migrate.inf is then processed.
  2057. ProcessDll must NOT be called more than once for the same DLL.
  2058. Arguments:
  2059. EnumPtr - Specifies the DLL to process, as enumerated by
  2060. EnumFirstMigrationDll/EnumNextMigrationDll.
  2061. Return Value:
  2062. TRUE if processing was successful, or FALSE if an error occurred.
  2063. If an error occurred, GetLastError will contain the failure. If the
  2064. error is ERROR_SUCCESS, the DLL should be abandoned. If the error
  2065. is something else, Setup should terminate.
  2066. --*/
  2067. {
  2068. CHAR DllPath[MAX_MBCHAR_PATH];
  2069. PMIGRATION_DLL_PROPS Dll;
  2070. MEMDB_ENUM e;
  2071. PSTR End;
  2072. LONG rc;
  2073. BOOL result;
  2074. Dll = EnumPtr->AllDllProps;
  2075. //
  2076. // Write the path exclusions now
  2077. //
  2078. if (!pWriteStringToEndOfInf (Dll, "\r\n[Excluded Paths]", NULL, TRUE)) {
  2079. return FALSE;
  2080. }
  2081. if (MemDbGetValueEx (
  2082. &e,
  2083. MEMDB_CATEGORY_FILEENUM,
  2084. g_ExclusionValueString,
  2085. MEMDB_FIELD_FE_PATHS
  2086. )) {
  2087. do {
  2088. End = GetEndOfStringA (e.szName);
  2089. MYASSERT (End);
  2090. End = _mbsdec2 (e.szName, End);
  2091. if (End && *End == '*') {
  2092. *End = 0;
  2093. }
  2094. if (!pWriteStringToEndOfInf (Dll, pQuoteMe (e.szName), NULL, TRUE)) {
  2095. return FALSE;
  2096. }
  2097. } while (MemDbEnumNextValue(&e));
  2098. }
  2099. if (MemDbGetValueEx (
  2100. &e,
  2101. MEMDB_CATEGORY_FILEENUM,
  2102. g_ExclusionValueString,
  2103. MEMDB_FIELD_FE_FILES
  2104. )) {
  2105. do {
  2106. if (!pWriteStringToEndOfInf (Dll, pQuoteMe (e.szName), NULL, TRUE)) {
  2107. return FALSE;
  2108. }
  2109. } while (MemDbEnumNextValue (&e));
  2110. }
  2111. //
  2112. // Make sure the migrate.inf file is closed now
  2113. //
  2114. if (Dll->MigInfAppend != INVALID_HANDLE_VALUE) {
  2115. CloseHandle (Dll->MigInfAppend);
  2116. Dll->MigInfAppend = INVALID_HANDLE_VALUE;
  2117. }
  2118. //
  2119. // Open the migrate.dll
  2120. //
  2121. wsprintf (DllPath, "%s\\migrate.dll", Dll->WorkingDir);
  2122. if (!OpenMigrationDll (DllPath, Dll->WorkingDir)) {
  2123. LOG ((LOG_ERROR, "Can't open %s", DllPath));
  2124. return FALSE;
  2125. }
  2126. result = FALSE;
  2127. __try {
  2128. //
  2129. // Call the entry points
  2130. //
  2131. if (!pProcessInitialize9x (Dll) ||
  2132. !pProcessUser9x (Dll) ||
  2133. !pProcessSystem9x (Dll) ||
  2134. !pProcessMigrateInf (Dll)
  2135. ) {
  2136. rc = GetLastError();
  2137. if (rc == RPC_S_CALL_FAILED) {
  2138. rc = ERROR_NOACCESS;
  2139. }
  2140. pMigrationDllFailedMsg (Dll, NULL, MSG_MIGDLL_FAILED_POPUP, MSG_MIGDLL_FAILED_LOG, rc);
  2141. SetLastError (ERROR_SUCCESS);
  2142. __leave;
  2143. }
  2144. TickProgressBar ();
  2145. result = TRUE;
  2146. }
  2147. __finally {
  2148. PushError();
  2149. //
  2150. // Close the DLL
  2151. //
  2152. CloseMigrationDll();
  2153. PopError();
  2154. }
  2155. return result;
  2156. }
  2157. BOOL
  2158. pProcessInitialize9x (
  2159. IN PMIGRATION_DLL_PROPS Dll
  2160. )
  2161. /*++
  2162. Routine Description:
  2163. pProcessInitialize9x calls the Initialize9x entry point of the
  2164. specified DLL.
  2165. Arguments:
  2166. Dll - Specifies the properties of the DLL to call
  2167. Return Value:
  2168. TRUE if processing was successful, or FALSE if an error occurred.
  2169. --*/
  2170. {
  2171. LONG rc;
  2172. if (CANCELLED()) {
  2173. SetLastError (ERROR_CANCELLED);
  2174. return FALSE;
  2175. }
  2176. Dll->LastFnName = "Initialize9x";
  2177. //
  2178. // Call the entry points
  2179. //
  2180. rc = CallInitialize9x (
  2181. Dll->WorkingDir,
  2182. (PCSTR) g_SourceDirList.Buf,
  2183. (PVOID) Dll->OriginalDir,
  2184. SizeOfString (Dll->OriginalDir)
  2185. );
  2186. //
  2187. // If DLL returns ERROR_NOT_INSTALLED, do not call it any further
  2188. // If DLL returns something other than ERROR_SUCCESS, abandon the DLL
  2189. //
  2190. if (rc == ERROR_NOT_INSTALLED) {
  2191. SetLastError (ERROR_SUCCESS);
  2192. return FALSE;
  2193. } else if (rc != ERROR_SUCCESS) {
  2194. SetLastError (rc);
  2195. DEBUGMSG ((DBG_MIGDLLS, "DLL failed with rc=%u", rc));
  2196. return FALSE;
  2197. }
  2198. return TRUE;
  2199. }
  2200. BOOL
  2201. pProcessUser9x (
  2202. IN PMIGRATION_DLL_PROPS Dll
  2203. )
  2204. /*++
  2205. Routine Description:
  2206. pProcessUser9x calls the MigrateUser9x for every user that will be migrated.
  2207. Arguments:
  2208. Dll - Specifies the properites of the DLL to call
  2209. Return Value:
  2210. TRUE if processing was successful, or FALSE if an error occurred.
  2211. --*/
  2212. {
  2213. USERENUM e;
  2214. LONG rc;
  2215. Dll->LastFnName = "MigrateUser9x";
  2216. //
  2217. // Enumerate all the users
  2218. //
  2219. if (EnumFirstUser (&e, ENUMUSER_ENABLE_NAME_FIX)) {
  2220. do {
  2221. if (CANCELLED()) {
  2222. SetLastError (ERROR_CANCELLED);
  2223. return FALSE;
  2224. }
  2225. if (e.AccountType & INVALID_ACCOUNT) {
  2226. continue;
  2227. }
  2228. rc = CallMigrateUser9x (
  2229. g_ParentWnd,
  2230. e.FixedUserName,
  2231. g_MigDllAnswerFile,
  2232. NULL,
  2233. 0
  2234. );
  2235. if (rc == ERROR_SUCCESS) {
  2236. Dll->WantsToRunOnNt = TRUE;
  2237. } else if (rc != ERROR_NOT_INSTALLED) {
  2238. EnumUserAbort (&e);
  2239. SetLastError (rc);
  2240. DEBUGMSG ((DBG_MIGDLLS, "DLL failed with rc=%u", rc));
  2241. return FALSE;
  2242. }
  2243. } while (EnumNextUser (&e));
  2244. }
  2245. return TRUE;
  2246. }
  2247. BOOL
  2248. pProcessSystem9x (
  2249. IN PMIGRATION_DLL_PROPS Dll
  2250. )
  2251. /*++
  2252. Routine Description:
  2253. pProcessSystem9x calls the MigrateSystem9x entry point.
  2254. Arguments:
  2255. Dll - Specifies the properties of the DLL to process
  2256. Return Value:
  2257. TRUE if processing was successful, or FALSE if an error occurred.
  2258. --*/
  2259. {
  2260. LONG rc;
  2261. if (CANCELLED()) {
  2262. SetLastError (ERROR_CANCELLED);
  2263. return FALSE;
  2264. }
  2265. Dll->LastFnName = "MigrateSystem9x";
  2266. rc = CallMigrateSystem9x (g_ParentWnd, g_MigDllAnswerFile, NULL, 0);
  2267. if (rc == ERROR_SUCCESS) {
  2268. Dll->WantsToRunOnNt = TRUE;
  2269. } else if (rc != ERROR_NOT_INSTALLED) {
  2270. SetLastError (rc);
  2271. DEBUGMSG ((DBG_MIGDLLS, "DLL failed with rc=%u", rc));
  2272. return FALSE;
  2273. }
  2274. return TRUE;
  2275. }
  2276. BOOL
  2277. pProcessMigrateInf (
  2278. IN PMIGRATION_DLL_PROPS Dll
  2279. )
  2280. /*++
  2281. Routine Description:
  2282. pProcessMigrateInf reads in all the sections of migrate.inf that a DLL might
  2283. write to and performs the actions necessary. The following sections are
  2284. supported:
  2285. [Handled] - Any file, directory or reg location will suppress
  2286. incompatibility messages associated with the handled item.
  2287. Also, any file or directory will not be touched by Setup,
  2288. and any registry key will not be copied.
  2289. [Moved] - Any file or directory marked for move will cause the rest of the
  2290. upgrade to make the correct changes, such as updating links or
  2291. replacing the old path with the new path in the registry or INI
  2292. files.
  2293. Any file marked for deletion is simply noted, and all links to the
  2294. file are also deleted.
  2295. [Incompatible Messages] - All messages are added to the report (and may be
  2296. suppressed if someone else handles the problem)
  2297. [NT Disk Space Requirements] - Any additional space needed by a migration DLL
  2298. will be added to the computations performed
  2299. by Setup
  2300. Arguments:
  2301. Dll - Specifies the properties of the DLL who owns the migrate.inf
  2302. Return Value:
  2303. TRUE if processing was successful, or FALSE if an error occurred.
  2304. --*/
  2305. {
  2306. HINF Inf;
  2307. INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
  2308. INFSTRUCT is2 = INITINFSTRUCT_POOLHANDLE;
  2309. PCSTR Object;
  2310. PCSTR ObjectType;
  2311. PCSTR Source;
  2312. PCSTR Dest;
  2313. PCSTR Size;
  2314. PCSTR Drive;
  2315. CHAR WithColonAndWack[4];
  2316. PCSTR ObjectSection;
  2317. CHAR MsgMgrContext[MAX_MBCHAR_PATH];
  2318. PSTR DisplayObjectSection;
  2319. PCSTR MigDllGroup;
  2320. BOOL HardwareSpecialCase;
  2321. PSTR p;
  2322. CHAR QuotedObjectSection[256];
  2323. PCSTR ResText;
  2324. DWORD SrcAttribs;
  2325. TREE_ENUM TreeEnum;
  2326. CHAR FixedSrc[MAX_MBCHAR_PATH];
  2327. CHAR NewDest[MAX_MBCHAR_PATH];
  2328. PCSTR OtherDevices = NULL;
  2329. PCSTR DeviceType;
  2330. PCSTR PrintDevice = NULL;
  2331. PCSTR Num;
  2332. UINT Value;
  2333. PCSTR PreDefGroup;
  2334. INT PrevChar;
  2335. //
  2336. // Open the INF
  2337. //
  2338. WritePrivateProfileString(
  2339. NULL,
  2340. NULL,
  2341. NULL,
  2342. Dll->MigrateInfPath
  2343. );
  2344. Inf = InfOpenInfFile (Dll->MigrateInfPath);
  2345. if (Inf == INVALID_HANDLE_VALUE) {
  2346. LOG ((LOG_ERROR, "Cannot open %s for processing", Dll->MigrateInfPath));
  2347. return TRUE;
  2348. }
  2349. //
  2350. // Read in the [Handled] section
  2351. //
  2352. if (InfFindFirstLine (Inf, "Handled", NULL, &is)) {
  2353. do {
  2354. Object = InfGetStringField (&is, 0);
  2355. ObjectType = InfGetStringField (&is, 1);
  2356. if (Object) {
  2357. //
  2358. // Suppress all incompatibility messages associated with the object
  2359. //
  2360. DEBUGMSG ((DBG_MIGDLLS, "%s handled %s", Dll->MigrateInfPath, Object));
  2361. HandleObject (Object, ObjectType);
  2362. }
  2363. InfResetInfStruct (&is);
  2364. } while (InfFindNextLine (&is));
  2365. }
  2366. //
  2367. // Read in the [Moved] section
  2368. //
  2369. if (InfFindFirstLine (Inf, "Moved", NULL, &is)) {
  2370. do {
  2371. Source = InfGetStringField (&is, 0);
  2372. Dest = InfGetStringField (&is, 1);
  2373. if (Source) {
  2374. StackStringCopy (FixedSrc, Source);
  2375. RemoveWackAtEnd (FixedSrc);
  2376. SrcAttribs = QuietGetFileAttributes (FixedSrc);
  2377. if (SrcAttribs != INVALID_ATTRIBUTES) {
  2378. if (Source && *Source) {
  2379. if (SrcAttribs & FILE_ATTRIBUTE_DIRECTORY) {
  2380. DEBUGMSG ((DBG_MIGDLLS, "Directory %s marked as handled because %s will move it.", Source, Dll->MigrateInfPath));
  2381. HandleObject (Source, TEXT("Directory"));
  2382. }
  2383. else {
  2384. DEBUGMSG ((DBG_MIGDLLS, "File %s marked as handled because %s will move it.", Source, Dll->MigrateInfPath));
  2385. HandleObject (Source, TEXT("File"));
  2386. }
  2387. }
  2388. if (Dest && *Dest) {
  2389. if (SrcAttribs & FILE_ATTRIBUTE_DIRECTORY) {
  2390. //
  2391. // Migration DLL will move this dir
  2392. //
  2393. DEBUGMSG ((DBG_MIGDLLS, "%s moved dir %s to %s", Dll->MigrateInfPath, Source, Dest));
  2394. if (EnumFirstFileInTree (&TreeEnum, Source, NULL, TRUE)) {
  2395. StackStringCopy (NewDest, Dest);
  2396. p = AppendWack (NewDest);
  2397. do {
  2398. RemoveOperationsFromPath (TreeEnum.FullPath, ALL_CHANGE_OPERATIONS);
  2399. MYASSERT (*TreeEnum.SubPath != '\\');
  2400. StringCopy (p, TreeEnum.SubPath);
  2401. MarkFileForMoveExternal (TreeEnum.FullPath, NewDest);
  2402. } while (EnumNextFileInTree (&TreeEnum));
  2403. }
  2404. StackStringCopy (NewDest, Dest);
  2405. RemoveWackAtEnd (NewDest);
  2406. RemoveOperationsFromPath (FixedSrc, ALL_CHANGE_OPERATIONS);
  2407. MarkFileForMoveExternal (FixedSrc, NewDest);
  2408. } else {
  2409. //
  2410. // Migration DLL will move this file
  2411. //
  2412. DEBUGMSG ((DBG_MIGDLLS, "%s moved %s to %s", Dll->MigrateInfPath, Source, Dest));
  2413. RemoveOperationsFromPath (Source, ALL_CHANGE_OPERATIONS);
  2414. MarkFileForMoveExternal (Source, Dest);
  2415. }
  2416. } else {
  2417. if (SrcAttribs & FILE_ATTRIBUTE_DIRECTORY) {
  2418. DEBUGMSG ((DBG_MIGDLLS, "%s deleted dir %s", Dll->MigrateInfPath, Source));
  2419. if (EnumFirstFileInTree (&TreeEnum, Source, NULL, TRUE)) {
  2420. do {
  2421. RemoveOperationsFromPath (TreeEnum.FullPath, ALL_CHANGE_OPERATIONS);
  2422. MarkFileForExternalDelete (TreeEnum.FullPath);
  2423. } while (EnumNextFileInTree (&TreeEnum));
  2424. }
  2425. } else {
  2426. //
  2427. // Migration DLL will delete this file
  2428. //
  2429. DEBUGMSG ((DBG_MIGDLLS, "%s deleted %s", Dll->MigrateInfPath, Source));
  2430. RemoveOperationsFromPath (Source, ALL_CHANGE_OPERATIONS);
  2431. MarkFileForExternalDelete (Source);
  2432. }
  2433. }
  2434. }
  2435. ELSE_DEBUGMSG ((
  2436. DBG_WARNING,
  2437. "Ignoring non-existent soruce in [Moved]: %s",
  2438. Source
  2439. ));
  2440. }
  2441. InfResetInfStruct (&is);
  2442. } while (InfFindNextLine (&is));
  2443. }
  2444. //
  2445. // Read in the [Incompatible Messages] section
  2446. //
  2447. if (InfFindFirstLine (Inf, "Incompatible Messages", NULL, &is)) {
  2448. OtherDevices = GetStringResource (MSG_UNKNOWN_DEVICE_CLASS);
  2449. PrintDevice = GetStringResource (MSG_PRINTERS_DEVICE_CLASS);
  2450. do {
  2451. //
  2452. // Add incompatible messages
  2453. //
  2454. ObjectSection = InfGetStringField (&is, 0);
  2455. if (!ObjectSection) {
  2456. DEBUGMSG ((DBG_ERROR, "Malformed migrate.inf. Some incompatibility messages may be missing."));
  2457. continue;
  2458. }
  2459. GetPrivateProfileString (
  2460. "Incompatible Messages",
  2461. ObjectSection,
  2462. "",
  2463. g_MessageBuf,
  2464. MAX_MESSAGE - 4,
  2465. Dll->MigrateInfPath
  2466. );
  2467. if (*g_MessageBuf == 0 && ByteCount (ObjectSection) < 250) {
  2468. wsprintf (QuotedObjectSection, TEXT("\"%s\""), ObjectSection);
  2469. GetPrivateProfileString (
  2470. "Incompatible Messages",
  2471. QuotedObjectSection,
  2472. "",
  2473. g_MessageBuf,
  2474. MAX_MESSAGE - 4,
  2475. Dll->MigrateInfPath
  2476. );
  2477. }
  2478. // Remove quote pairs, replace \n with actual line break character
  2479. for (p = g_MessageBuf ; *p ; p = _mbsinc (p)) {
  2480. PrevChar = _mbsnextc (p);
  2481. if (PrevChar == '\"' || PrevChar == '%') {
  2482. if (_mbsnextc (p + 1) == PrevChar) {
  2483. MoveMemory ((PSTR) p, p + 1, SizeOfStringA (p + 1));
  2484. }
  2485. } else if (_mbsnextc (p) == '\\') {
  2486. if (_mbsnextc (p + 1) == 'n') {
  2487. MoveMemory ((PSTR) p, p + 1, SizeOfStringA (p + 1));
  2488. *((PSTR) p) = '\r';
  2489. }
  2490. }
  2491. }
  2492. // Terminate anchor tag if DLL forgot it, harmless otherwise
  2493. StringCatA (g_MessageBuf, "</A>");
  2494. //
  2495. // Replace OS name variables
  2496. //
  2497. MappingSearchAndReplace (g_MsgVariableMap, g_MessageBuf, MAX_MESSAGE);
  2498. //
  2499. // Associate objects with the message
  2500. //
  2501. if (InfFindFirstLine (Inf, ObjectSection, NULL, &is2)) {
  2502. wsprintf (MsgMgrContext, "%s,%s", Dll->MigrateInfPath, ObjectSection);
  2503. //
  2504. // The ObjectSection specified by the migration DLL indicates
  2505. // what message group it goes in. There are four possibilities:
  2506. //
  2507. // 1. ObjectSection starts with a # and gives the group number,
  2508. // as in #1\Program Name. In this case we parse the number,
  2509. // and then put the message in the proper group.
  2510. //
  2511. // 2. ObjectSection starts with a well-defined, localized root
  2512. // name. In this case we use that name.
  2513. //
  2514. // 3. ObjectSection is in the form of \Hardware\<device>. In
  2515. // this case we put the device in the "Other devices"
  2516. // subgroup.
  2517. //
  2518. // 4. ObjectSection is in another format than above. In this
  2519. // case we put the object section into the migration DLL group.
  2520. //
  2521. DisplayObjectSection = NULL;
  2522. if (*ObjectSection == TEXT('#')) {
  2523. Value = 0;
  2524. Num = ObjectSection + 1;
  2525. while (*Num >= TEXT('0') && *Num <= TEXT('9')) {
  2526. Value = Value * 10 + (*Num - TEXT('0'));
  2527. Num++;
  2528. }
  2529. if (_tcsnextc (Num) == TEXT('\\')) {
  2530. Num++;
  2531. if (*Num) {
  2532. PreDefGroup = GetPreDefinedMessageGroupText (Value);
  2533. if (PreDefGroup) {
  2534. DisplayObjectSection = JoinText (PreDefGroup, Num);
  2535. DEBUGMSG ((
  2536. DBG_MIGDLLS,
  2537. "Pre-defined group created: %s -> %s",
  2538. ObjectSection,
  2539. DisplayObjectSection
  2540. ));
  2541. }
  2542. }
  2543. }
  2544. }
  2545. if (!DisplayObjectSection) {
  2546. if (IsPreDefinedMessageGroup (ObjectSection)) {
  2547. DisplayObjectSection = DuplicateText (ObjectSection);
  2548. MYASSERT (DisplayObjectSection);
  2549. } else {
  2550. //
  2551. // Put message in migration DLL group
  2552. //
  2553. HardwareSpecialCase = StringIMatchCharCount (
  2554. ObjectSection,
  2555. S_HARDWARE_IN_WACKS,
  2556. S_HARDWARE_CHARS
  2557. );
  2558. if (HardwareSpecialCase) {
  2559. //
  2560. // Hack -- if this is the printer migration DLL,
  2561. // then use Printers instead of Other Devices.
  2562. //
  2563. p = (PSTR) _tcsistr (Dll->OriginalDir, TEXT("\\print"));
  2564. if (p && (*(p + ARRAYSIZE(TEXT("\\print"))) == 0)) {
  2565. DeviceType = PrintDevice;
  2566. } else {
  2567. DeviceType = OtherDevices;
  2568. }
  2569. MigDllGroup = BuildMessageGroup (
  2570. MSG_INCOMPATIBLE_HARDWARE_ROOT,
  2571. MSG_INCOMPATIBLE_HARDWARE_PNP_SUBGROUP,
  2572. DeviceType
  2573. );
  2574. ObjectSection += S_HARDWARE_CHARS;
  2575. MYASSERT (MigDllGroup);
  2576. } else {
  2577. ResText = GetStringResource (MSG_MIGDLL_ROOT);
  2578. MYASSERT (ResText);
  2579. MigDllGroup = DuplicateText (ResText);
  2580. FreeStringResource (ResText);
  2581. MYASSERT (MigDllGroup);
  2582. }
  2583. DisplayObjectSection = AllocText (SizeOfStringA (MigDllGroup) +
  2584. SizeOfStringA (ObjectSection) +
  2585. SizeOfStringA (Dll->ProductId)
  2586. );
  2587. MYASSERT (DisplayObjectSection);
  2588. if (HardwareSpecialCase) {
  2589. wsprintf (DisplayObjectSection, "%s\\%s", MigDllGroup, ObjectSection);
  2590. } else if (StringIMatch (Dll->ProductId, ObjectSection)) {
  2591. wsprintf (DisplayObjectSection, "%s\\%s", MigDllGroup, Dll->ProductId);
  2592. } else {
  2593. wsprintf (DisplayObjectSection, "%s\\%s\\%s", MigDllGroup, Dll->ProductId, ObjectSection);
  2594. }
  2595. FreeText (MigDllGroup);
  2596. }
  2597. }
  2598. MsgMgr_ContextMsg_Add (
  2599. MsgMgrContext,
  2600. DisplayObjectSection,
  2601. g_MessageBuf
  2602. );
  2603. FreeText (DisplayObjectSection);
  2604. do {
  2605. Object = InfGetStringField (&is2, 0);
  2606. if (Object) {
  2607. MsgMgr_LinkObjectWithContext (
  2608. MsgMgrContext,
  2609. Object
  2610. );
  2611. }
  2612. ELSE_DEBUGMSG ((DBG_WHOOPS, "pProcessMigrateInf: InfGetStringField failed"));
  2613. if (Object == NULL) {
  2614. LOG ((LOG_ERROR, "Failed to get string field from migration.dll migrate.inf."));
  2615. }
  2616. } while (InfFindNextLine (&is2));
  2617. InfResetInfStruct (&is2);
  2618. }
  2619. ELSE_DEBUGMSG ((DBG_ERROR, "Object section %s not found", ObjectSection));
  2620. InfResetInfStruct (&is);
  2621. } while (InfFindNextLine (&is));
  2622. if (OtherDevices) {
  2623. FreeStringResource (OtherDevices);
  2624. }
  2625. if (PrintDevice) {
  2626. FreeStringResource (PrintDevice);
  2627. }
  2628. }
  2629. //
  2630. // Read in the [NT Disk Space Requirements] section
  2631. //
  2632. if (InfFindFirstLine (Inf, "NT Disk Space Requirements", NULL, &is)) {
  2633. do {
  2634. Drive = InfGetStringField (&is, 0);
  2635. if (!Drive) {
  2636. DEBUGMSG ((DBG_ERROR, "Could not read some NT Disk Space Requirements from migrate.inf"));
  2637. continue;
  2638. }
  2639. WithColonAndWack[0] = Drive[0];
  2640. WithColonAndWack[1] = ':';
  2641. WithColonAndWack[2] = '\\';
  2642. WithColonAndWack[3] = 0;
  2643. Size = InfGetStringField (&is, 1);
  2644. UseSpace (WithColonAndWack, (LONGLONG) atoi (Size));
  2645. InfResetInfStruct (&is);
  2646. } while (InfFindNextLine (&is));
  2647. }
  2648. InfCleanUpInfStruct (&is);
  2649. InfCleanUpInfStruct (&is2);
  2650. InfCloseInfFile (Inf);
  2651. return TRUE;
  2652. }