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.

3593 lines
87 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 "migdllp.h"
  14. #include "plugin.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 = LoadSystemLibrary ("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 Tchars;
  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 = TcharCount (g_TempDir);
  517. }
  518. //
  519. // Determine if path is a containment case of the setup temp dir
  520. //
  521. Tchars = min (TcharCount (Path), TempDirLen);
  522. if (StringIMatchTcharCount (Path, g_TempDir, Tchars)) {
  523. ch = _tcsnextc (Path + Tchars);
  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 (!ClusterSize) {
  1481. ClusterSize = 4096;
  1482. }
  1483. if (EnumFirstFileInTree (&e, PathSpec, NULL, FALSE)) {
  1484. do {
  1485. //
  1486. // We assume the migrate.dll will never pack more than 4G of
  1487. // files.
  1488. //
  1489. if (!e.Directory) {
  1490. MYASSERT (Size + e.FindData->nFileSizeLow >= Size);
  1491. MYASSERT (!e.FindData->nFileSizeHigh);
  1492. Size += e.FindData->nFileSizeLow + ClusterSize -
  1493. (e.FindData->nFileSizeLow % ClusterSize);
  1494. } else {
  1495. // Add a fudge factor here, we don't know the exact size
  1496. e.Directory += ClusterSize;
  1497. }
  1498. } while (EnumNextFileInTree (&e));
  1499. }
  1500. return Size;
  1501. }
  1502. BOOL
  1503. pEnumMigrationDllWorker (
  1504. IN OUT PMIGDLL_ENUM EnumPtr,
  1505. IN PMIGRATION_DLL_PROPS Props
  1506. )
  1507. /*++
  1508. Routine Description:
  1509. pEnumMigrationDllWorker is a common routine that completes the
  1510. enumeration of a DLL. It fills in the EnumPtr data members
  1511. and returns TRUE. Also, it screens out invalid DLL structures
  1512. (those that have been disabled by RemoveDllFromList).
  1513. Arguments:
  1514. EnumPtr - Specifies the partially completed enumeration structure,
  1515. receives the complete information.
  1516. Props - Specifies the properties of the item that was enumerated.
  1517. Return Value:
  1518. FALSE if all remaining of the properties are invalid, or TRUE otherwise
  1519. --*/
  1520. {
  1521. while (Props && Props->Id == -1) {
  1522. Props = Props->Next;
  1523. }
  1524. if (!Props) {
  1525. return FALSE;
  1526. }
  1527. EnumPtr->ProductId = Props->ProductId;
  1528. EnumPtr->VendorInfo = Props->VendorInfo;
  1529. EnumPtr->CurrentDir = Props->WorkingDir;
  1530. EnumPtr->AllDllProps = Props;
  1531. EnumPtr->Id = Props->Id;
  1532. return TRUE;
  1533. }
  1534. BOOL
  1535. EnumFirstMigrationDll (
  1536. OUT PMIGDLL_ENUM EnumPtr
  1537. )
  1538. /*++
  1539. Routine Description:
  1540. EnumFirstMigrationDll begins an enumeration of migration DLLs.
  1541. Callers can then use the enumerated information to fill list
  1542. boxes or any other processing.
  1543. Arguments:
  1544. EnumPtr - Receives the first enumerated DLL's properties
  1545. Return Value:
  1546. TRUE if a DLL was enumerated, or FALSE if not.
  1547. --*/
  1548. {
  1549. ZeroMemory (EnumPtr, sizeof (MIGDLL_ENUM));
  1550. return pEnumMigrationDllWorker (EnumPtr, g_HeadDll);
  1551. }
  1552. BOOL
  1553. EnumNextMigrationDll (
  1554. IN OUT PMIGDLL_ENUM EnumPtr
  1555. )
  1556. /*++
  1557. Routine Description:
  1558. EnumNextMigrationDll continues enumeration started by EnumFirstMigrationDll.
  1559. Arguments:
  1560. EnumPtr - Specifies the last enumerated item, receives the next enumerated
  1561. item.
  1562. Return Value:
  1563. TRUE if another DLL was enumerated, or FALSE if not.
  1564. --*/
  1565. {
  1566. if (EnumPtr->AllDllProps->Next) {
  1567. return pEnumMigrationDllWorker (EnumPtr, EnumPtr->AllDllProps->Next);
  1568. }
  1569. return FALSE;
  1570. }
  1571. BOOL
  1572. pAddDllToList (
  1573. IN PCSTR MediaDir,
  1574. IN PCSTR WorkingDir,
  1575. IN PCSTR ProductId,
  1576. IN UINT Version,
  1577. IN PCSTR ExeNamesBuf, OPTIONAL
  1578. IN PVENDORINFO VendorInfo
  1579. )
  1580. /*++
  1581. Routine Description:
  1582. pAddDllToList adds the supplied properties to the private data structures
  1583. used to organize the migration DLLs. The ProductId is placed in a string
  1584. table, the ExeNamesBuf is put in a list of files, and the rest of the
  1585. members are duplciated into a memory pool.
  1586. Arguments:
  1587. MediaDir - Specifies the directory containing the migration DLL
  1588. WorkingDir - Specifies the working directory assigned to the DLL on local
  1589. storage
  1590. ProductId - Specifies the display name of the migration DLL
  1591. Version - Specifies the DLL's version number
  1592. ExeNamesBuf - Specifies a multi-sz listing file names that need to
  1593. be located
  1594. VendorInfo - Specifies the vendor info provided by the migration DLL
  1595. Return Value:
  1596. TRUE if processing was successful, or FALSE if an error occurred.
  1597. --*/
  1598. {
  1599. PMIGRATION_DLL_PROPS Props;
  1600. CHAR MigrateInfPath[MAX_MBCHAR_PATH];
  1601. PCSTR p;
  1602. HANDLE File;
  1603. //
  1604. // Copy the DLL into the working directory
  1605. //
  1606. if (!CopyTree (
  1607. MediaDir,
  1608. WorkingDir,
  1609. 0,
  1610. COPYTREE_DOCOPY | COPYTREE_NOOVERWRITE,
  1611. ENUM_ALL_LEVELS,
  1612. FILTER_ALL,
  1613. NULL,
  1614. NULL,
  1615. NULL
  1616. )) {
  1617. LOG ((LOG_ERROR, "Error while copying files for migration.dll."));
  1618. return FALSE;
  1619. }
  1620. //
  1621. // Generate a new DLL struct
  1622. //
  1623. Props = (PMIGRATION_DLL_PROPS) PoolMemGetMemory (g_MigDllPool, sizeof (MIGRATION_DLL_PROPS));
  1624. //
  1625. // Link props to list of all DLLs
  1626. //
  1627. Props->Next = g_HeadDll;
  1628. g_HeadDll = Props;
  1629. //
  1630. // Add product ID to string table for quick lookup
  1631. //
  1632. Props->Id = pSetupStringTableAddStringEx (
  1633. g_DllTable,
  1634. (PTSTR) ProductId,
  1635. STRTAB_CASE_INSENSITIVE|STRTAB_NEW_EXTRADATA,
  1636. &Props,
  1637. sizeof (Props)
  1638. );
  1639. if (Props->Id == -1) {
  1640. LOG ((LOG_ERROR, "Error adding migration.dll to list."));
  1641. return FALSE;
  1642. }
  1643. //
  1644. // Fill in the rest of the DLL properties
  1645. //
  1646. Props->ProductId = PoolMemDuplicateString (g_MigDllPool, ProductId);
  1647. Props->VendorInfo = (PVENDORINFO) PoolMemDuplicateMemory (g_MigDllPool, (PBYTE) VendorInfo, sizeof (VENDORINFO));
  1648. Props->WorkingDir = PoolMemDuplicateString (g_MigDllPool, WorkingDir);
  1649. Props->Version = Version;
  1650. Props->OriginalDir = PoolMemDuplicateString (g_MigDllPool, MediaDir);
  1651. wsprintf (MigrateInfPath, "%s\\migrate.inf", Props->WorkingDir);
  1652. Props->MigrateInfPath = PoolMemDuplicateString (g_MigDllPool, MigrateInfPath);
  1653. Props->WantsToRunOnNt = FALSE; // MigrateUser9x or MigrateSystem9x must return success for this to be TRUE
  1654. Props->MigInfAppend = INVALID_HANDLE_VALUE;
  1655. //
  1656. // Dump vendor info to log
  1657. //
  1658. LOG ((
  1659. LOG_INFORMATION,
  1660. "Upgrade Pack: %s\n"
  1661. "Version: %u\n"
  1662. "Company Name: %s\n"
  1663. "Support Number: %s\n"
  1664. "Support URL: %s\n"
  1665. "Instructions: %s\n",
  1666. Props->ProductId,
  1667. Props->Version,
  1668. VendorInfo->CompanyName,
  1669. VendorInfo->SupportNumber,
  1670. VendorInfo->SupportUrl,
  1671. VendorInfo->InstructionsToUser
  1672. ));
  1673. //
  1674. // Add all search files to string table
  1675. //
  1676. p = ExeNamesBuf;
  1677. if (p) {
  1678. while (*p) {
  1679. pAddFileToSearchTable (p, Props);
  1680. p = GetEndOfStringA (p) + 1;
  1681. }
  1682. }
  1683. //
  1684. // Copy migrate.inf to DLL dir
  1685. //
  1686. SetFileAttributes (Props->MigrateInfPath, FILE_ATTRIBUTE_NORMAL);
  1687. CopyFile (g_MigrateInfTemplate, Props->MigrateInfPath, FALSE);
  1688. File = CreateFile (Props->MigrateInfPath, GENERIC_READ|GENERIC_WRITE, 0, NULL,
  1689. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1690. if (File != INVALID_HANDLE_VALUE) {
  1691. SetFilePointer (File, 0, NULL, FILE_END);
  1692. WriteFileString (File, TEXT("\r\n; "));
  1693. WriteFileString (File, Props->ProductId);
  1694. WriteFileString (File, TEXT("\r\n"));
  1695. CloseHandle (File);
  1696. } else {
  1697. LOG ((LOG_ERROR, "Cannot open %s", Props->MigrateInfPath));
  1698. }
  1699. g_MigDllsAlive++;
  1700. return TRUE;
  1701. }
  1702. VOID
  1703. RemoveDllFromList (
  1704. IN LONG ItemId
  1705. )
  1706. /*++
  1707. Routine Description:
  1708. RemoveDllFromList disables the data structures for the specified DLL and
  1709. removes it from local storage.
  1710. Arguments:
  1711. ItemId - Specifies the ID of the migration DLL to remove
  1712. Return Value:
  1713. none
  1714. --*/
  1715. {
  1716. PMIGRATION_DLL_PROPS Prev, This;
  1717. PMIGRATION_DLL_PROPS Props;
  1718. Props = pFindMigrationDllById (ItemId);
  1719. if (!Props) {
  1720. DEBUGMSG ((DBG_WHOOPS, "Cannot remove migration DLL id %i", ItemId));
  1721. return;
  1722. }
  1723. //
  1724. // Delete the linkage
  1725. //
  1726. Prev = NULL;
  1727. This = g_HeadDll;
  1728. while (This && This != Props) {
  1729. Prev = This;
  1730. This = This->Next;
  1731. }
  1732. if (Prev) {
  1733. Prev->Next = Props->Next;
  1734. } else {
  1735. g_HeadDll = Props->Next;
  1736. }
  1737. //
  1738. // Delete the string table entry by making the item data NULL
  1739. //
  1740. This = NULL;
  1741. pSetupStringTableSetExtraData (
  1742. g_DllTable,
  1743. ItemId,
  1744. &This,
  1745. sizeof (This)
  1746. );
  1747. //
  1748. // Set Id to -1 so any search files are ignored
  1749. //
  1750. Props->Id = -1;
  1751. pDestroyWorkingDir (Props->WorkingDir);
  1752. g_MigDllsAlive--;
  1753. }
  1754. BOOL
  1755. pAddFileToSearchTable (
  1756. IN PCSTR File,
  1757. IN PMIGRATION_DLL_PROPS Props
  1758. )
  1759. /*++
  1760. Routine Description:
  1761. pAddFileToSearchTable adds the specified file name to the global lookup
  1762. table used to quickly find the DLL (or DLLs) that want the location
  1763. of the file.
  1764. Arguments:
  1765. File - Specifies the long file name of the file to find
  1766. Props - Specifies the properties of the DLL that wants the location of
  1767. File
  1768. Return Value:
  1769. TRUE if processing was successful, or FALSE if an error occurred.
  1770. --*/
  1771. {
  1772. PFILETOFIND IndexedFile;
  1773. PFILETOFIND NewFile;
  1774. LONG rc;
  1775. LONG Offset;
  1776. //
  1777. // Allocate a new file struct
  1778. //
  1779. NewFile = (PFILETOFIND) PoolMemGetMemory (g_MigDllPool, sizeof (FILETOFIND));
  1780. if (!NewFile) {
  1781. return FALSE;
  1782. }
  1783. NewFile->Next = NULL;
  1784. NewFile->Dll = Props;
  1785. //
  1786. // Does a struct already exist in string table?
  1787. //
  1788. Offset = pSetupStringTableLookUpStringEx (
  1789. g_DllFileTable,
  1790. (PTSTR) File,
  1791. STRTAB_CASE_INSENSITIVE,
  1792. &IndexedFile,
  1793. sizeof (IndexedFile)
  1794. );
  1795. if (Offset == -1) {
  1796. //
  1797. // No, add it now
  1798. //
  1799. rc = pSetupStringTableAddStringEx (
  1800. g_DllFileTable,
  1801. (PTSTR) File,
  1802. STRTAB_CASE_INSENSITIVE,
  1803. &NewFile,
  1804. sizeof (NewFile)
  1805. );
  1806. } else {
  1807. //
  1808. // Yes, put it at the head of the list
  1809. //
  1810. rc = pSetupStringTableSetExtraData (
  1811. g_DllFileTable,
  1812. Offset,
  1813. &NewFile,
  1814. sizeof (NewFile)
  1815. );
  1816. IndexedFile->Next = NewFile;
  1817. }
  1818. return rc != -1;
  1819. }
  1820. BOOL
  1821. pWriteStringToEndOfInf (
  1822. IN OUT PMIGRATION_DLL_PROPS Dll,
  1823. IN PCSTR String,
  1824. IN PCSTR HeaderString, OPTIONAL
  1825. IN BOOL WriteLineFeed
  1826. )
  1827. /*++
  1828. Routine Description:
  1829. pWriteStringToEndOfInf writes the specified string to migrate.inf.
  1830. This routine also opens migrate.inf if it has not already been
  1831. opened.
  1832. If HeaderString is provided and migrate.inf needs to be opened,
  1833. the header string is written to the file, ahead of String.
  1834. Arguments:
  1835. Dll - Specifies the DLL associated with the migrate.inf
  1836. String - Specifies the string to write
  1837. HeaderString - Specifies text that is written when migrate.inf is
  1838. opened for writing for the first time.
  1839. WriteLineFeed - Specifies TRUE if a \r\n sequence should be written
  1840. after String, or FALSE if not.
  1841. Return Value:
  1842. TRUE if processing was successful, or FALSE if an error occurred.
  1843. --*/
  1844. {
  1845. if (Dll->MigInfAppend == INVALID_HANDLE_VALUE) {
  1846. //
  1847. // Flush the profile APIs
  1848. //
  1849. WritePrivateProfileString(
  1850. NULL,
  1851. NULL,
  1852. NULL,
  1853. Dll->MigrateInfPath
  1854. );
  1855. //
  1856. // Open the file for writing
  1857. //
  1858. Dll->MigInfAppend = CreateFile (
  1859. Dll->MigrateInfPath,
  1860. GENERIC_WRITE,
  1861. 0,
  1862. NULL,
  1863. OPEN_ALWAYS,
  1864. FILE_ATTRIBUTE_NORMAL,
  1865. NULL
  1866. );
  1867. } else {
  1868. HeaderString = NULL;
  1869. }
  1870. if (Dll->MigInfAppend == INVALID_HANDLE_VALUE) {
  1871. LOG ((LOG_ERROR, "Cannot open %s", Dll->MigrateInfPath));
  1872. return FALSE;
  1873. }
  1874. SetFilePointer (Dll->MigInfAppend, 0, NULL, FILE_END);
  1875. if (HeaderString) {
  1876. if (!WriteFileString (Dll->MigInfAppend, HeaderString)) {
  1877. return FALSE;
  1878. }
  1879. }
  1880. if (!WriteFileString (Dll->MigInfAppend, String)) {
  1881. return FALSE;
  1882. }
  1883. if (WriteLineFeed) {
  1884. if (!WriteFileString (Dll->MigInfAppend, "\r\n")) {
  1885. return FALSE;
  1886. }
  1887. }
  1888. return TRUE;
  1889. }
  1890. BOOL
  1891. UpdateFileSearch (
  1892. IN PCSTR FullFileSpec,
  1893. IN PCSTR FileOnly
  1894. )
  1895. /*++
  1896. Routine Description:
  1897. UpdateFileSearch is called for every file on the machine being upgraded,
  1898. and any file that the DLL wants the location file will receive its path
  1899. in the DLL's migrate.inf.
  1900. Arguments:
  1901. FullFileSpec - specifies the full path to the file, in long name format
  1902. FileOnly - Specifies only the file name and must match the file in
  1903. FullFileSpec.
  1904. Return Value:
  1905. TRUE if processing was successful, or FALSE if an error occurred.
  1906. --*/
  1907. {
  1908. PFILETOFIND FileWanted;
  1909. LONG rc;
  1910. //
  1911. // Look in string table for an indexed file, and if found, enumerate
  1912. // all the DLLs that want to know where the file is.
  1913. //
  1914. rc = pSetupStringTableLookUpStringEx (
  1915. g_DllFileTable,
  1916. (PTSTR) FileOnly,
  1917. STRTAB_CASE_INSENSITIVE,
  1918. &FileWanted,
  1919. sizeof (FileWanted)
  1920. );
  1921. if (rc == -1) {
  1922. return TRUE;
  1923. }
  1924. while (FileWanted) {
  1925. if (FileWanted->Dll->Id != -1) {
  1926. //
  1927. // Append path to the end of the file
  1928. //
  1929. if (!pWriteStringToEndOfInf (
  1930. FileWanted->Dll,
  1931. FullFileSpec,
  1932. "\r\n[Migration Paths]\r\n",
  1933. TRUE
  1934. )) {
  1935. return FALSE;
  1936. }
  1937. }
  1938. FileWanted = FileWanted->Next;
  1939. }
  1940. return TRUE;
  1941. }
  1942. VOID
  1943. pMigrationDllFailedMsg (
  1944. IN PMIGRATION_DLL_PROPS Dll, OPTIONAL
  1945. IN PCSTR Path, OPTIONAL
  1946. IN UINT PopupId, OPTIONAL
  1947. IN UINT LogId, OPTIONAL
  1948. IN LONG rc
  1949. )
  1950. /*++
  1951. Routine Description:
  1952. pMigrationDllFailedMsg presents a popup for DLLs that fail to run,
  1953. and also logs the failure to setuperr.log.
  1954. The system's last error is preserved. Also, no output is generated
  1955. if the user has chosen to cancel or if rc is ERROR_SUCCESS.
  1956. Arguments:
  1957. Dll - Specifies the DLL that failed. If Dll is not provided, PopupId
  1958. must be zero.
  1959. Path - Specifies the path to the DLL media
  1960. PopupId - Specifies the message ID for the popup dialog box
  1961. LogId - Specifies the message ID for the log
  1962. rc - Specifies the failure code
  1963. Return Value:
  1964. None.
  1965. --*/
  1966. {
  1967. CHAR ErrorCode[16];
  1968. PCTSTR FixupPhone;
  1969. PCTSTR FixupUrl;
  1970. PCTSTR FixupInstructions;
  1971. PCTSTR LineBreak = S_EMPTY;
  1972. PCTSTR ArgArray[1];
  1973. PushError();
  1974. if (!CANCELLED() && rc != ERROR_SUCCESS && rc != ERROR_CANCELLED) {
  1975. wsprintf (ErrorCode, "%u", rc);
  1976. if (Dll) {
  1977. //
  1978. // Generate fixup strings
  1979. //
  1980. if (Dll->VendorInfo->SupportNumber[0]) {
  1981. ArgArray[0] = Dll->VendorInfo->SupportNumber;
  1982. FixupPhone = ParseMessageID (MSG_MIGDLL_SUPPORT_PHONE_FIXUP, ArgArray);
  1983. LineBreak = TEXT("\n");
  1984. } else {
  1985. FixupPhone = S_EMPTY;
  1986. }
  1987. if (Dll->VendorInfo->SupportUrl[0]) {
  1988. ArgArray[0] = Dll->VendorInfo->SupportUrl;
  1989. FixupUrl = ParseMessageID (MSG_MIGDLL_SUPPORT_URL_FIXUP, ArgArray);
  1990. LineBreak = TEXT("\n");
  1991. } else {
  1992. FixupUrl = S_EMPTY;
  1993. }
  1994. if (Dll->VendorInfo->InstructionsToUser[0]) {
  1995. ArgArray[0] = Dll->VendorInfo->InstructionsToUser;
  1996. FixupInstructions = ParseMessageID (MSG_MIGDLL_INSTRUCTIONS_FIXUP, ArgArray);
  1997. LineBreak = TEXT("\n");
  1998. } else {
  1999. FixupInstructions = S_EMPTY;
  2000. }
  2001. LOG ((
  2002. LOG_ERROR,
  2003. (PCSTR) LogId,
  2004. Dll->WorkingDir,
  2005. Dll->ProductId,
  2006. ErrorCode,
  2007. Dll->LastFnName,
  2008. Dll->VendorInfo->CompanyName,
  2009. FixupPhone,
  2010. FixupUrl,
  2011. FixupInstructions,
  2012. LineBreak
  2013. ));
  2014. LOG ((
  2015. LOG_ERROR,
  2016. (PCSTR) PopupId,
  2017. Dll->WorkingDir,
  2018. Dll->ProductId,
  2019. ErrorCode,
  2020. Dll->LastFnName,
  2021. Dll->VendorInfo->CompanyName,
  2022. FixupPhone,
  2023. FixupUrl,
  2024. FixupInstructions,
  2025. LineBreak
  2026. ));
  2027. } else {
  2028. MYASSERT (!PopupId);
  2029. LOG ((
  2030. LOG_ERROR,
  2031. (PCSTR) LogId,
  2032. Path ? Path : S_EMPTY,
  2033. S_EMPTY,
  2034. ErrorCode,
  2035. TEXT("QueryVersion")
  2036. ));
  2037. }
  2038. }
  2039. PopError();
  2040. }
  2041. PCTSTR
  2042. pQuoteMe (
  2043. IN PCTSTR String
  2044. )
  2045. {
  2046. static TCHAR QuotedString[1024];
  2047. QuotedString[0] = TEXT('\"');
  2048. _tcssafecpy (&QuotedString[1], String, 1022);
  2049. StringCat (QuotedString, TEXT("\""));
  2050. return QuotedString;
  2051. }
  2052. BOOL
  2053. ProcessDll (
  2054. IN PMIGDLL_ENUM EnumPtr
  2055. )
  2056. /*++
  2057. Routine Description:
  2058. ProcessDll calls the Initialize9x, MigrateUser9x and MigrateSystem9x
  2059. entry points of the DLL. The DLL's migrate.inf is then processed.
  2060. ProcessDll must NOT be called more than once for the same DLL.
  2061. Arguments:
  2062. EnumPtr - Specifies the DLL to process, as enumerated by
  2063. EnumFirstMigrationDll/EnumNextMigrationDll.
  2064. Return Value:
  2065. TRUE if processing was successful, or FALSE if an error occurred.
  2066. If an error occurred, GetLastError will contain the failure. If the
  2067. error is ERROR_SUCCESS, the DLL should be abandoned. If the error
  2068. is something else, Setup should terminate.
  2069. --*/
  2070. {
  2071. CHAR DllPath[MAX_MBCHAR_PATH];
  2072. PMIGRATION_DLL_PROPS Dll;
  2073. MEMDB_ENUM e;
  2074. PSTR End;
  2075. LONG rc;
  2076. BOOL result;
  2077. Dll = EnumPtr->AllDllProps;
  2078. //
  2079. // Write the path exclusions now
  2080. //
  2081. if (!pWriteStringToEndOfInf (Dll, "\r\n[Excluded Paths]", NULL, TRUE)) {
  2082. return FALSE;
  2083. }
  2084. if (MemDbGetValueEx (
  2085. &e,
  2086. MEMDB_CATEGORY_FILEENUM,
  2087. g_ExclusionValueString,
  2088. MEMDB_FIELD_FE_PATHS
  2089. )) {
  2090. do {
  2091. End = GetEndOfStringA (e.szName);
  2092. MYASSERT (End);
  2093. End = our_mbsdec (e.szName, End);
  2094. if (End && *End == '*') {
  2095. *End = 0;
  2096. }
  2097. if (!pWriteStringToEndOfInf (Dll, pQuoteMe (e.szName), NULL, TRUE)) {
  2098. return FALSE;
  2099. }
  2100. } while (MemDbEnumNextValue(&e));
  2101. }
  2102. if (MemDbGetValueEx (
  2103. &e,
  2104. MEMDB_CATEGORY_FILEENUM,
  2105. g_ExclusionValueString,
  2106. MEMDB_FIELD_FE_FILES
  2107. )) {
  2108. do {
  2109. if (!pWriteStringToEndOfInf (Dll, pQuoteMe (e.szName), NULL, TRUE)) {
  2110. return FALSE;
  2111. }
  2112. } while (MemDbEnumNextValue (&e));
  2113. }
  2114. //
  2115. // Make sure the migrate.inf file is closed now
  2116. //
  2117. if (Dll->MigInfAppend != INVALID_HANDLE_VALUE) {
  2118. CloseHandle (Dll->MigInfAppend);
  2119. Dll->MigInfAppend = INVALID_HANDLE_VALUE;
  2120. }
  2121. //
  2122. // Open the migrate.dll
  2123. //
  2124. wsprintf (DllPath, "%s\\migrate.dll", Dll->WorkingDir);
  2125. if (!OpenMigrationDll (DllPath, Dll->WorkingDir)) {
  2126. LOG ((LOG_ERROR, "Can't open %s", DllPath));
  2127. return FALSE;
  2128. }
  2129. result = FALSE;
  2130. __try {
  2131. //
  2132. // Call the entry points
  2133. //
  2134. if (!pProcessInitialize9x (Dll) ||
  2135. !pProcessUser9x (Dll) ||
  2136. !pProcessSystem9x (Dll) ||
  2137. !pProcessMigrateInf (Dll)
  2138. ) {
  2139. rc = GetLastError();
  2140. if (rc == RPC_S_CALL_FAILED) {
  2141. rc = ERROR_NOACCESS;
  2142. }
  2143. pMigrationDllFailedMsg (Dll, NULL, MSG_MIGDLL_FAILED_POPUP, MSG_MIGDLL_FAILED_LOG, rc);
  2144. SetLastError (ERROR_SUCCESS);
  2145. __leave;
  2146. }
  2147. TickProgressBar ();
  2148. result = TRUE;
  2149. }
  2150. __finally {
  2151. PushError();
  2152. //
  2153. // Close the DLL
  2154. //
  2155. CloseMigrationDll();
  2156. PopError();
  2157. }
  2158. return result;
  2159. }
  2160. BOOL
  2161. pProcessInitialize9x (
  2162. IN PMIGRATION_DLL_PROPS Dll
  2163. )
  2164. /*++
  2165. Routine Description:
  2166. pProcessInitialize9x calls the Initialize9x entry point of the
  2167. specified DLL.
  2168. Arguments:
  2169. Dll - Specifies the properties of the DLL to call
  2170. Return Value:
  2171. TRUE if processing was successful, or FALSE if an error occurred.
  2172. --*/
  2173. {
  2174. LONG rc;
  2175. if (CANCELLED()) {
  2176. SetLastError (ERROR_CANCELLED);
  2177. return FALSE;
  2178. }
  2179. Dll->LastFnName = "Initialize9x";
  2180. //
  2181. // Call the entry points
  2182. //
  2183. rc = CallInitialize9x (
  2184. Dll->WorkingDir,
  2185. (PCSTR) g_SourceDirList.Buf,
  2186. (PVOID) Dll->OriginalDir,
  2187. SizeOfString (Dll->OriginalDir)
  2188. );
  2189. //
  2190. // If DLL returns ERROR_NOT_INSTALLED, do not call it any further
  2191. // If DLL returns something other than ERROR_SUCCESS, abandon the DLL
  2192. //
  2193. if (rc == ERROR_NOT_INSTALLED) {
  2194. SetLastError (ERROR_SUCCESS);
  2195. return FALSE;
  2196. } else if (rc != ERROR_SUCCESS) {
  2197. SetLastError (rc);
  2198. DEBUGMSG ((DBG_MIGDLLS, "DLL failed with rc=%u", rc));
  2199. return FALSE;
  2200. }
  2201. return TRUE;
  2202. }
  2203. BOOL
  2204. pProcessUser9x (
  2205. IN PMIGRATION_DLL_PROPS Dll
  2206. )
  2207. /*++
  2208. Routine Description:
  2209. pProcessUser9x calls the MigrateUser9x for every user that will be migrated.
  2210. Arguments:
  2211. Dll - Specifies the properites of the DLL to call
  2212. Return Value:
  2213. TRUE if processing was successful, or FALSE if an error occurred.
  2214. --*/
  2215. {
  2216. USERENUM e;
  2217. LONG rc;
  2218. Dll->LastFnName = "MigrateUser9x";
  2219. //
  2220. // Enumerate all the users
  2221. //
  2222. if (EnumFirstUser (&e, ENUMUSER_ENABLE_NAME_FIX)) {
  2223. do {
  2224. if (CANCELLED()) {
  2225. SetLastError (ERROR_CANCELLED);
  2226. return FALSE;
  2227. }
  2228. if (e.AccountType & INVALID_ACCOUNT) {
  2229. continue;
  2230. }
  2231. rc = CallMigrateUser9x (
  2232. g_ParentWnd,
  2233. e.FixedUserName,
  2234. g_MigDllAnswerFile,
  2235. NULL,
  2236. 0
  2237. );
  2238. if (rc == ERROR_SUCCESS) {
  2239. Dll->WantsToRunOnNt = TRUE;
  2240. } else if (rc != ERROR_NOT_INSTALLED) {
  2241. EnumUserAbort (&e);
  2242. SetLastError (rc);
  2243. DEBUGMSG ((DBG_MIGDLLS, "DLL failed with rc=%u", rc));
  2244. return FALSE;
  2245. }
  2246. } while (EnumNextUser (&e));
  2247. }
  2248. return TRUE;
  2249. }
  2250. BOOL
  2251. pProcessSystem9x (
  2252. IN PMIGRATION_DLL_PROPS Dll
  2253. )
  2254. /*++
  2255. Routine Description:
  2256. pProcessSystem9x calls the MigrateSystem9x entry point.
  2257. Arguments:
  2258. Dll - Specifies the properties of the DLL to process
  2259. Return Value:
  2260. TRUE if processing was successful, or FALSE if an error occurred.
  2261. --*/
  2262. {
  2263. LONG rc;
  2264. if (CANCELLED()) {
  2265. SetLastError (ERROR_CANCELLED);
  2266. return FALSE;
  2267. }
  2268. Dll->LastFnName = "MigrateSystem9x";
  2269. rc = CallMigrateSystem9x (g_ParentWnd, g_MigDllAnswerFile, NULL, 0);
  2270. if (rc == ERROR_SUCCESS) {
  2271. Dll->WantsToRunOnNt = TRUE;
  2272. } else if (rc != ERROR_NOT_INSTALLED) {
  2273. SetLastError (rc);
  2274. DEBUGMSG ((DBG_MIGDLLS, "DLL failed with rc=%u", rc));
  2275. return FALSE;
  2276. }
  2277. return TRUE;
  2278. }
  2279. BOOL
  2280. pProcessMigrateInf (
  2281. IN PMIGRATION_DLL_PROPS Dll
  2282. )
  2283. /*++
  2284. Routine Description:
  2285. pProcessMigrateInf reads in all the sections of migrate.inf that a DLL might
  2286. write to and performs the actions necessary. The following sections are
  2287. supported:
  2288. [Handled] - Any file, directory or reg location will suppress
  2289. incompatibility messages associated with the handled item.
  2290. Also, any file or directory will not be touched by Setup,
  2291. and any registry key will not be copied.
  2292. [Moved] - Any file or directory marked for move will cause the rest of the
  2293. upgrade to make the correct changes, such as updating links or
  2294. replacing the old path with the new path in the registry or INI
  2295. files.
  2296. Any file marked for deletion is simply noted, and all links to the
  2297. file are also deleted.
  2298. [Incompatible Messages] - All messages are added to the report (and may be
  2299. suppressed if someone else handles the problem)
  2300. [NT Disk Space Requirements] - Any additional space needed by a migration DLL
  2301. will be added to the computations performed
  2302. by Setup
  2303. Arguments:
  2304. Dll - Specifies the properties of the DLL who owns the migrate.inf
  2305. Return Value:
  2306. TRUE if processing was successful, or FALSE if an error occurred.
  2307. --*/
  2308. {
  2309. HINF Inf;
  2310. INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
  2311. INFSTRUCT is2 = INITINFSTRUCT_POOLHANDLE;
  2312. PCSTR Object;
  2313. PCSTR ObjectType;
  2314. PCSTR Source;
  2315. PCSTR Dest;
  2316. PCSTR Size;
  2317. PCSTR Drive;
  2318. CHAR WithColonAndWack[4];
  2319. PCSTR ObjectSection;
  2320. CHAR MsgMgrContext[MAX_MBCHAR_PATH];
  2321. PSTR DisplayObjectSection;
  2322. PCSTR MigDllGroup;
  2323. BOOL HardwareSpecialCase;
  2324. PSTR p;
  2325. CHAR QuotedObjectSection[256];
  2326. PCSTR ResText;
  2327. DWORD SrcAttribs;
  2328. TREE_ENUM TreeEnum;
  2329. CHAR FixedSrc[MAX_MBCHAR_PATH];
  2330. CHAR NewDest[MAX_MBCHAR_PATH];
  2331. PCSTR OtherDevices = NULL;
  2332. PCSTR DeviceType;
  2333. PCSTR PrintDevice = NULL;
  2334. PCSTR Num;
  2335. UINT Value;
  2336. PCSTR PreDefGroup;
  2337. INT PrevChar;
  2338. //
  2339. // Open the INF
  2340. //
  2341. WritePrivateProfileString(
  2342. NULL,
  2343. NULL,
  2344. NULL,
  2345. Dll->MigrateInfPath
  2346. );
  2347. Inf = InfOpenInfFile (Dll->MigrateInfPath);
  2348. if (Inf == INVALID_HANDLE_VALUE) {
  2349. LOG ((LOG_ERROR, "Cannot open %s for processing", Dll->MigrateInfPath));
  2350. return TRUE;
  2351. }
  2352. //
  2353. // Read in the [Handled] section
  2354. //
  2355. if (InfFindFirstLine (Inf, "Handled", NULL, &is)) {
  2356. do {
  2357. Object = InfGetStringField (&is, 0);
  2358. ObjectType = InfGetStringField (&is, 1);
  2359. if (Object) {
  2360. //
  2361. // Suppress all incompatibility messages associated with the object
  2362. //
  2363. DEBUGMSG ((DBG_MIGDLLS, "%s handled %s", Dll->MigrateInfPath, Object));
  2364. HandleObject (Object, ObjectType);
  2365. }
  2366. InfResetInfStruct (&is);
  2367. } while (InfFindNextLine (&is));
  2368. }
  2369. //
  2370. // Read in the [Moved] section
  2371. //
  2372. if (InfFindFirstLine (Inf, "Moved", NULL, &is)) {
  2373. do {
  2374. Source = InfGetStringField (&is, 0);
  2375. Dest = InfGetStringField (&is, 1);
  2376. if (Source) {
  2377. StackStringCopy (FixedSrc, Source);
  2378. RemoveWackAtEnd (FixedSrc);
  2379. SrcAttribs = QuietGetFileAttributes (FixedSrc);
  2380. if (SrcAttribs != INVALID_ATTRIBUTES) {
  2381. if (Source && *Source) {
  2382. if (SrcAttribs & FILE_ATTRIBUTE_DIRECTORY) {
  2383. DEBUGMSG ((DBG_MIGDLLS, "Directory %s marked as handled because %s will move it.", Source, Dll->MigrateInfPath));
  2384. HandleObject (Source, TEXT("Directory"));
  2385. }
  2386. else {
  2387. DEBUGMSG ((DBG_MIGDLLS, "File %s marked as handled because %s will move it.", Source, Dll->MigrateInfPath));
  2388. HandleObject (Source, TEXT("File"));
  2389. }
  2390. }
  2391. if (Dest && *Dest) {
  2392. if (SrcAttribs & FILE_ATTRIBUTE_DIRECTORY) {
  2393. //
  2394. // Migration DLL will move this dir
  2395. //
  2396. DEBUGMSG ((DBG_MIGDLLS, "%s moved dir %s to %s", Dll->MigrateInfPath, Source, Dest));
  2397. if (EnumFirstFileInTree (&TreeEnum, Source, NULL, TRUE)) {
  2398. StackStringCopy (NewDest, Dest);
  2399. p = AppendWack (NewDest);
  2400. do {
  2401. RemoveOperationsFromPath (TreeEnum.FullPath, ALL_CHANGE_OPERATIONS);
  2402. MYASSERT (*TreeEnum.SubPath != '\\');
  2403. StringCopy (p, TreeEnum.SubPath);
  2404. MarkFileForMoveExternal (TreeEnum.FullPath, NewDest);
  2405. } while (EnumNextFileInTree (&TreeEnum));
  2406. }
  2407. StackStringCopy (NewDest, Dest);
  2408. RemoveWackAtEnd (NewDest);
  2409. RemoveOperationsFromPath (FixedSrc, ALL_CHANGE_OPERATIONS);
  2410. MarkFileForMoveExternal (FixedSrc, NewDest);
  2411. } else {
  2412. //
  2413. // Migration DLL will move this file
  2414. //
  2415. DEBUGMSG ((DBG_MIGDLLS, "%s moved %s to %s", Dll->MigrateInfPath, Source, Dest));
  2416. RemoveOperationsFromPath (Source, ALL_CHANGE_OPERATIONS);
  2417. MarkFileForMoveExternal (Source, Dest);
  2418. }
  2419. } else {
  2420. if (SrcAttribs & FILE_ATTRIBUTE_DIRECTORY) {
  2421. DEBUGMSG ((DBG_MIGDLLS, "%s deleted dir %s", Dll->MigrateInfPath, Source));
  2422. if (EnumFirstFileInTree (&TreeEnum, Source, NULL, TRUE)) {
  2423. do {
  2424. RemoveOperationsFromPath (TreeEnum.FullPath, ALL_CHANGE_OPERATIONS);
  2425. MarkFileForExternalDelete (TreeEnum.FullPath);
  2426. } while (EnumNextFileInTree (&TreeEnum));
  2427. }
  2428. } else {
  2429. //
  2430. // Migration DLL will delete this file
  2431. //
  2432. DEBUGMSG ((DBG_MIGDLLS, "%s deleted %s", Dll->MigrateInfPath, Source));
  2433. RemoveOperationsFromPath (Source, ALL_CHANGE_OPERATIONS);
  2434. MarkFileForExternalDelete (Source);
  2435. }
  2436. }
  2437. }
  2438. ELSE_DEBUGMSG ((
  2439. DBG_WARNING,
  2440. "Ignoring non-existent soruce in [Moved]: %s",
  2441. Source
  2442. ));
  2443. }
  2444. InfResetInfStruct (&is);
  2445. } while (InfFindNextLine (&is));
  2446. }
  2447. //
  2448. // Read in the [Incompatible Messages] section
  2449. //
  2450. if (InfFindFirstLine (Inf, "Incompatible Messages", NULL, &is)) {
  2451. OtherDevices = GetStringResource (MSG_UNKNOWN_DEVICE_CLASS);
  2452. PrintDevice = GetStringResource (MSG_PRINTERS_DEVICE_CLASS);
  2453. do {
  2454. //
  2455. // Add incompatible messages
  2456. //
  2457. ObjectSection = InfGetStringField (&is, 0);
  2458. if (!ObjectSection) {
  2459. DEBUGMSG ((DBG_ERROR, "Malformed migrate.inf. Some incompatibility messages may be missing."));
  2460. continue;
  2461. }
  2462. GetPrivateProfileString (
  2463. "Incompatible Messages",
  2464. ObjectSection,
  2465. "",
  2466. g_MessageBuf,
  2467. MAX_MESSAGE - 4,
  2468. Dll->MigrateInfPath
  2469. );
  2470. if (*g_MessageBuf == 0 && ByteCount (ObjectSection) < 250) {
  2471. wsprintf (QuotedObjectSection, TEXT("\"%s\""), ObjectSection);
  2472. GetPrivateProfileString (
  2473. "Incompatible Messages",
  2474. QuotedObjectSection,
  2475. "",
  2476. g_MessageBuf,
  2477. MAX_MESSAGE - 4,
  2478. Dll->MigrateInfPath
  2479. );
  2480. }
  2481. // Remove quote pairs, replace \n with actual line break character
  2482. for (p = g_MessageBuf ; *p ; p = _mbsinc (p)) {
  2483. PrevChar = _mbsnextc (p);
  2484. if (PrevChar == '\"' || PrevChar == '%') {
  2485. if (_mbsnextc (p + 1) == PrevChar) {
  2486. MoveMemory ((PSTR) p, p + 1, SizeOfStringA (p + 1));
  2487. }
  2488. } else if (_mbsnextc (p) == '\\') {
  2489. if (_mbsnextc (p + 1) == 'n') {
  2490. MoveMemory ((PSTR) p, p + 1, SizeOfStringA (p + 1));
  2491. *((PSTR) p) = '\r';
  2492. }
  2493. }
  2494. }
  2495. // Terminate anchor tag if DLL forgot it, harmless otherwise
  2496. StringCatA (g_MessageBuf, "</A>");
  2497. //
  2498. // Replace OS name variables
  2499. //
  2500. MappingSearchAndReplace (g_MsgVariableMap, g_MessageBuf, MAX_MESSAGE);
  2501. //
  2502. // Associate objects with the message
  2503. //
  2504. if (InfFindFirstLine (Inf, ObjectSection, NULL, &is2)) {
  2505. wsprintf (MsgMgrContext, "%s,%s", Dll->MigrateInfPath, ObjectSection);
  2506. //
  2507. // The ObjectSection specified by the migration DLL indicates
  2508. // what message group it goes in. There are four possibilities:
  2509. //
  2510. // 1. ObjectSection starts with a # and gives the group number,
  2511. // as in #1\Program Name. In this case we parse the number,
  2512. // and then put the message in the proper group.
  2513. //
  2514. // 2. ObjectSection starts with a well-defined, localized root
  2515. // name. In this case we use that name.
  2516. //
  2517. // 3. ObjectSection is in the form of \Hardware\<device>. In
  2518. // this case we put the device in the "Other devices"
  2519. // subgroup.
  2520. //
  2521. // 4. ObjectSection is in another format than above. In this
  2522. // case we put the object section into the migration DLL group.
  2523. //
  2524. DisplayObjectSection = NULL;
  2525. if (*ObjectSection == TEXT('#')) {
  2526. Value = 0;
  2527. Num = ObjectSection + 1;
  2528. while (*Num >= TEXT('0') && *Num <= TEXT('9')) {
  2529. Value = Value * 10 + (*Num - TEXT('0'));
  2530. Num++;
  2531. }
  2532. if (_tcsnextc (Num) == TEXT('\\')) {
  2533. Num++;
  2534. if (*Num) {
  2535. PreDefGroup = GetPreDefinedMessageGroupText (Value);
  2536. if (PreDefGroup) {
  2537. DisplayObjectSection = JoinText (PreDefGroup, Num);
  2538. DEBUGMSG ((
  2539. DBG_MIGDLLS,
  2540. "Pre-defined group created: %s -> %s",
  2541. ObjectSection,
  2542. DisplayObjectSection
  2543. ));
  2544. }
  2545. }
  2546. }
  2547. }
  2548. if (!DisplayObjectSection) {
  2549. if (IsPreDefinedMessageGroup (ObjectSection)) {
  2550. DisplayObjectSection = DuplicateText (ObjectSection);
  2551. MYASSERT (DisplayObjectSection);
  2552. } else {
  2553. //
  2554. // Put message in migration DLL group
  2555. //
  2556. HardwareSpecialCase = StringIMatchTcharCount (
  2557. ObjectSection,
  2558. S_HARDWARE_IN_WACKS,
  2559. S_HARDWARE_CHARS
  2560. );
  2561. if (HardwareSpecialCase) {
  2562. //
  2563. // Hack -- if this is the printer migration DLL,
  2564. // then use Printers instead of Other Devices.
  2565. //
  2566. p = (PSTR) _tcsistr (Dll->OriginalDir, TEXT("\\print"));
  2567. if (p && (*(p + ARRAYSIZE(TEXT("\\print"))) == 0)) {
  2568. DeviceType = PrintDevice;
  2569. } else {
  2570. DeviceType = OtherDevices;
  2571. }
  2572. MigDllGroup = BuildMessageGroup (
  2573. MSG_INCOMPATIBLE_HARDWARE_ROOT,
  2574. MSG_INCOMPATIBLE_HARDWARE_PNP_SUBGROUP,
  2575. DeviceType
  2576. );
  2577. ObjectSection += S_HARDWARE_CHARS;
  2578. MYASSERT (MigDllGroup);
  2579. } else {
  2580. ResText = GetStringResource (MSG_MIGDLL_ROOT);
  2581. MYASSERT (ResText);
  2582. MigDllGroup = DuplicateText (ResText);
  2583. FreeStringResource (ResText);
  2584. MYASSERT (MigDllGroup);
  2585. }
  2586. DisplayObjectSection = AllocText (SizeOfStringA (MigDllGroup) +
  2587. SizeOfStringA (ObjectSection) +
  2588. SizeOfStringA (Dll->ProductId)
  2589. );
  2590. MYASSERT (DisplayObjectSection);
  2591. if (HardwareSpecialCase) {
  2592. wsprintf (DisplayObjectSection, "%s\\%s", MigDllGroup, ObjectSection);
  2593. } else if (StringIMatch (Dll->ProductId, ObjectSection)) {
  2594. wsprintf (DisplayObjectSection, "%s\\%s", MigDllGroup, Dll->ProductId);
  2595. } else {
  2596. wsprintf (DisplayObjectSection, "%s\\%s\\%s", MigDllGroup, Dll->ProductId, ObjectSection);
  2597. }
  2598. FreeText (MigDllGroup);
  2599. }
  2600. }
  2601. MsgMgr_ContextMsg_Add (
  2602. MsgMgrContext,
  2603. DisplayObjectSection,
  2604. g_MessageBuf
  2605. );
  2606. FreeText (DisplayObjectSection);
  2607. do {
  2608. Object = InfGetStringField (&is2, 0);
  2609. if (Object) {
  2610. MsgMgr_LinkObjectWithContext (
  2611. MsgMgrContext,
  2612. Object
  2613. );
  2614. }
  2615. ELSE_DEBUGMSG ((DBG_WHOOPS, "pProcessMigrateInf: InfGetStringField failed"));
  2616. if (Object == NULL) {
  2617. LOG ((LOG_ERROR, "Failed to get string field from migration.dll migrate.inf."));
  2618. }
  2619. } while (InfFindNextLine (&is2));
  2620. InfResetInfStruct (&is2);
  2621. }
  2622. ELSE_DEBUGMSG ((DBG_ERROR, "Object section %s not found", ObjectSection));
  2623. InfResetInfStruct (&is);
  2624. } while (InfFindNextLine (&is));
  2625. if (OtherDevices) {
  2626. FreeStringResource (OtherDevices);
  2627. }
  2628. if (PrintDevice) {
  2629. FreeStringResource (PrintDevice);
  2630. }
  2631. }
  2632. //
  2633. // Read in the [NT Disk Space Requirements] section
  2634. //
  2635. if (InfFindFirstLine (Inf, "NT Disk Space Requirements", NULL, &is)) {
  2636. do {
  2637. Drive = InfGetStringField (&is, 0);
  2638. if (!Drive) {
  2639. DEBUGMSG ((DBG_ERROR, "Could not read some NT Disk Space Requirements from migrate.inf"));
  2640. continue;
  2641. }
  2642. WithColonAndWack[0] = Drive[0];
  2643. WithColonAndWack[1] = ':';
  2644. WithColonAndWack[2] = '\\';
  2645. WithColonAndWack[3] = 0;
  2646. Size = InfGetStringField (&is, 1);
  2647. UseSpace (WithColonAndWack, (LONGLONG) atoi (Size));
  2648. InfResetInfStruct (&is);
  2649. } while (InfFindNextLine (&is));
  2650. }
  2651. InfCleanUpInfStruct (&is);
  2652. InfCleanUpInfStruct (&is2);
  2653. InfCloseInfFile (Inf);
  2654. return TRUE;
  2655. }