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.

3105 lines
98 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. //
  4. // Names of wizard page types, do not change order unless
  5. // the WizardPagesType enum is changed.
  6. //
  7. LPCTSTR WizardPagesTypeNames[WizPagesTypeMax] = { TEXT("Welcome"), TEXT("Mode"),
  8. TEXT("Early") , TEXT("Prenet"),
  9. TEXT("Postnet"), TEXT("Late"),
  10. TEXT("Final")
  11. };
  12. //
  13. // Name of sections and keys in infs.
  14. //
  15. LPCTSTR szComponents = TEXT("Components");
  16. LPCTSTR szOptionalComponents = TEXT("Optional Components");
  17. LPCTSTR szExtraSetupFiles = TEXT("ExtraSetupFiles");
  18. LPCTSTR szNeeds = TEXT("Needs");
  19. LPCTSTR szExclude = TEXT("Exclude");
  20. LPCTSTR szParent = TEXT("Parent");
  21. LPCTSTR szIconIndex = TEXT("IconIndex");
  22. LPCTSTR szModes = TEXT("Modes");
  23. LPCTSTR szTip = TEXT("Tip");
  24. LPCTSTR szOptionDesc = TEXT("OptionDesc");
  25. LPCTSTR szInstalledFlag = TEXT("InstalledFlag");
  26. LPCTSTR szHide = TEXT("HIDE");
  27. LPCTSTR szOSSetupOnly = TEXT("OSSetupOnly");
  28. LPCTSTR szStandaloneOnly = TEXT("StandaloneOnly");
  29. LPCTSTR szPageTitle = TEXT("PageTitles");
  30. LPCTSTR szSetupTitle = TEXT("SetupPage");
  31. LPCTSTR szGlobal = TEXT("Global");
  32. LPCTSTR szWindowTitle = TEXT("WindowTitle");
  33. LPCTSTR szWindowTitleAlone = TEXT("WindowTitle.StandAlone");
  34. LPCTSTR szSizeApproximation = TEXT("SizeApproximation");
  35. LPCTSTR szWindowTitleInternal = TEXT("*");
  36. //
  37. // Key in registry where private component data is kept.
  38. // We form a unique name within this key for the OC Manager
  39. // instantiation.
  40. //
  41. LPCTSTR szOcManagerRoot = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\OC Manager");
  42. LPCTSTR szPrivateDataRoot = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\OC Manager\\TemporaryData");
  43. LPCTSTR szMasterInfs = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\OC Manager\\MasterInfs");
  44. LPCTSTR szSubcompList = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\OC Manager\\Subcomponents");
  45. LPCTSTR szOcManagerErrors = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\OC Manager\\Errors");
  46. //
  47. // Other string constants.
  48. //
  49. LPCTSTR szSetupDir = TEXT("Setup");
  50. //
  51. // locale information
  52. //
  53. LOCALE locale;
  54. // Structure used for string table callback when
  55. // building a subcomponent list.
  56. //
  57. typedef struct _BUILDSUBCOMPLIST_PARAMS {
  58. POC_MANAGER OcManager;
  59. UINT Pass;
  60. } BUILDSUBCOMPLIST_PARAMS, *PBUILDSUBCOMPLIST_PARAMS;
  61. //
  62. // oc manager pointer for debugging/logging
  63. //
  64. POC_MANAGER gLastOcManager = NULL;
  65. UINT
  66. pOcQueryOrSetNewInf(
  67. IN PCTSTR MasterOcInfName,
  68. OUT PTSTR SuiteName,
  69. IN DWORD Operation
  70. );
  71. VOID
  72. pOcDestroyPerOcData(
  73. IN POC_MANAGER OcManager
  74. );
  75. BOOL
  76. pOcDestroyPerOcDataStringCB(
  77. IN PVOID StringTable,
  78. IN LONG StringId,
  79. IN PCTSTR String,
  80. IN POPTIONAL_COMPONENT Oc,
  81. IN UINT OcSize,
  82. IN LPARAM Unused
  83. );
  84. VOID
  85. pOcClearAllErrorStates(
  86. IN POC_MANAGER OcManager
  87. );
  88. BOOL
  89. FileExists(
  90. IN PCTSTR FileName,
  91. OUT PWIN32_FIND_DATA FindData OPTIONAL
  92. )
  93. /*++
  94. Routine Description:
  95. Determine if a file exists and is accessible.
  96. Errormode is set (and then restored) so the user will not see
  97. any pop-ups.
  98. Arguments:
  99. FileName - supplies full path of file to check for existance.
  100. FindData - if specified, receives find data for the file.
  101. Return Value:
  102. TRUE if the file exists and is accessible.
  103. FALSE if not. GetLastError() returns extended error info.
  104. --*/
  105. {
  106. WIN32_FIND_DATA findData;
  107. HANDLE FindHandle;
  108. UINT OldMode;
  109. DWORD Error;
  110. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  111. FindHandle = FindFirstFile(FileName,&findData);
  112. if(FindHandle == INVALID_HANDLE_VALUE) {
  113. Error = GetLastError();
  114. } else {
  115. FindClose(FindHandle);
  116. if(FindData) {
  117. *FindData = findData;
  118. }
  119. Error = NO_ERROR;
  120. }
  121. SetErrorMode(OldMode);
  122. SetLastError(Error);
  123. return (Error == NO_ERROR);
  124. }
  125. VOID
  126. pOcFormSuitePath(
  127. IN LPCTSTR SuiteName,
  128. IN LPCTSTR FileName, OPTIONAL
  129. OUT LPTSTR FullPath
  130. )
  131. /*++
  132. Routine Description:
  133. Forms the name of the directory in the OS tree where per-suite
  134. infs and installation dlls are kept (system32\setup).
  135. Optionally also appends the name of a file to the path.
  136. Arguments:
  137. SuiteName - shortname for the suite.
  138. FileName - optionally specifies the name of a file in the per-suite
  139. directory.
  140. FullPath - receives the full path of the per-suite directory (or the
  141. file within the directory). This buffer should be MAX_PATH TCHAR
  142. elements.
  143. Return Value:
  144. None.
  145. --*/
  146. {
  147. UNREFERENCED_PARAMETER(SuiteName);
  148. GetSystemDirectory(FullPath,MAX_PATH);
  149. pSetupConcatenatePaths(FullPath,szSetupDir,MAX_PATH,NULL);
  150. //
  151. // We put all such files in a single flat directory.
  152. // This makes life easier for components that want to share
  153. // installation pieces, such as infs, dlls, etc.
  154. //
  155. // There are potential name conflict issues but we blow them off.
  156. //
  157. //pSetupConcatenatePaths(FullPath,SuiteName,MAX_PATH,NULL);
  158. if(FileName) {
  159. pSetupConcatenatePaths(FullPath,FileName,MAX_PATH,NULL);
  160. }
  161. }
  162. BOOL
  163. pOcBuildSubcomponentListStringCB(
  164. IN PVOID StringTable,
  165. IN LONG StringId,
  166. IN PCTSTR String,
  167. IN POC_INF OcInf,
  168. IN UINT OcInfSize,
  169. IN PBUILDSUBCOMPLIST_PARAMS Params
  170. )
  171. /*++
  172. Routine Description:
  173. String table callback, worker routine for pOcBuildSubcomponentLists.
  174. This routine examines the loaded per-component infs and builds the
  175. subcomponent hierarchies that are described therein via the Parent=
  176. lines in the various per-component sections.
  177. Arguments:
  178. Standard string table callback args.
  179. Return Value:
  180. Boolean indicating outcome. If FALSE, an error will have been logged.
  181. FALSE also stops the string table enumeration and causes pSetupStringTableEnum()
  182. to return FALSE.
  183. --*/
  184. {
  185. OPTIONAL_COMPONENT OptionalComponent;
  186. OPTIONAL_COMPONENT AuxOc;
  187. INFCONTEXT LineContext;
  188. INFCONTEXT SublineContext;
  189. LPCTSTR SubcompName;
  190. LPCTSTR ModuleFlags;
  191. LPCTSTR p;
  192. LONG l;
  193. LONG CurrentStringId;
  194. UINT u,n;
  195. INT IconIndex;
  196. POC_MANAGER OcManager = Params->OcManager;
  197. if(SetupFindFirstLine(OcInf->Handle,szOptionalComponents,NULL,&LineContext)) {
  198. do {
  199. if((SubcompName = pSetupGetField(&LineContext,1)) && *SubcompName) {
  200. l = pSetupStringTableLookUpStringEx(
  201. Params->OcManager->ComponentStringTable,
  202. (PTSTR)SubcompName,
  203. STRTAB_CASE_INSENSITIVE,
  204. &OptionalComponent,
  205. sizeof(OPTIONAL_COMPONENT)
  206. );
  207. if(Params->Pass == 0) {
  208. //
  209. // First pass. Add subcomponents listed in [Optional Components]
  210. // to the string table. Each one has an associated OPTIONAL_COMPONENT
  211. // structure. Top-level components already exist in the table,
  212. // so we are careful here about how we overwrite existing entries.
  213. //
  214. if(l == -1) {
  215. ZeroMemory(&OptionalComponent,sizeof(OPTIONAL_COMPONENT));
  216. OptionalComponent.ParentStringId = -1;
  217. OptionalComponent.FirstChildStringId = -1;
  218. OptionalComponent.NextSiblingStringId = -1;
  219. OptionalComponent.InfStringId = StringId;
  220. OptionalComponent.Exists = FALSE;
  221. }
  222. if (OptionalComponent.Exists) {
  223. _LogError(OcManager,
  224. OcErrLevError,
  225. MSG_OC_DUPLICATE_COMPONENT,
  226. SubcompName);
  227. continue;
  228. }
  229. OptionalComponent.Exists = TRUE;
  230. // Get the second Field of the Optional components line
  231. // Determine if this component is hidden or not
  232. ModuleFlags = pSetupGetField(&LineContext,2);
  233. if (ModuleFlags) {
  234. if (OcManager->SetupData.OperationFlags & SETUPOP_STANDALONE)
  235. p = szOSSetupOnly;
  236. else
  237. p = szStandaloneOnly;
  238. if (!_tcsicmp(ModuleFlags, szHide) || !_tcsicmp(ModuleFlags, p))
  239. OptionalComponent.InternalFlags |= OCFLAG_HIDE;
  240. }
  241. //
  242. // Fetch the description, tip, and iconindex.
  243. //
  244. if(SetupFindFirstLine(OcInf->Handle,SubcompName,szOptionDesc,&SublineContext)
  245. && (p = pSetupGetField(&SublineContext,1))) {
  246. lstrcpyn(OptionalComponent.Description,p,MAXOCDESC);
  247. } else {
  248. OptionalComponent.Description[0] = 0;
  249. }
  250. if(SetupFindFirstLine(OcInf->Handle,SubcompName,szTip,&SublineContext)
  251. && (p = pSetupGetField(&SublineContext,1))) {
  252. lstrcpyn(OptionalComponent.Tip,p,MAXOCTIP);
  253. } else {
  254. OptionalComponent.Tip[0] = 0;
  255. }
  256. if(SetupFindFirstLine(OcInf->Handle,SubcompName,szIconIndex,&SublineContext)
  257. && (p = pSetupGetField(&SublineContext,1))) {
  258. LPCTSTR p2,p3;
  259. //
  260. // If we have fields 2 and 3 then assume we've got a dll
  261. // and resource name. Otherwise it's an index or *.
  262. //
  263. if((p2 = pSetupGetField(&SublineContext,2))
  264. && (p3 = pSetupGetField(&SublineContext,3))) {
  265. lstrcpyn(
  266. OptionalComponent.IconDll,
  267. p2,
  268. sizeof(OptionalComponent.IconDll)/sizeof(TCHAR)
  269. );
  270. lstrcpyn(
  271. OptionalComponent.IconResource,
  272. p3,
  273. sizeof(OptionalComponent.IconResource)/sizeof(TCHAR)
  274. );
  275. IconIndex = -2;
  276. } else {
  277. //
  278. // If the icon index is * then stick -1 in there
  279. // as a special marker value for later.
  280. // Otherwise we call SetupGetIntField because it will
  281. // validate the field for us.
  282. //
  283. if((p[0] == TEXT('*')) && (p[1] == 0)) {
  284. IconIndex = -1;
  285. } else {
  286. if(!SetupGetIntField(&SublineContext,1,&IconIndex)) {
  287. IconIndex = DEFAULT_ICON_INDEX;
  288. } else {
  289. // Setupapi will return DEFAULT_ICON_INDEX if out of range.
  290. if (IconIndex < 0) {
  291. IconIndex = DEFAULT_ICON_INDEX;
  292. }
  293. }
  294. }
  295. }
  296. } else {
  297. //
  298. // No icon index.
  299. //
  300. IconIndex = DEFAULT_ICON_INDEX;
  301. }
  302. OptionalComponent.IconIndex = IconIndex;
  303. //
  304. // if the InstalledFlag is specified, check it
  305. // and set the original selection state accordingly
  306. //
  307. OptionalComponent.InstalledState = INSTSTATE_UNKNOWN;
  308. if(SetupFindFirstLine(OcInf->Handle,SubcompName,szInstalledFlag,&SublineContext)
  309. && (p = pSetupGetField(&SublineContext,1))) {
  310. TCHAR regkey[MAXOCIFLAG];
  311. lstrcpyn(regkey,p,MAXOCIFLAG);
  312. if (p = pSetupGetField(&SublineContext,2)) {
  313. TCHAR regval[MAXOCIFLAG];
  314. TCHAR buf[MAXOCIFLAG];
  315. HKEY hkey;
  316. DWORD size;
  317. DWORD type;
  318. DWORD rc;
  319. lstrcpyn(regval,p,MAXOCIFLAG);
  320. if (RegOpenKey(HKEY_LOCAL_MACHINE, regkey, &hkey) == ERROR_SUCCESS) {
  321. size = sizeof(buf);
  322. rc = RegQueryValueEx(hkey,
  323. regval,
  324. NULL,
  325. &type,
  326. (LPBYTE)buf,
  327. &size);
  328. RegCloseKey(hkey);
  329. if (rc == ERROR_SUCCESS) {
  330. OptionalComponent.InstalledState = INSTSTATE_YES;
  331. } else {
  332. OptionalComponent.InstalledState = INSTSTATE_NO;
  333. }
  334. }
  335. }
  336. }
  337. //
  338. // Fetch the list of modes in which the subcomponent should be
  339. // on by default. For future expandability, we'll accept any
  340. // mode values up to 31, which is the number of bits we can fit
  341. // in out UINT bitfield/
  342. //
  343. if(SetupFindFirstLine(OcInf->Handle,SubcompName,szModes,&SublineContext)) {
  344. n = SetupGetFieldCount(&SublineContext);
  345. for(u=0; u<n; u++) {
  346. if(SetupGetIntField(&SublineContext,u+1,&IconIndex)
  347. && ((DWORD)IconIndex < 32)) {
  348. OptionalComponent.ModeBits |= (1 << IconIndex);
  349. }
  350. }
  351. }
  352. //
  353. // As an optimization, fetch the size approximation, if they
  354. // supplied one.If they didn't supply this then we have to
  355. // query them for disk space
  356. //
  357. //
  358. if(SetupFindFirstLine(OcInf->Handle,SubcompName,szSizeApproximation,&SublineContext)
  359. && (p = pSetupGetField(&SublineContext,1))) {
  360. //
  361. // we have the text version of something that needs to be converted into
  362. // a LONGLONG...
  363. //
  364. pConvertStringToLongLong(p,&OptionalComponent.SizeApproximation);
  365. OptionalComponent.InternalFlags |= OCFLAG_APPROXSPACE;
  366. }
  367. // Find the The "TopLevelParent" for this Node
  368. // Search the list if TopLevelComponent looking for
  369. // the "INF string id" that matches the Inf String ID
  370. // of this component.
  371. for(u=0; u<OcManager->TopLevelOcCount; u++) {
  372. pSetupStringTableGetExtraData(
  373. OcManager->ComponentStringTable,
  374. OcManager->TopLevelOcStringIds[u],
  375. &AuxOc,
  376. sizeof(OPTIONAL_COMPONENT)
  377. );
  378. if(AuxOc.InfStringId == StringId) {
  379. // Found it and save to the current component
  380. OptionalComponent.TopLevelStringId = OcManager->TopLevelOcStringIds[u];
  381. u=(UINT)-1;
  382. break;
  383. }
  384. }
  385. // Check Found the Right String ID.
  386. if(u != (UINT)-1) {
  387. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  388. return(FALSE);
  389. }
  390. } else {
  391. // Pass Two - Discover Needs and Parentage
  392. // Two passs First to collect all the names second to
  393. // create the needs and parent links
  394. CurrentStringId = l;
  395. //
  396. // Deal with the needs.
  397. //
  398. if(SetupFindFirstLine(OcInf->Handle,SubcompName,szNeeds,&SublineContext)) {
  399. n = 0;
  400. u = 0;
  401. while(p = pSetupGetField(&SublineContext,n+1)) {
  402. //
  403. // Ignore unless the subcomponent is in the string table.
  404. //
  405. l = pSetupStringTableLookUpStringEx(
  406. Params->OcManager->ComponentStringTable,
  407. (PTSTR)p,
  408. STRTAB_CASE_INSENSITIVE,
  409. &AuxOc,
  410. sizeof(OPTIONAL_COMPONENT)
  411. );
  412. if(l != -1) {
  413. //
  414. // Grow the needs array and put this item in it.
  415. //
  416. if(OptionalComponent.NeedsStringIds) {
  417. p = pSetupRealloc(
  418. OptionalComponent.NeedsStringIds,
  419. (OptionalComponent.NeedsCount+1) * sizeof(LONG)
  420. );
  421. } else {
  422. OptionalComponent.NeedsCount = 0;
  423. p = pSetupMalloc(sizeof(LONG));
  424. }
  425. if(p) {
  426. OptionalComponent.NeedsStringIds = (PVOID)p;
  427. OptionalComponent.NeedsStringIds[OptionalComponent.NeedsCount++] = l;
  428. } else {
  429. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  430. return(FALSE);
  431. }
  432. //
  433. // Insert this component in the needed component's neededby array.
  434. //
  435. if(AuxOc.NeededByStringIds) {
  436. p = pSetupRealloc(
  437. AuxOc.NeededByStringIds,
  438. (AuxOc.NeededByCount+1) * sizeof(LONG)
  439. );
  440. } else {
  441. AuxOc.NeededByCount = 0;
  442. p = pSetupMalloc(sizeof(LONG));
  443. }
  444. if(p) {
  445. AuxOc.NeededByStringIds = (PVOID)p;
  446. AuxOc.NeededByStringIds[AuxOc.NeededByCount++] = CurrentStringId;
  447. } else {
  448. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  449. return(FALSE);
  450. }
  451. pSetupStringTableSetExtraData(
  452. Params->OcManager->ComponentStringTable,
  453. l,
  454. &AuxOc,
  455. sizeof(OPTIONAL_COMPONENT)
  456. );
  457. }
  458. n++;
  459. }
  460. }
  461. //
  462. // Deal with the excludes.
  463. //
  464. if(SetupFindFirstLine(OcInf->Handle,SubcompName,szExclude,&SublineContext)) {
  465. n = 0;
  466. u = 0;
  467. while(p = pSetupGetField(&SublineContext,n+1)) {
  468. //
  469. // Ignore unless the subcomponent is in the string table.
  470. //
  471. l = pSetupStringTableLookUpStringEx(
  472. Params->OcManager->ComponentStringTable,
  473. (PTSTR)p,
  474. STRTAB_CASE_INSENSITIVE,
  475. &AuxOc,
  476. sizeof(OPTIONAL_COMPONENT)
  477. );
  478. if(l != -1) {
  479. //
  480. // Grow the exclude array and put this item in it.
  481. //
  482. if(OptionalComponent.ExcludeStringIds) {
  483. p = pSetupRealloc(
  484. OptionalComponent.ExcludeStringIds,
  485. (OptionalComponent.ExcludeCount+1) * sizeof(LONG)
  486. );
  487. } else {
  488. OptionalComponent.ExcludeCount = 0;
  489. p = pSetupMalloc(sizeof(LONG));
  490. }
  491. if(p) {
  492. OptionalComponent.ExcludeStringIds = (PVOID)p;
  493. OptionalComponent.ExcludeStringIds[OptionalComponent.ExcludeCount++] = l;
  494. } else {
  495. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  496. return(FALSE);
  497. }
  498. //
  499. // Insert this component in the excluded component's excludedby array.
  500. //
  501. if(AuxOc.ExcludedByStringIds) {
  502. p = pSetupRealloc(
  503. AuxOc.ExcludedByStringIds,
  504. (AuxOc.ExcludedByCount+1) * sizeof(LONG)
  505. );
  506. } else {
  507. AuxOc.ExcludedByCount = 0;
  508. p = pSetupMalloc(sizeof(LONG));
  509. }
  510. if(p) {
  511. AuxOc.ExcludedByStringIds = (PVOID)p;
  512. AuxOc.ExcludedByStringIds[AuxOc.ExcludedByCount++] = CurrentStringId;
  513. } else {
  514. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  515. return(FALSE);
  516. }
  517. pSetupStringTableSetExtraData(
  518. Params->OcManager->ComponentStringTable,
  519. l,
  520. &AuxOc,
  521. sizeof(OPTIONAL_COMPONENT)
  522. );
  523. }
  524. n++;
  525. }
  526. }
  527. //
  528. // Figure out parentage. Ignore specified parent unless it exists
  529. // in the string table. We also note in the parent that it has children.
  530. //
  531. if(SetupFindFirstLine(OcInf->Handle,SubcompName,szParent,&SublineContext)
  532. && (p = (PVOID)pSetupGetField(&SublineContext,1))) {
  533. l = pSetupStringTableLookUpStringEx(
  534. Params->OcManager->ComponentStringTable,
  535. (PTSTR)p,
  536. STRTAB_CASE_INSENSITIVE,
  537. &AuxOc,
  538. sizeof(OPTIONAL_COMPONENT)
  539. );
  540. if(l != -1) {
  541. //
  542. // l is the string id of the parent, and AuxOc is filled with
  543. // the parent's optional component data.
  544. //
  545. OptionalComponent.ParentStringId = l;
  546. if(AuxOc.FirstChildStringId == -1) {
  547. //
  548. // This parent has no children yet.
  549. // Set the current component as its (first) child.
  550. // Note that in this case the current component does not yet
  551. // have any siblings.
  552. //
  553. AuxOc.FirstChildStringId = CurrentStringId;
  554. AuxOc.ChildrenCount = 1;
  555. pSetupStringTableSetExtraData(
  556. Params->OcManager->ComponentStringTable,
  557. l,
  558. &AuxOc,
  559. sizeof(OPTIONAL_COMPONENT)
  560. );
  561. } else {
  562. //
  563. // The parent already has children.
  564. // Increment the parent's count of children, then
  565. // walk the siblings list and add the new component to the end.
  566. //
  567. AuxOc.ChildrenCount++;
  568. pSetupStringTableSetExtraData(
  569. Params->OcManager->ComponentStringTable,
  570. l,
  571. &AuxOc,
  572. sizeof(OPTIONAL_COMPONENT)
  573. );
  574. l = AuxOc.FirstChildStringId;
  575. pSetupStringTableGetExtraData(
  576. Params->OcManager->ComponentStringTable,
  577. AuxOc.FirstChildStringId,
  578. &AuxOc,
  579. sizeof(OPTIONAL_COMPONENT)
  580. );
  581. while(AuxOc.NextSiblingStringId != -1) {
  582. l = AuxOc.NextSiblingStringId;
  583. pSetupStringTableGetExtraData(
  584. Params->OcManager->ComponentStringTable,
  585. l,
  586. &AuxOc,
  587. sizeof(OPTIONAL_COMPONENT)
  588. );
  589. }
  590. AuxOc.NextSiblingStringId = CurrentStringId;
  591. pSetupStringTableSetExtraData(
  592. Params->OcManager->ComponentStringTable,
  593. l,
  594. &AuxOc,
  595. sizeof(OPTIONAL_COMPONENT)
  596. );
  597. }
  598. }
  599. } else { // a node with out a parent a new Top Level node
  600. // Finally Add this String ID to the Component Strings list
  601. // UINT TopLevelParentOcCount;
  602. // PLONG TopLevelParentOcStringIds;
  603. if(OcManager->TopLevelParentOcStringIds != NULL) {
  604. p = pSetupRealloc(
  605. OcManager->TopLevelParentOcStringIds,
  606. (OcManager->TopLevelParentOcCount+1)
  607. * sizeof(OcManager->TopLevelParentOcStringIds)
  608. );
  609. } else {
  610. OcManager->TopLevelParentOcCount = 0;
  611. p = pSetupMalloc(sizeof(LONG));
  612. }
  613. if(p) {
  614. OcManager->TopLevelParentOcStringIds = (PVOID)p;
  615. OcManager->TopLevelParentOcStringIds[OcManager->TopLevelParentOcCount++] = CurrentStringId;
  616. } else {
  617. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  618. return(FALSE);
  619. }
  620. }
  621. }
  622. //
  623. // Now add the subcomponent to the string table.
  624. // We overwrite the extra data, which is not harmful since
  625. // we specifically fetched it earlier.
  626. //
  627. l = pSetupStringTableAddStringEx(
  628. Params->OcManager->ComponentStringTable,
  629. (PTSTR)SubcompName,
  630. STRTAB_NEW_EXTRADATA | STRTAB_CASE_INSENSITIVE,
  631. &OptionalComponent,
  632. sizeof(OPTIONAL_COMPONENT)
  633. );
  634. if(l == -1) {
  635. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  636. return(FALSE);
  637. }
  638. }
  639. } while(SetupFindNextLine(&LineContext,&LineContext));
  640. }
  641. return(TRUE);
  642. }
  643. BOOL
  644. pOcBuildSubcomponentLists(
  645. IN OUT POC_MANAGER OcManager,
  646. IN PVOID Log
  647. )
  648. /*++
  649. Routine Description:
  650. This routine examines the loaded per-component infs and builds the
  651. subcomponent hierarchies that are described therein via the Parent=
  652. lines in the various per-component sections.
  653. Arguments:
  654. OcManager - supplies a pointer to the context data structure
  655. for the OC Manager.
  656. Log - supplies a handle to use to log errors.
  657. Return Value:
  658. Boolean indicating outcome. If FALSE, an error will have been logged.
  659. --*/
  660. {
  661. OC_INF OcInf;
  662. BOOL b;
  663. BUILDSUBCOMPLIST_PARAMS s;
  664. s.OcManager = OcManager;
  665. //
  666. // We make 2 passes. The first adds all the subcomponent names to
  667. // the string table. The second computes parentage. If we don't do
  668. // it this way then we might have ordering problems.
  669. //
  670. s.Pass = 0;
  671. b = pSetupStringTableEnum(
  672. OcManager->InfListStringTable,
  673. &OcInf,
  674. sizeof(OC_INF),
  675. (PSTRTAB_ENUM_ROUTINE)pOcBuildSubcomponentListStringCB,
  676. (LPARAM)&s
  677. );
  678. if(b) {
  679. s.Pass = 1;
  680. b = pSetupStringTableEnum(
  681. OcManager->InfListStringTable,
  682. &OcInf,
  683. sizeof(OC_INF),
  684. (PSTRTAB_ENUM_ROUTINE)pOcBuildSubcomponentListStringCB,
  685. (LPARAM)&s
  686. );
  687. }
  688. return(b);
  689. }
  690. BOOL
  691. pOcInitPaths(
  692. IN OUT POC_MANAGER OcManager,
  693. IN PCTSTR MasterInfName
  694. )
  695. {
  696. TCHAR path[MAX_PATH];
  697. TCHAR *p;
  698. //
  699. // 1. look for master INF in specified directory.
  700. // 2. look in %systemroot%\system32\Setup directory.
  701. // 3. look in %systemroot%\inf directory.
  702. //
  703. if (!FileExists(MasterInfName, NULL)) {
  704. pOcFormSuitePath(NULL, NULL, path);
  705. p = _tcsrchr(MasterInfName, TEXT('\\'));
  706. if (!p)
  707. p = (TCHAR *)MasterInfName;
  708. pSetupConcatenatePaths(path, p, MAX_PATH, NULL);
  709. if (!FileExists(path, NULL)) {
  710. #ifdef UNICODE
  711. HMODULE hMod;
  712. FARPROC pGetSystemWindowsDirectory;
  713. hMod = LoadLibrary(L"kernel32.dll");
  714. if (hMod) {
  715. pGetSystemWindowsDirectory = GetProcAddress(hMod,"GetSystemWindowsDirectoryW");
  716. if (!pGetSystemWindowsDirectory) {
  717. pGetSystemWindowsDirectory = GetProcAddress(hMod,"GetWindowsDirectoryW");
  718. }
  719. if (pGetSystemWindowsDirectory) {
  720. pGetSystemWindowsDirectory( path, MAX_PATH );
  721. } else {
  722. GetWindowsDirectory(path,MAX_PATH);
  723. }
  724. FreeLibrary(hMod);
  725. }
  726. #else
  727. GetWindowsDirectory(path,MAX_PATH);
  728. #endif
  729. pSetupConcatenatePaths(path,TEXT("INF"),MAX_PATH,NULL);
  730. pSetupConcatenatePaths(path,p,MAX_PATH,NULL);
  731. if (!FileExists(path, NULL))
  732. return FALSE;
  733. }
  734. } else {
  735. _tcscpy(path, MasterInfName);
  736. }
  737. _tcscpy(OcManager->MasterOcInfPath, path);
  738. return TRUE;
  739. }
  740. BOOL
  741. pOcInstallSetupComponents(
  742. IN POPTIONAL_COMPONENT Oc,
  743. IN OUT POC_MANAGER OcManager,
  744. IN PCTSTR Component,
  745. IN PCTSTR DllName, OPTIONAL
  746. IN PCTSTR InfName, OPTIONAL
  747. IN HWND OwnerWindow,
  748. IN PVOID Log
  749. )
  750. /*++
  751. Routine Description:
  752. This routine makes sure that all files required for installation of
  753. a component listed in a master oc inf are properly installed in
  754. a well-known location.
  755. If the master OC inf is in the system inf directory, then we assume
  756. that all files are already in their proper locations and we do nothing.
  757. Otherwise we copy all installation files into system32\setup.
  758. Files copied include the per-component inf (if any), the installation dll,
  759. and all files listed on the ExtraSetupFiles= line in the [<component>]
  760. section in the master OC inf.
  761. Do not call this routine if the registry setting indicates that the
  762. master OC inf has been processed before.
  763. Arguments:
  764. OcManager - supplies a pointer to the context data structure
  765. for the OC Manager.
  766. MasterOcInfName - supplies the full Win32 path of the master OC inf file.
  767. Component - supplies the shortname of the component we care about.
  768. DllName - supplies the name of the component's installation dll, if any.
  769. InfName - supplies the name of the component's per-component inf,
  770. if any.
  771. OwnerWindow - supplies the handle of the window to own any UI which may be
  772. popped up by this routine.
  773. Log - supplies a handle to use to log errors.
  774. Return Value:
  775. Boolean indicating outcome. If FALSE, an error will have been logged.
  776. --*/
  777. {
  778. TCHAR Path[MAX_PATH];
  779. TCHAR TargetPath[MAX_PATH];
  780. TCHAR InfPath[MAX_PATH];
  781. PTCHAR p;
  782. UINT u;
  783. HSPFILEQ FileQueue;
  784. PVOID QueueContext;
  785. INFCONTEXT InfLine;
  786. BOOL b;
  787. TCHAR FileName[MAX_PATH];
  788. DWORD n;
  789. b = FALSE;
  790. //
  791. // All of the installation files are expected to be sourced
  792. // in the same directory as the master oc inf itself.
  793. //
  794. // We'll stick all the installation files for the component
  795. // in %windir%\system32\setup so we know where to get at them later.
  796. //
  797. // If the master inf is in the inf directory, then we instead
  798. // assume that the the component is tightly integrated into
  799. // the system and that the installation files are already in
  800. // the system32 directory.
  801. //
  802. if (!GetWindowsDirectory(Path,MAX_PATH) ||
  803. !pSetupConcatenatePaths(Path,TEXT("INF"),MAX_PATH,NULL)) {
  804. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  805. goto c0;
  806. }
  807. u = lstrlen(Path);
  808. pOcFormSuitePath(OcManager->SuiteName,NULL,TargetPath);
  809. lstrcpy(InfPath, OcManager->MasterOcInfPath);
  810. if (p = _tcsrchr(InfPath, TEXT('\\')))
  811. *p = 0;
  812. if (_tcsicmp(InfPath, Path) && _tcsicmp(InfPath, TargetPath)) {
  813. //
  814. // Inf is not in inf directory, so need to copy files.
  815. //
  816. FileQueue = SetupOpenFileQueue();
  817. if(FileQueue == INVALID_HANDLE_VALUE) {
  818. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  819. goto c0;
  820. }
  821. //
  822. // We will use the silent feature; no progress gauge but
  823. // we want errors to be displayed. Pass INVALID_HANDLE_VALUE
  824. // to get this behavior.
  825. //
  826. QueueContext = SetupInitDefaultQueueCallbackEx(OwnerWindow,INVALID_HANDLE_VALUE,0,0,0);
  827. if(!QueueContext) {
  828. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  829. goto c1;
  830. }
  831. //
  832. // Form source and target paths
  833. //
  834. lstrcpy(Path,OcManager->MasterOcInfPath);
  835. if(p = _tcsrchr(Path,TEXT('\\'))) {
  836. *p = 0;
  837. }
  838. //
  839. // Queue dll, and, if specified, inf
  840. //
  841. if (DllName && *DllName) {
  842. if ( (OcManager->SetupMode & SETUPMODE_PRIVATE_MASK) == SETUPMODE_REMOVEALL ) {
  843. b = SetupQueueDelete(
  844. FileQueue, // handle to the file queue
  845. TargetPath, // path to the file to delete
  846. DllName // optional, additional path info
  847. );
  848. } else {
  849. BOOL bCopyFile = TRUE;
  850. // check if the file is present, it may not have to be for
  851. // defered installs, where the suite will provide the Exe usally on demand
  852. // via Web download
  853. if (Oc && Oc->InterfaceFunctionName[0] == 0 ) {
  854. // No functin name means external setup
  855. lstrcpy(FileName,Path);
  856. pSetupConcatenatePaths(FileName, Oc->InstallationDllName, MAX_PATH, NULL);
  857. bCopyFile = (GetFileAttributes(FileName) == -1) ? FALSE: TRUE;
  858. b=TRUE;
  859. // bCopyFile=TRUE if we found the file
  860. }
  861. if( bCopyFile ) {
  862. b = SetupQueueCopy(
  863. FileQueue,
  864. Path,
  865. NULL,
  866. DllName,
  867. NULL,
  868. NULL,
  869. TargetPath,
  870. NULL,
  871. SP_COPY_SOURCEPATH_ABSOLUTE
  872. );
  873. }
  874. }
  875. if(!b) {
  876. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  877. goto c2;
  878. }
  879. }
  880. if(InfName && *InfName) {
  881. if ( (OcManager->SetupMode & SETUPMODE_PRIVATE_MASK) == SETUPMODE_REMOVEALL ) {
  882. b = SetupQueueDelete(
  883. FileQueue, // handle to the file queue
  884. TargetPath, // path to the file to delete
  885. InfName // optional, additional path info
  886. );
  887. } else {
  888. b = SetupQueueCopy(
  889. FileQueue,
  890. Path,
  891. NULL,
  892. InfName,
  893. NULL,
  894. NULL,
  895. TargetPath,
  896. NULL,
  897. SP_COPY_SOURCEPATH_ABSOLUTE
  898. );
  899. }
  900. if(!b) {
  901. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  902. goto c2;
  903. }
  904. }
  905. //
  906. // Queue each extra installation file.
  907. //
  908. if(SetupFindFirstLine(OcManager->MasterOcInf,Component,szExtraSetupFiles,&InfLine)) {
  909. n = 1;
  910. while(SetupGetStringField(&InfLine,n++,FileName,MAX_PATH,NULL)) {
  911. if ( (OcManager->SetupMode & SETUPMODE_PRIVATE_MASK) == SETUPMODE_REMOVEALL ) {
  912. b = SetupQueueDelete(
  913. FileQueue, // handle to the file queue
  914. TargetPath, // path to the file to delete
  915. FileName // optional, additional path info
  916. );
  917. } else {
  918. b = SetupQueueCopy(
  919. FileQueue,
  920. Path,
  921. NULL,
  922. FileName,
  923. NULL,
  924. NULL,
  925. TargetPath,
  926. NULL,
  927. SP_COPY_SOURCEPATH_ABSOLUTE
  928. );
  929. }
  930. if(!b) {
  931. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  932. goto c2;
  933. }
  934. }
  935. }
  936. //
  937. // Commit the queue.
  938. //
  939. b = SetupCommitFileQueue(OwnerWindow,FileQueue,SetupDefaultQueueCallback,QueueContext);
  940. if(!b) {
  941. _LogError(OcManager,OcErrLevError,MSG_OC_CANT_COPY_SETUP_FILES,GetLastError());
  942. goto c2;
  943. }
  944. //
  945. // Make a note that this OC inf is now "known."
  946. //
  947. u = pOcQueryOrSetNewInf(OcManager->MasterOcInfPath,OcManager->SuiteName,infSet);
  948. if(u != NO_ERROR) {
  949. _LogError(OcManager,OcErrLevWarning,MSG_OC_CANT_WRITE_REGISTRY,u);
  950. }
  951. c2:
  952. SetupTermDefaultQueueCallback(QueueContext);
  953. c1:
  954. SetupCloseFileQueue(FileQueue);
  955. c0:
  956. ;
  957. } else {
  958. b = TRUE;
  959. }
  960. return(b);
  961. }
  962. BOOL
  963. pOcLoadMasterOcInf(
  964. IN OUT POC_MANAGER OcManager,
  965. IN DWORD Flags,
  966. IN PVOID Log
  967. )
  968. /*++
  969. Routine Description:
  970. This routine loads the master OC inf and builds up the list of
  971. top-level optional components and some of the associated data
  972. inclucing the name of the installation inf, dll and the entry point.
  973. The per-components infs and dlls are not actually loaded
  974. by this routine.
  975. The wizard page ordering stuff is also initialized in the
  976. OC Manager data structure.
  977. Arguments:
  978. OcManager - supplies a pointer to the context data structure
  979. for the OC Manager.
  980. Flags - if OCINIT_FORCENEWINF, then behave as if the master OC inf is new.
  981. if OCINIT_KILLSUBCOMPS, then delete all applicable subcomponent
  982. entries from the registry before processing.
  983. Log - supplies a handle to use to log errors.
  984. Return Value:
  985. Boolean indicating outcome. If FALSE, an error will have been logged.
  986. --*/
  987. {
  988. BOOL b;
  989. INFCONTEXT InfContext;
  990. PCTSTR ComponentName;
  991. PCTSTR DllName;
  992. PCTSTR ModuleFlags;
  993. DWORD OtherFlags;
  994. PCTSTR EntryName;
  995. PCTSTR InfName;
  996. LPCTSTR chkflag;
  997. OPTIONAL_COMPONENT Oc;
  998. LONG Id;
  999. PVOID p;
  1000. UINT i,j;
  1001. UINT ActualCount;
  1002. WizardPagesType ReplacePages[4] = {WizPagesWelcome,WizPagesMode,WizPagesFinal,-1},
  1003. AddPages[5] = {WizPagesEarly,WizPagesPrenet,WizPagesPostnet,WizPagesLate,-1};
  1004. WizardPagesType *PageList;
  1005. PCTSTR SectionName;
  1006. BOOL NewInf;
  1007. TCHAR ComponentsSection[100];
  1008. TCHAR setupdir[MAX_PATH];
  1009. // First check and see if the setup cache directory exists.
  1010. // If not, then we should create it on this run.
  1011. pOcFormSuitePath(NULL, NULL, setupdir);
  1012. sapiAssert(*setupdir);
  1013. if (!FileExists(setupdir, NULL))
  1014. Flags |= OCINIT_FORCENEWINF;
  1015. //
  1016. // Always run pOcQueryOrSetNewInf in case it has side effects.
  1017. //
  1018. if (Flags & OCINIT_KILLSUBCOMPS)
  1019. pOcQueryOrSetNewInf(OcManager->MasterOcInfPath, OcManager->SuiteName, infReset);
  1020. NewInf = !pOcQueryOrSetNewInf(OcManager->MasterOcInfPath,OcManager->SuiteName,infQuery);
  1021. if(Flags & OCINIT_FORCENEWINF) {
  1022. NewInf = TRUE;
  1023. OcManager->InternalFlags |= OCMFLAG_NEWINF;
  1024. }
  1025. if (Flags & OCINIT_KILLSUBCOMPS)
  1026. OcManager->InternalFlags |= OCMFLAG_KILLSUBCOMPS;
  1027. if (Flags & OCINIT_RUNQUIET)
  1028. OcManager->InternalFlags |= OCMFLAG_RUNQUIET;
  1029. if (Flags & OCINIT_LANGUAGEAWARE)
  1030. OcManager->InternalFlags |= OCMFLAG_LANGUAGEAWARE;
  1031. OcManager->MasterOcInf = SetupOpenInfFile(OcManager->MasterOcInfPath,NULL,INF_STYLE_WIN4,&i);
  1032. if(OcManager->MasterOcInf == INVALID_HANDLE_VALUE) {
  1033. _LogError(OcManager,OcErrLevFatal,MSG_OC_CANT_OPEN_INF,OcManager->MasterOcInfPath,GetLastError(),i);
  1034. goto c0;
  1035. }
  1036. //
  1037. // Get the number of lines in the [Components] section and allocate
  1038. // arrays in the OC Manager context structure accordingly. This may
  1039. // overallocate the arrays (in case of duplicates, invalid lines, etc)
  1040. // but we won't worry about that here.
  1041. //
  1042. lstrcpy(ComponentsSection,szComponents);
  1043. OcManager->TopLevelOcCount = (UINT)(-1);
  1044. #if defined(_AMD64_)
  1045. lstrcat(ComponentsSection,TEXT(".amd64"));
  1046. #elif defined(_X86_)
  1047. lstrcat(ComponentsSection,TEXT(".w95"));
  1048. OcManager->TopLevelOcCount = SetupGetLineCount(OcManager->MasterOcInf,ComponentsSection);
  1049. if(OcManager->TopLevelOcCount == (UINT)(-1)) {
  1050. lstrcpy(ComponentsSection,szComponents);
  1051. lstrcat(ComponentsSection,TEXT(".x86"));
  1052. }
  1053. #elif defined(_IA64_)
  1054. lstrcat(ComponentsSection,TEXT(".ia64"));
  1055. #else
  1056. #error Unknown platform!
  1057. #endif
  1058. if(OcManager->TopLevelOcCount == (UINT)(-1)) {
  1059. OcManager->TopLevelOcCount = SetupGetLineCount(OcManager->MasterOcInf,ComponentsSection);
  1060. }
  1061. if(OcManager->TopLevelOcCount == (UINT)(-1)) {
  1062. lstrcpy(ComponentsSection,szComponents);
  1063. OcManager->TopLevelOcCount = SetupGetLineCount(OcManager->MasterOcInf,ComponentsSection);
  1064. }
  1065. if(OcManager->TopLevelOcCount == (UINT)(-1)) {
  1066. _LogError(OcManager,OcErrLevFatal,MSG_OC_INF_INVALID_NO_SECTION,OcManager->MasterOcInfPath,szComponents);
  1067. goto c1;
  1068. }
  1069. if (OcManager->TopLevelOcCount < 1) {
  1070. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  1071. goto c1;
  1072. }
  1073. if(p = pSetupRealloc(OcManager->TopLevelOcStringIds,OcManager->TopLevelOcCount*sizeof(LONG))) {
  1074. OcManager->TopLevelOcStringIds = p;
  1075. for(i=0; i<WizPagesTypeMax; i++) {
  1076. if(p = pSetupRealloc(OcManager->WizardPagesOrder[i],OcManager->TopLevelOcCount*sizeof(LONG))) {
  1077. OcManager->WizardPagesOrder[i] = p;
  1078. } else {
  1079. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  1080. goto c1;
  1081. }
  1082. }
  1083. } else {
  1084. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  1085. goto c1;
  1086. }
  1087. // get global info -
  1088. if ((OcManager->SetupData.OperationFlags & SETUPOP_STANDALONE) &&
  1089. SetupFindFirstLine(
  1090. OcManager->MasterOcInf,
  1091. szGlobal,
  1092. szWindowTitleAlone,
  1093. &InfContext)) {
  1094. // the main window title
  1095. SetupGetStringField(
  1096. &InfContext,
  1097. 1, // index of the field to get
  1098. OcManager->WindowTitle, // optional, receives the field
  1099. sizeof(OcManager->WindowTitle)/sizeof(OcManager->WindowTitle[0]), // num char of the provided buffer
  1100. NULL);
  1101. if( !lstrcmpi( OcManager->WindowTitle, szWindowTitleInternal)) {
  1102. //This will happen when we load sysoc.inf For MUI.
  1103. LoadString(MyModuleHandle,IDS_OCM_WINDOWTITLE,OcManager->WindowTitle,sizeof(OcManager->WindowTitle)/sizeof(TCHAR));
  1104. }
  1105. } else if(SetupFindFirstLine(
  1106. OcManager->MasterOcInf,
  1107. szGlobal,
  1108. szWindowTitle,
  1109. &InfContext)) {
  1110. // the main window title
  1111. SetupGetStringField(
  1112. &InfContext,
  1113. 1, // index of the field to get
  1114. OcManager->WindowTitle, // optional, receives the field
  1115. sizeof(OcManager->WindowTitle)/sizeof(OcManager->WindowTitle[0]), // num char of the provided buffer
  1116. NULL);
  1117. } else {
  1118. *OcManager->WindowTitle = 0;
  1119. }
  1120. //
  1121. // Go through the [Components] section. Each line in there is a top-level
  1122. // component spec, giving dll name, entry point name, and optionally
  1123. // the name of the per-component inf.
  1124. //
  1125. if(!SetupFindFirstLine(OcManager->MasterOcInf,ComponentsSection,NULL,&InfContext)) {
  1126. _LogError(OcManager,OcErrLevFatal,MSG_OC_INF_INVALID_NO_SECTION,OcManager->MasterOcInfPath,ComponentsSection);
  1127. goto c1;
  1128. }
  1129. ActualCount = 0;
  1130. do {
  1131. //
  1132. // Get pointers to each field in each line. Ignore invalid lines.
  1133. //
  1134. if(ComponentName = pSetupGetField(&InfContext,0)) {
  1135. DllName = pSetupGetField(&InfContext,1);
  1136. if(DllName && !*DllName) {
  1137. DllName = NULL;
  1138. }
  1139. EntryName = pSetupGetField(&InfContext,2);
  1140. if(EntryName && !*EntryName) {
  1141. EntryName = NULL;
  1142. }
  1143. //
  1144. // An empty string for the inf name is the same as
  1145. // not specifying the inf at all.
  1146. //
  1147. if((InfName = pSetupGetField(&InfContext,3)) && *InfName) {
  1148. Id = pSetupStringTableAddString(
  1149. OcManager->InfListStringTable,
  1150. (PTSTR)InfName,
  1151. STRTAB_CASE_INSENSITIVE
  1152. );
  1153. if(Id == -1) {
  1154. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  1155. goto c1;
  1156. }
  1157. } else {
  1158. Id = -1;
  1159. }
  1160. // Get the Flags Field
  1161. ModuleFlags = pSetupGetField(&InfContext,4);
  1162. if(ModuleFlags && !*ModuleFlags) {
  1163. ModuleFlags = NULL;
  1164. }
  1165. OtherFlags = 0;
  1166. SetupGetIntField(&InfContext,5,&OtherFlags);
  1167. ZeroMemory(&Oc,sizeof(OPTIONAL_COMPONENT));
  1168. //
  1169. // These guys are top-level. Also remember the string id
  1170. // of the inf name in the inf string table.
  1171. //
  1172. Oc.FirstChildStringId = -1;
  1173. Oc.NextSiblingStringId = -1;
  1174. Oc.ParentStringId = -1;
  1175. Oc.InfStringId = Id;
  1176. // Show flags allows up to have a component that is hidden
  1177. // Only on one flags now so keep processing simple
  1178. Oc.Exists = FALSE;
  1179. Oc.InternalFlags |= OCFLAG_TOPLEVELITEM;
  1180. if (ModuleFlags) {
  1181. if (OcManager->SetupData.OperationFlags & SETUPOP_STANDALONE)
  1182. chkflag = szOSSetupOnly;
  1183. else
  1184. chkflag = szStandaloneOnly;
  1185. if (!_tcsicmp(ModuleFlags, szHide) || !_tcsicmp(ModuleFlags, chkflag))
  1186. Oc.InternalFlags |= OCFLAG_HIDE;
  1187. }
  1188. if (OtherFlags & OCFLAG_NOWIZPAGES) {
  1189. Oc.InternalFlags |= OCFLAG_NOWIZARDPAGES;
  1190. }
  1191. if (OtherFlags & OCFLAG_NOQUERYSKIP) {
  1192. Oc.InternalFlags |= OCFLAG_NOQUERYSKIPPAGES;
  1193. }
  1194. if (OtherFlags & OCFLAG_NOEXTRAFLAGS) {
  1195. Oc.InternalFlags |= OCFLAG_NOEXTRAROUTINES;
  1196. }
  1197. if(DllName) {
  1198. lstrcpyn(Oc.InstallationDllName,DllName,MAX_PATH);
  1199. } else {
  1200. Oc.InstallationDllName[0] = 0;
  1201. }
  1202. //
  1203. // Interface Function Name is always ANSI -- there's no
  1204. // Unicode version of GetProcAddress.
  1205. //
  1206. if(EntryName) {
  1207. #ifdef UNICODE
  1208. WideCharToMultiByte(CP_ACP,0,EntryName,-1,Oc.InterfaceFunctionName,MAX_PATH,NULL,NULL);
  1209. #else
  1210. lstrcpyn(Oc.InterfaceFunctionName,EntryName,MAX_PATH);
  1211. #endif
  1212. } else {
  1213. Oc.InterfaceFunctionName[0] = 0;
  1214. }
  1215. Id = pSetupStringTableAddStringEx(
  1216. OcManager->ComponentStringTable,
  1217. (PTSTR)ComponentName,
  1218. STRTAB_CASE_INSENSITIVE | STRTAB_NEW_EXTRADATA,
  1219. &Oc,
  1220. sizeof(OPTIONAL_COMPONENT)
  1221. );
  1222. if(Id == -1) {
  1223. //
  1224. // OOM adding string
  1225. //
  1226. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  1227. goto c1;
  1228. }
  1229. OcManager->TopLevelOcStringIds[ActualCount++] = Id;
  1230. }
  1231. } while(SetupFindNextLine(&InfContext,&InfContext));
  1232. //
  1233. // Shrink down the various arrays.
  1234. //
  1235. OcManager->TopLevelOcStringIds = pSetupRealloc(OcManager->TopLevelOcStringIds,ActualCount*sizeof(LONG));
  1236. for(i=0; i<WizPagesTypeMax; i++) {
  1237. OcManager->WizardPagesOrder[i] = pSetupRealloc(OcManager->WizardPagesOrder[i],ActualCount*sizeof(LONG));
  1238. }
  1239. OcManager->TopLevelOcCount = ActualCount;
  1240. //
  1241. // Now for each wizard page type figure out the ordering.
  1242. //
  1243. for(i=0; i<2; i++) {
  1244. SectionName = i ? TEXT("PageAdd") : TEXT("PageReplace");
  1245. for(PageList = i ? AddPages : ReplacePages; *PageList != -1; PageList++) {
  1246. b = SetupFindFirstLine(
  1247. OcManager->MasterOcInf,
  1248. SectionName,
  1249. WizardPagesTypeNames[*PageList],
  1250. &InfContext
  1251. );
  1252. //
  1253. // Check for the "default" string, which is the same as if the line
  1254. // had not been specified at all.
  1255. //
  1256. if(b
  1257. && (ComponentName = pSetupGetField(&InfContext,1))
  1258. && !lstrcmpi(ComponentName,TEXT("Default"))) {
  1259. b = FALSE;
  1260. }
  1261. if(b) {
  1262. //
  1263. // Make sure the array is padded with -1's,
  1264. //
  1265. FillMemory(
  1266. OcManager->WizardPagesOrder[*PageList],
  1267. OcManager->TopLevelOcCount * sizeof(LONG),
  1268. (BYTE)(-1)
  1269. );
  1270. //
  1271. // Now process each element on the line, but don't allow
  1272. // overflowing the array.
  1273. //
  1274. j = 1;
  1275. ActualCount = 0;
  1276. while((ActualCount < OcManager->TopLevelOcCount)
  1277. && (ComponentName = pSetupGetField(&InfContext,j)) && *ComponentName) {
  1278. Id = pSetupStringTableLookUpString(
  1279. OcManager->ComponentStringTable,
  1280. (PTSTR)ComponentName,
  1281. STRTAB_CASE_INSENSITIVE
  1282. );
  1283. if(Id == -1) {
  1284. //
  1285. // Invalid component. Log error and keep going.
  1286. //
  1287. _LogError(OcManager,
  1288. OcErrLevWarning,
  1289. MSG_OC_INVALID_COMP_IN_SECT,
  1290. OcManager->MasterOcInfPath,
  1291. SectionName,
  1292. ComponentName
  1293. );
  1294. } else {
  1295. //
  1296. // Remember the string id for this component.
  1297. //
  1298. OcManager->WizardPagesOrder[*PageList][ActualCount++] = Id;
  1299. }
  1300. j++;
  1301. }
  1302. } else {
  1303. //
  1304. // Default ordering, which is the order in which the components
  1305. // were listed in the [Components] section
  1306. //
  1307. CopyMemory(
  1308. OcManager->WizardPagesOrder[*PageList],
  1309. OcManager->TopLevelOcStringIds,
  1310. OcManager->TopLevelOcCount * sizeof(LONG)
  1311. );
  1312. }
  1313. }
  1314. }
  1315. // get the caption for various pages
  1316. if(SetupFindFirstLine(OcManager->MasterOcInf,szPageTitle,szSetupTitle,&InfContext)) {
  1317. // Found it
  1318. SetupGetStringField(
  1319. &InfContext,
  1320. 1, // index of the field to get
  1321. OcManager->SetupPageTitle, // optional, receives the field
  1322. sizeof(OcManager->SetupPageTitle)/sizeof(OcManager->SetupPageTitle[0]), // size of the provided buffer
  1323. NULL);
  1324. }
  1325. return(TRUE);
  1326. c1:
  1327. sapiAssert(OcManager->MasterOcInf != INVALID_HANDLE_VALUE);
  1328. SetupCloseInfFile(OcManager->MasterOcInf);
  1329. c0:
  1330. return(FALSE);
  1331. }
  1332. BOOL
  1333. pOcSetOcManagerDirIds(
  1334. IN HINF InfHandle,
  1335. IN LPCTSTR MasterOcInfName,
  1336. IN LPCTSTR ComponentName
  1337. )
  1338. /*++
  1339. Routine Description:
  1340. This routine sets up the pre-defined OC Manager directory ids for
  1341. per-component infs.
  1342. DIRID_OCM_MASTERINF
  1343. DIRID_OCM_MASTERINF_PLAT
  1344. DIRID_OCM_MASTERINF_COMP
  1345. DIRID_OCM_MASTERINF_COMP_PLAT
  1346. Arguments:
  1347. InfHandle - supplies handle to open inf file
  1348. MasterOcInfName - win32 path to master oc inf
  1349. ComponentName - simple shortname for the component
  1350. Return Value:
  1351. Boolean value indicating outcome. If FALSE, caller can assume OOM.
  1352. --*/
  1353. {
  1354. TCHAR Path[MAX_PATH];
  1355. TCHAR *p;
  1356. #if defined(_AMD64_)
  1357. LPCTSTR Platform = TEXT("AMD64");
  1358. #elif defined(_X86_)
  1359. LPCTSTR Platform = (IsNEC_98) ? TEXT("NEC98") : TEXT("I386");
  1360. #elif defined(_IA64_)
  1361. LPCTSTR Platform = TEXT("IA64");
  1362. #else
  1363. #error "No Target Architecture"
  1364. #endif
  1365. lstrcpy(Path,MasterOcInfName);
  1366. if(p = _tcsrchr(Path,TEXT('\\'))) {
  1367. *p = 0;
  1368. } else {
  1369. //
  1370. // Something is very broken
  1371. //
  1372. return(FALSE);
  1373. }
  1374. if(!SetupSetDirectoryId(InfHandle,DIRID_OCM_MASTERINF,Path)) {
  1375. return(FALSE);
  1376. }
  1377. if(!SetupSetDirectoryIdEx(InfHandle,DIRID_OCM_PLATFORM,Platform,SETDIRID_NOT_FULL_PATH,0,0)) {
  1378. return(FALSE);
  1379. }
  1380. if(!SetupSetDirectoryIdEx(
  1381. InfHandle,DIRID_OCM_PLATFORM_ALTERNATE,
  1382. #ifdef _X86_
  1383. TEXT("X86"),
  1384. #else
  1385. Platform,
  1386. #endif
  1387. SETDIRID_NOT_FULL_PATH,0,0)) {
  1388. return(FALSE);
  1389. }
  1390. if(!SetupSetDirectoryIdEx(InfHandle,DIRID_OCM_COMPONENT,ComponentName,SETDIRID_NOT_FULL_PATH,0,0)) {
  1391. return(FALSE);
  1392. }
  1393. return(TRUE);
  1394. }
  1395. BOOL
  1396. pOcLoadInfsAndDlls(
  1397. IN OUT POC_MANAGER OcManager,
  1398. OUT PBOOL Canceled,
  1399. IN PVOID Log
  1400. )
  1401. /*++
  1402. Routine Description:
  1403. Loads per-component INFs and installation DLLs.
  1404. This includes invoking the preinitialization and initialization
  1405. entry points in the DLLs.
  1406. Arguments:
  1407. OcManager - supplies OC manager context structure
  1408. Cancelled - receives a flag that is valid when this routine fails,
  1409. indicating whether the failure was caused by a component
  1410. canceling.
  1411. Log - supplies a handle to use to log errors.
  1412. Return Value:
  1413. Boolean value indicating outcome
  1414. --*/
  1415. {
  1416. UINT i;
  1417. OPTIONAL_COMPONENT Oc;
  1418. OC_INF OcInf;
  1419. UINT ErrorLine;
  1420. UINT Flags;
  1421. UINT ErrorCode;
  1422. PCTSTR InfName;
  1423. PCTSTR ComponentName;
  1424. TCHAR Library[MAX_PATH];
  1425. BOOL b;
  1426. INFCONTEXT Context;
  1427. *Canceled = FALSE;
  1428. //
  1429. // The top-level component strctures have everything we need.
  1430. // Spin through them.
  1431. //
  1432. for(i=0; i<OcManager->TopLevelOcCount; i++) {
  1433. //
  1434. // Get the OC data from the string table.
  1435. //
  1436. pSetupStringTableGetExtraData(
  1437. OcManager->ComponentStringTable,
  1438. OcManager->TopLevelOcStringIds[i],
  1439. &Oc,
  1440. sizeof(OPTIONAL_COMPONENT)
  1441. );
  1442. if(Oc.InfStringId == -1) {
  1443. //
  1444. // The master OC inf specified that this component has no per-component inf.
  1445. //
  1446. OcInf.Handle = INVALID_HANDLE_VALUE;
  1447. } else {
  1448. //
  1449. // Load the per-component INF if it has not already been loaded.
  1450. //
  1451. pSetupStringTableGetExtraData(OcManager->InfListStringTable,Oc.InfStringId,&OcInf,sizeof(OC_INF));
  1452. if(!OcInf.Handle) {
  1453. InfName = pSetupStringTableStringFromId(OcManager->InfListStringTable,Oc.InfStringId);
  1454. if (!InfName) {
  1455. _LogError(OcManager,OcErrLevError,MSG_OC_OOM);
  1456. return(FALSE);
  1457. }
  1458. if(OcManager->InternalFlags & OCMFLAG_NEWINF) {
  1459. // First try the directory the master inf is in
  1460. lstrcpy(Library, OcManager->SourceDir);
  1461. pSetupConcatenatePaths(Library, InfName, MAX_PATH, NULL);
  1462. } else {
  1463. pOcFormSuitePath(OcManager->SuiteName,InfName,Library);
  1464. }
  1465. if(FileExists(Library, NULL)) {
  1466. OcInf.Handle = SetupOpenInfFile(Library,NULL,INF_STYLE_WIN4,&ErrorLine);
  1467. } else {
  1468. //
  1469. // Use standard inf search rules if the inf can't be found
  1470. // in the special suite directory.
  1471. //
  1472. OcInf.Handle = SetupOpenInfFile(InfName,NULL,INF_STYLE_WIN4,&ErrorLine);
  1473. }
  1474. if(OcInf.Handle == INVALID_HANDLE_VALUE) {
  1475. //
  1476. // Log error.
  1477. //
  1478. _LogError(OcManager,OcErrLevError,MSG_OC_CANT_OPEN_INF,InfName,GetLastError(),ErrorLine);
  1479. return(FALSE);
  1480. } else {
  1481. // open the layout file
  1482. SetupOpenAppendInfFile(NULL, OcInf.Handle, NULL);
  1483. //
  1484. // Remember inf handle and set OC Manager DIRIDs.
  1485. //
  1486. pSetupStringTableSetExtraData(
  1487. OcManager->InfListStringTable,
  1488. Oc.InfStringId,
  1489. &OcInf,
  1490. sizeof(OC_INF)
  1491. );
  1492. b = pOcSetOcManagerDirIds(
  1493. OcInf.Handle,
  1494. OcManager->MasterOcInfPath,
  1495. pSetupStringTableStringFromId(OcManager->ComponentStringTable,OcManager->TopLevelOcStringIds[i])
  1496. );
  1497. if(!b) {
  1498. _LogError(OcManager,OcErrLevError,MSG_OC_OOM);
  1499. return(FALSE);
  1500. }
  1501. OcManager->SubComponentsPresent = TRUE;
  1502. }
  1503. }
  1504. }
  1505. //
  1506. // Load the DLL and get the entry point address.
  1507. // We make no attempt to track duplicates like we do for infs --
  1508. // the underlying OS does that for us.
  1509. //
  1510. // The dll could be either in the special suite directory for this
  1511. // master oc inf, or in a standard place. LoadLibraryEx does
  1512. // exactly what we want.
  1513. //
  1514. if(Oc.InstallationDllName[0] && Oc.InterfaceFunctionName[0]) {
  1515. if (OcManager->InternalFlags & OCMFLAG_NEWINF) {
  1516. // First try the directory the master inf is in
  1517. lstrcpy(Library, OcManager->SourceDir);
  1518. pSetupConcatenatePaths(Library, Oc.InstallationDllName, MAX_PATH, NULL);
  1519. Oc.InstallationDll = LoadLibraryEx(Library,NULL,LOAD_WITH_ALTERED_SEARCH_PATH);
  1520. }
  1521. // Try the Setup Directory
  1522. if (! Oc.InstallationDll ) {
  1523. pOcFormSuitePath(OcManager->SuiteName,Oc.InstallationDllName,Library);
  1524. Oc.InstallationDll = LoadLibraryEx(Library,NULL,LOAD_WITH_ALTERED_SEARCH_PATH);
  1525. }
  1526. // lastly try anywhere in the path
  1527. if ( ! Oc.InstallationDll ) {
  1528. Oc.InstallationDll = LoadLibraryEx(Oc.InstallationDllName,NULL,LOAD_WITH_ALTERED_SEARCH_PATH);
  1529. }
  1530. //
  1531. // Failure is taken care of below....
  1532. //
  1533. if (Oc.InstallationDll) {
  1534. Oc.InstallationRoutine = (POCSETUPPROC)GetProcAddress(
  1535. Oc.InstallationDll,
  1536. Oc.InterfaceFunctionName);
  1537. } else {
  1538. Oc.InstallationRoutine = NULL;
  1539. }
  1540. } else {
  1541. Oc.InstallationDll = MyModuleHandle;
  1542. Oc.InstallationRoutine = StandAloneSetupAppInterfaceRoutine;
  1543. }
  1544. if(Oc.InstallationDll && Oc.InstallationRoutine) {
  1545. //
  1546. // Success. Call the init-related entry points. Note that we can't call
  1547. // any entry point except the preinit one until after we've stored
  1548. // the ansi/unicode flag into the OPTIONAL_COMPONENT structure.
  1549. //
  1550. // Also note that before we do this we have to store the Oc structure,
  1551. // otherwise the interface routine is NULL and we fault.
  1552. //
  1553. pSetupStringTableSetExtraData(
  1554. OcManager->ComponentStringTable,
  1555. OcManager->TopLevelOcStringIds[i],
  1556. &Oc,
  1557. sizeof(OPTIONAL_COMPONENT)
  1558. );
  1559. Oc.Flags = OcInterfacePreinitialize(OcManager,OcManager->TopLevelOcStringIds[i]);
  1560. if(!Oc.Flags) {
  1561. //
  1562. // If this fails, then assume the DLL is written for a different
  1563. // platform or version, for example a Unicode/ANSI problem.
  1564. //
  1565. _LogError(OcManager,
  1566. OcErrLevError,
  1567. MSG_OC_DLL_PREINIT_FAILED,
  1568. pSetupStringTableStringFromId(
  1569. OcManager->ComponentStringTable,
  1570. OcManager->TopLevelOcStringIds[i]
  1571. ),
  1572. Oc.InstallationDllName
  1573. );
  1574. return(FALSE);
  1575. }
  1576. } else {
  1577. //
  1578. // Failure, log error.
  1579. //
  1580. _LogError(OcManager,
  1581. OcErrLevError,
  1582. MSG_OC_DLL_LOAD_FAIL,
  1583. Oc.InstallationDllName,
  1584. Oc.InterfaceFunctionName,
  1585. GetLastError()
  1586. );
  1587. return(FALSE);
  1588. }
  1589. //
  1590. // Set the OC data back into the string table.
  1591. // After this we can call other interface entry points since
  1592. // the ansi/unicode flag will now be stored in the OPTIONAL_COMPONENT
  1593. // structure for the component.
  1594. //
  1595. pSetupStringTableSetExtraData(
  1596. OcManager->ComponentStringTable,
  1597. OcManager->TopLevelOcStringIds[i],
  1598. &Oc,
  1599. sizeof(OPTIONAL_COMPONENT)
  1600. );
  1601. ErrorCode = OcInterfaceInitComponent(
  1602. OcManager,
  1603. OcManager->TopLevelOcStringIds[i]
  1604. );
  1605. if(ErrorCode == NO_ERROR) {
  1606. // Send down extra helper routines.
  1607. if ((Oc.InternalFlags & OCFLAG_NOEXTRAROUTINES)==0) {
  1608. ErrorCode = OcInterfaceExtraRoutines(
  1609. OcManager,
  1610. OcManager->TopLevelOcStringIds[i]
  1611. );
  1612. }
  1613. }
  1614. if(ErrorCode == NO_ERROR) {
  1615. if (OcManager->InternalFlags & OCMFLAG_LANGUAGEAWARE) {
  1616. //
  1617. // Send down a set-language request.
  1618. // Ignore the result.
  1619. //
  1620. OcInterfaceSetLanguage(
  1621. OcManager,
  1622. OcManager->TopLevelOcStringIds[i],
  1623. LANGIDFROMLCID(GetThreadLocale())
  1624. );
  1625. }
  1626. } else {
  1627. if(ErrorCode == ERROR_CANCELLED) {
  1628. // cancel will stop oc manager only if
  1629. // we aren't running in gui-mode setup
  1630. *Canceled = TRUE;
  1631. if (OcManager->SetupData.OperationFlags & SETUPOP_STANDALONE)
  1632. return FALSE;
  1633. } else {
  1634. _LogError(OcManager,
  1635. OcErrLevError,
  1636. MSG_OC_DLL_INIT_FAILED,
  1637. pSetupStringTableStringFromId(
  1638. OcManager->ComponentStringTable,
  1639. OcManager->TopLevelOcStringIds[i]
  1640. )
  1641. );
  1642. }
  1643. pOcRemoveComponent(OcManager, OcManager->TopLevelOcStringIds[i], pidLoadComponent);
  1644. }
  1645. }
  1646. //
  1647. // Now go gather additional information about subcomponents
  1648. // (descriptions, parentage, needs=, etc).
  1649. //
  1650. return(pOcBuildSubcomponentLists(OcManager,Log));
  1651. }
  1652. BOOL
  1653. pOcUnloadInfsAndDlls(
  1654. IN OUT POC_MANAGER OcManager,
  1655. IN PVOID Log
  1656. )
  1657. /*++
  1658. Routine Description:
  1659. Unloads per-component INFs and installation DLLs that were
  1660. previously loaded by pOcLoadInfsAndDlls().
  1661. This routine does NOT call the interface entry points to
  1662. uninitialize the installation DLLs.
  1663. Arguments:
  1664. OcManager - supplies OC manager context structure
  1665. Log - supplies a handle to use to log errors.
  1666. Return Value:
  1667. Boolean value indicating outcome.
  1668. If FALSE, an error will have been logged to indicate what failed.
  1669. --*/
  1670. {
  1671. OPTIONAL_COMPONENT Oc;
  1672. OC_INF OcInf;
  1673. UINT i;
  1674. //
  1675. // Unload Dlls.
  1676. //
  1677. for(i=0; i<OcManager->TopLevelOcCount; i++) {
  1678. pSetupStringTableGetExtraData(
  1679. OcManager->ComponentStringTable,
  1680. OcManager->TopLevelOcStringIds[i],
  1681. &Oc,
  1682. sizeof(OPTIONAL_COMPONENT)
  1683. );
  1684. if(Oc.InstallationDll && (Oc.InstallationDll != MyModuleHandle)) {
  1685. FreeLibrary(Oc.InstallationDll);
  1686. Oc.InstallationDll = NULL;
  1687. }
  1688. Oc.InstallationRoutine = NULL;
  1689. Oc.InstallationDllName[0] = 0;
  1690. Oc.InterfaceFunctionName[0]= 0;
  1691. if(Oc.InfStringId != -1) {
  1692. pSetupStringTableGetExtraData(
  1693. OcManager->InfListStringTable,
  1694. Oc.InfStringId,
  1695. &OcInf,
  1696. sizeof(OC_INF)
  1697. );
  1698. if(OcInf.Handle && (OcInf.Handle != INVALID_HANDLE_VALUE)) {
  1699. SetupCloseInfFile(OcInf.Handle);
  1700. OcInf.Handle = INVALID_HANDLE_VALUE;
  1701. pSetupStringTableSetExtraData(
  1702. OcManager->InfListStringTable,
  1703. Oc.InfStringId,
  1704. &OcInf,
  1705. sizeof(OC_INF)
  1706. );
  1707. }
  1708. Oc.InfStringId = -1;
  1709. }
  1710. pSetupStringTableSetExtraData(
  1711. OcManager->ComponentStringTable,
  1712. OcManager->TopLevelOcStringIds[i],
  1713. &Oc,
  1714. sizeof(OPTIONAL_COMPONENT)
  1715. );
  1716. }
  1717. return(TRUE);
  1718. }
  1719. BOOL
  1720. pOcManagerInitPrivateDataStore(
  1721. IN OUT POC_MANAGER OcManager,
  1722. IN PVOID Log
  1723. )
  1724. /*++
  1725. Routine Description:
  1726. Initializes the private data store for components.
  1727. The registry is used as the backing store for private data.
  1728. We make use of volatile keys to help ensure that this data is temporary
  1729. in nature.
  1730. Arguments:
  1731. OcManager - supplies OC Manager context stucture.
  1732. Log - supplies a handle to use to log errors.
  1733. Return Value:
  1734. Boolean value indicating outcome. If FALSE an error will have
  1735. been logged.
  1736. --*/
  1737. {
  1738. LONG l;
  1739. DWORD Disposition;
  1740. //
  1741. // Start out by forming a unique name for this instantiation
  1742. // of the OC Manager.
  1743. //
  1744. wsprintf(OcManager->PrivateDataSubkey,TEXT("%x:%x"),GetCurrentProcessId(),OcManager);
  1745. //
  1746. // Open/create the private data root. Save the handle.
  1747. //
  1748. l = RegCreateKeyEx(
  1749. HKEY_LOCAL_MACHINE,
  1750. szPrivateDataRoot,
  1751. 0,
  1752. NULL,
  1753. REG_OPTION_VOLATILE,
  1754. KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_SET_VALUE,
  1755. NULL,
  1756. &OcManager->hKeyPrivateDataRoot,
  1757. &Disposition
  1758. );
  1759. if(l != NO_ERROR) {
  1760. OcManager->hKeyPrivateDataRoot = NULL;
  1761. OcManager->hKeyPrivateData = NULL;
  1762. _LogError(OcManager,OcErrLevWarning,MSG_OC_CREATE_KEY_FAILED,szPrivateDataRoot,l);
  1763. return(FALSE);
  1764. }
  1765. //
  1766. // Get rid of the private data tree if it already exists for some reason.
  1767. //
  1768. if(Disposition == REG_OPENED_EXISTING_KEY) {
  1769. pSetupRegistryDelnode(OcManager->hKeyPrivateDataRoot,OcManager->PrivateDataSubkey);
  1770. }
  1771. //
  1772. // Create the private data tree. Save the handle.
  1773. //
  1774. l = RegCreateKeyEx(
  1775. OcManager->hKeyPrivateDataRoot,
  1776. OcManager->PrivateDataSubkey,
  1777. 0,
  1778. NULL,
  1779. REG_OPTION_VOLATILE,
  1780. KEY_CREATE_SUB_KEY | KEY_QUERY_VALUE | KEY_SET_VALUE,
  1781. NULL,
  1782. &OcManager->hKeyPrivateData,
  1783. &Disposition
  1784. );
  1785. if(l != NO_ERROR) {
  1786. RegCloseKey(OcManager->hKeyPrivateDataRoot);
  1787. OcManager->hKeyPrivateDataRoot = NULL;
  1788. OcManager->hKeyPrivateData = NULL;
  1789. _LogError(OcManager,OcErrLevWarning,MSG_OC_CREATE_KEY_FAILED,OcManager->PrivateDataSubkey,l);
  1790. return(FALSE);
  1791. }
  1792. return(TRUE);
  1793. }
  1794. VOID
  1795. pOcManagerTearDownPrivateDataStore(
  1796. IN OUT POC_MANAGER OcManager
  1797. )
  1798. {
  1799. RegCloseKey(OcManager->hKeyPrivateData);
  1800. pSetupRegistryDelnode(OcManager->hKeyPrivateDataRoot,OcManager->PrivateDataSubkey);
  1801. RegCloseKey(OcManager->hKeyPrivateDataRoot);
  1802. OcManager->hKeyPrivateDataRoot = NULL;
  1803. OcManager->hKeyPrivateData = NULL;
  1804. }
  1805. UINT
  1806. pOcQueryOrSetNewInf(
  1807. IN PCTSTR MasterOcInfName,
  1808. OUT PTSTR SuiteName,
  1809. IN DWORD operation
  1810. )
  1811. /*++
  1812. Routine Description:
  1813. Determine whether a master OC inf has been encountered before,
  1814. or remember that a master inf has been encountered.
  1815. This information is stored in the registry.
  1816. Arguments:
  1817. MasterOcInfName - supplies the full Win32 path of the master OC inf.
  1818. SuiteName - receives the filename part of the .inf, without any
  1819. extension. This is suitable for use as a tag representing the
  1820. suite that the master INF is for. This buffer should be
  1821. MAX_PATH TCHAR elements.
  1822. QueryOnly - if TRUE, then the routine is to query whether the
  1823. master inf has been previously processed. If FALSE, then
  1824. the routine is to remember that the inf has been processed.
  1825. Return Value:
  1826. If QueryOnly is TRUE:
  1827. TRUE if the INF has been encountered before, FALSE if not.
  1828. If QueryOnly is FALSE:
  1829. Win32 error code indicating outcome.
  1830. --*/
  1831. {
  1832. PTCHAR p;
  1833. HKEY hKey;
  1834. LONG l;
  1835. DWORD Type;
  1836. DWORD Size;
  1837. DWORD Data;
  1838. //
  1839. // Form the suite name. The MasterOcInfName is expected to be
  1840. // a full path so this is pretty easy. We'll try to be at least
  1841. // a little more robust.
  1842. //
  1843. if(p = _tcsrchr(MasterOcInfName,TEXT('\\'))) {
  1844. p++;
  1845. } else {
  1846. p = (PTCHAR)MasterOcInfName;
  1847. }
  1848. lstrcpyn(SuiteName,p,MAX_PATH);
  1849. if(p = _tcsrchr(SuiteName,TEXT('.'))) {
  1850. *p = 0;
  1851. }
  1852. //
  1853. // Look in the registry to see if there is a value entry
  1854. // with the suite name in there.
  1855. //
  1856. l = RegCreateKeyEx(
  1857. HKEY_LOCAL_MACHINE,
  1858. szMasterInfs,
  1859. 0,
  1860. NULL,
  1861. REG_OPTION_NON_VOLATILE,
  1862. (operation == infQuery) ? KEY_QUERY_VALUE : KEY_SET_VALUE,
  1863. NULL,
  1864. &hKey,
  1865. &Type
  1866. );
  1867. if (l != NO_ERROR)
  1868. return (operation == infQuery) ? 0 : l;
  1869. // do the job
  1870. switch (operation) {
  1871. case infQuery:
  1872. Size = sizeof(DWORD);
  1873. l = RegQueryValueEx(hKey,SuiteName,NULL,&Type,(LPBYTE)&Data,&Size);
  1874. if((l == NO_ERROR) && (Type == REG_DWORD) && Data)
  1875. l = TRUE;
  1876. else
  1877. l = FALSE;
  1878. break;
  1879. case infSet:
  1880. Data = 1;
  1881. l = RegSetValueEx(hKey,SuiteName,0,REG_DWORD,(LPBYTE)&Data,sizeof(DWORD));
  1882. break;
  1883. case infReset:
  1884. l = RegDeleteValue(hKey,SuiteName);
  1885. break;
  1886. }
  1887. RegCloseKey(hKey);
  1888. return l;
  1889. }
  1890. PVOID
  1891. OcInitialize(
  1892. IN POCM_CLIENT_CALLBACKS Callbacks,
  1893. IN LPCTSTR MasterOcInfName,
  1894. IN UINT Flags,
  1895. OUT PBOOL ShowError,
  1896. IN PVOID Log
  1897. )
  1898. /*++
  1899. Routine Description:
  1900. Initializes the OC Manager. The master OC INF is loaded and
  1901. processed, which includes INFs, loading setup interface DLLs and
  1902. querying interface entry points. A set of in-memory structures
  1903. is built up.
  1904. If the OC INF hasn't been processed before then we copy the
  1905. installation files for the component(s) into %windir%\system32\setup.
  1906. Files are expected to be in the same directory as the OC inf.
  1907. Arguments:
  1908. Callbacks - supplies a set of routines used by the OC Manager
  1909. to perform various functions.
  1910. MasterOcInfName - supplies the full Win32 path of the master OC inf.
  1911. Flags - supplies various flags that control operation.
  1912. ShowError - receives a flag that is valid if this routine fails,
  1913. advising the caller whether he should show an error message.
  1914. Log - supplies a handle to use to log errors.
  1915. Return Value:
  1916. Opaque pointer to internal context structure or NULL if failure.
  1917. If NULL, an error will have been logged to indicate what failed.
  1918. --*/
  1919. {
  1920. POC_MANAGER OcManager;
  1921. UINT i;
  1922. HKEY hKey;
  1923. DWORD DontCare;
  1924. LONG l;
  1925. BOOL Canceled;
  1926. BOOL rc;
  1927. TCHAR *p;
  1928. *ShowError = TRUE;
  1929. // init the wizard handle
  1930. WizardDialogHandle = NULL;
  1931. //
  1932. // Allocate a new OC MANAGER structure
  1933. //
  1934. OcManager = pSetupMalloc(sizeof(OC_MANAGER));
  1935. if(!OcManager) {
  1936. //
  1937. // Make the callback work
  1938. //
  1939. OC_MANAGER ocm;
  1940. ocm.Callbacks = *Callbacks;
  1941. _LogError(&ocm,OcErrLevFatal,MSG_OC_OOM);
  1942. goto c0;
  1943. }
  1944. ZeroMemory(OcManager,sizeof(OC_MANAGER));
  1945. OcManager->Callbacks = *Callbacks;
  1946. OcManager->CurrentComponentStringId = -1;
  1947. OcManager->SetupMode = SETUPMODE_CUSTOM;
  1948. OcManager->UnattendedInf = INVALID_HANDLE_VALUE;
  1949. gLastOcManager = (POC_MANAGER) OcManager;
  1950. if (!pOcInitPaths(OcManager, MasterOcInfName)) {
  1951. _LogError(OcManager,OcErrLevFatal,MSG_OC_MASTER_INF_LOAD_FAILED);
  1952. goto c1;
  1953. }
  1954. sapiAssert(*OcManager->MasterOcInfPath);
  1955. #ifdef UNICODE
  1956. OcFillInSetupDataW(&(OcManager->SetupData));
  1957. #else
  1958. OcFillInSetupDataA(&(OcManager->SetupData));
  1959. #endif
  1960. // Say the user canceled until we successfully complete an install
  1961. // This will prevent Inf Files from being copied to system32\setup
  1962. OcManager->InternalFlags |= OCMFLAG_USERCANCELED;
  1963. // Make sure the OC Manager key exists in the registry as a non-volatile key.
  1964. // Other parts of the code deal in volatile keys so some care is needed to
  1965. // avoid getting a volatile key under which we want to create non-volatile entries.
  1966. //
  1967. l = RegCreateKeyEx(
  1968. HKEY_LOCAL_MACHINE,
  1969. szOcManagerRoot,
  1970. 0,
  1971. NULL,
  1972. REG_OPTION_NON_VOLATILE,
  1973. KEY_CREATE_SUB_KEY | KEY_QUERY_VALUE | KEY_SET_VALUE,
  1974. NULL,
  1975. &hKey,
  1976. &DontCare
  1977. );
  1978. if(l == NO_ERROR) {
  1979. RegCloseKey(hKey);
  1980. } else {
  1981. _LogError(OcManager,OcErrLevWarning,MSG_OC_CREATE_KEY_FAILED,szOcManagerRoot,l);
  1982. }
  1983. // get the locale info
  1984. locale.lcid = GetSystemDefaultLCID();
  1985. GetLocaleInfo(locale.lcid,
  1986. LOCALE_SDECIMAL,
  1987. locale.DecimalSeparator,
  1988. sizeof(locale.DecimalSeparator)/sizeof(TCHAR));
  1989. //
  1990. // Initialize string tables.
  1991. //
  1992. OcManager->InfListStringTable = pSetupStringTableInitializeEx(sizeof(OC_INF),0);
  1993. if(!OcManager->InfListStringTable) {
  1994. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  1995. goto c1;
  1996. }
  1997. OcManager->ComponentStringTable = pSetupStringTableInitializeEx(sizeof(OPTIONAL_COMPONENT),0);
  1998. if(!OcManager->ComponentStringTable) {
  1999. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  2000. goto c2;
  2001. }
  2002. //
  2003. // Initialize various arrays. We alloc 0-length blocks here to allow
  2004. // realloc later without special casing.
  2005. //
  2006. OcManager->TopLevelOcStringIds = pSetupMalloc(0);
  2007. if(!OcManager->TopLevelOcStringIds) {
  2008. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  2009. goto c3;
  2010. }
  2011. for(i=0; i<WizPagesTypeMax; i++) {
  2012. OcManager->WizardPagesOrder[i] = pSetupMalloc(0);
  2013. if(!OcManager->WizardPagesOrder[i]) {
  2014. _LogError(OcManager,OcErrLevFatal,MSG_OC_OOM);
  2015. goto c4;
  2016. }
  2017. }
  2018. //
  2019. // Initialize the private data store.
  2020. //
  2021. if(!pOcManagerInitPrivateDataStore(OcManager,Log)) {
  2022. _LogError(OcManager,OcErrLevFatal,MSG_OC_PRIVATEDATASTORE_INIT_FAILED);
  2023. goto c4;
  2024. }
  2025. //
  2026. // Load the master OC inf.
  2027. //
  2028. if(!pOcLoadMasterOcInf(OcManager, Flags, Log)) {
  2029. _LogError(OcManager,OcErrLevFatal,MSG_OC_MASTER_INF_LOAD_FAILED);
  2030. goto c5;
  2031. }
  2032. // set the source path
  2033. lstrcpy(OcManager->SourceDir, OcManager->MasterOcInfPath);
  2034. if (p = _tcsrchr(OcManager->SourceDir, TEXT('\\')))
  2035. *p = 0;
  2036. else
  2037. GetCurrentDirectory(MAX_PATH, OcManager->SourceDir);
  2038. //
  2039. // Load the unattend file
  2040. //
  2041. if(OcManager->SetupData.UnattendFile[0]) {
  2042. OcManager->UnattendedInf = SetupOpenInfFile(
  2043. OcManager->SetupData.UnattendFile,
  2044. NULL,
  2045. INF_STYLE_WIN4,
  2046. NULL
  2047. );
  2048. if (OcManager->UnattendedInf == INVALID_HANDLE_VALUE && GetLastError() == ERROR_WRONG_INF_STYLE) {
  2049. OcManager->UnattendedInf = SetupOpenInfFile(
  2050. OcManager->SetupData.UnattendFile,
  2051. NULL,
  2052. INF_STYLE_OLDNT,
  2053. NULL
  2054. );
  2055. }
  2056. if(OcManager->UnattendedInf == INVALID_HANDLE_VALUE) {
  2057. _LogError(OcManager,OcErrLevFatal,MSG_OC_CANT_OPEN_INF,OcManager->SetupData.UnattendFile,GetLastError());
  2058. goto c6;
  2059. }
  2060. }
  2061. //
  2062. // Load component infs and DLLs.
  2063. //
  2064. rc = pOcLoadInfsAndDlls(OcManager, &Canceled, Log);
  2065. //
  2066. // Error already logged if necessary
  2067. //
  2068. if (Canceled)
  2069. *ShowError = FALSE;
  2070. if (!rc)
  2071. goto c6;
  2072. pOcClearAllErrorStates(OcManager);
  2073. if(!pOcFetchInstallStates(OcManager)) {
  2074. //
  2075. // Error already logged.
  2076. //
  2077. goto c6;
  2078. }
  2079. //
  2080. // Ask the components to give up a rough estimate
  2081. // of their sizes so we can say something meaningful in the list boxes.
  2082. //
  2083. pOcGetApproximateDiskSpace(OcManager);
  2084. return(OcManager);
  2085. c6:
  2086. sapiAssert(OcManager->MasterOcInf != INVALID_HANDLE_VALUE);
  2087. SetupCloseInfFile(OcManager->MasterOcInf);
  2088. if (OcManager->UnattendedInf != INVALID_HANDLE_VALUE)
  2089. SetupCloseInfFile(OcManager->UnattendedInf);
  2090. c5:
  2091. //
  2092. // Tear down private data store.
  2093. //
  2094. pOcManagerTearDownPrivateDataStore(OcManager);
  2095. c4:
  2096. if(OcManager->TopLevelOcStringIds) {
  2097. pSetupFree(OcManager->TopLevelOcStringIds);
  2098. for(i=0; OcManager->WizardPagesOrder[i] && (i<WizPagesTypeMax); i++) {
  2099. pSetupFree(OcManager->WizardPagesOrder[i]);
  2100. }
  2101. }
  2102. // free up the list of aborted components
  2103. if (OcManager->AbortedComponentIds) {
  2104. pSetupFree(OcManager->AbortedComponentIds);
  2105. }
  2106. c3:
  2107. pOcDestroyPerOcData(OcManager);
  2108. pSetupStringTableDestroy(OcManager->ComponentStringTable);
  2109. c2:
  2110. pSetupStringTableDestroy(OcManager->InfListStringTable);
  2111. c1:
  2112. pSetupFree(OcManager);
  2113. c0:
  2114. return(NULL);
  2115. }
  2116. VOID
  2117. OcTerminate(
  2118. IN OUT PVOID *OcManagerContext
  2119. )
  2120. /*++
  2121. Routine Description:
  2122. This routine shuts down the OC Manager, including calling the subcomponents
  2123. to clean themselves up, release resources, etc.
  2124. Arguments:
  2125. OcManagerContext - in input, supplies a pointer to a context value returned
  2126. by OcInitialize. On output, receives NULL.
  2127. Return Value:
  2128. None.
  2129. --*/
  2130. {
  2131. POC_MANAGER OcManager;
  2132. UINT u;
  2133. BOOL b;
  2134. OPTIONAL_COMPONENT Oc;
  2135. OC_INF OcInf;
  2136. LPCTSTR ComponentName;
  2137. LPCTSTR InfName;
  2138. sapiAssert(OcManagerContext && *OcManagerContext);
  2139. OcManager = *OcManagerContext;
  2140. *OcManagerContext = NULL;
  2141. //
  2142. // Run down the top-level OCs, calling the dlls to indicate that we're done.
  2143. // We don't tear down any infrastructure until after we've told all the dlls
  2144. // that we're done.
  2145. //
  2146. for(u=0; u<OcManager->TopLevelOcCount; u++) {
  2147. OcInterfaceCleanup(OcManager,OcManager->TopLevelOcStringIds[u]);
  2148. }
  2149. // if the user did not cancel setup
  2150. //
  2151. if (!(OcManager->InternalFlags & OCMFLAG_USERCANCELED)){
  2152. //
  2153. // Remember persistent install state.
  2154. //
  2155. pOcRememberInstallStates(OcManager);
  2156. // copy the master INF file over
  2157. if ( OcManager->InternalFlags & OCMFLAG_NEWINF ) {
  2158. b = pOcInstallSetupComponents(
  2159. NULL,
  2160. OcManager,
  2161. OcManager->SuiteName,
  2162. NULL,
  2163. _tcsrchr(OcManager->MasterOcInfPath,TEXT('\\')), // InfName,
  2164. NULL,
  2165. NULL
  2166. );
  2167. }
  2168. }
  2169. //
  2170. // Run down the top-level OCs and free DLLs and per-component infs.
  2171. //
  2172. for(u=0; u<OcManager->TopLevelOcCount; u++) {
  2173. ComponentName = pSetupStringTableStringFromId( // ComponentName
  2174. OcManager->ComponentStringTable,
  2175. OcManager->TopLevelOcStringIds[u]);
  2176. pSetupStringTableGetExtraData(
  2177. OcManager->ComponentStringTable,
  2178. OcManager->TopLevelOcStringIds[u],
  2179. &Oc,
  2180. sizeof(OPTIONAL_COMPONENT)
  2181. );
  2182. if(Oc.InstallationDll && (Oc.InstallationDll != MyModuleHandle)) {
  2183. //FreeLibrary(Oc.InstallationDll);
  2184. }
  2185. if(Oc.InfStringId != -1) {
  2186. pSetupStringTableGetExtraData(
  2187. OcManager->InfListStringTable,
  2188. Oc.InfStringId,
  2189. &OcInf,
  2190. sizeof(OC_INF)
  2191. );
  2192. if(OcInf.Handle && (OcInf.Handle != INVALID_HANDLE_VALUE)) {
  2193. SetupCloseInfFile(OcInf.Handle);
  2194. //
  2195. // Mark the handle as closed, is to components are shareing
  2196. // the same INF file, should only close the file once.
  2197. //
  2198. OcInf.Handle = INVALID_HANDLE_VALUE;
  2199. pSetupStringTableSetExtraData(
  2200. OcManager->InfListStringTable,
  2201. Oc.InfStringId,
  2202. &OcInf,
  2203. sizeof(OC_INF)
  2204. );
  2205. }
  2206. }
  2207. // This is a new install and we did not cancel out of setup
  2208. // copy the setup components to the setup dir otherwise a canceled
  2209. // setup will leave an upgrade dead in the water.
  2210. if ( ( (OcManager->InternalFlags & OCMFLAG_NEWINF )
  2211. || ( (OcManager->SetupMode & SETUPMODE_PRIVATE_MASK) == SETUPMODE_REMOVEALL ) )
  2212. && (! (OcManager->InternalFlags & OCMFLAG_USERCANCELED))){
  2213. if (Oc.InfStringId == -1) {
  2214. InfName = NULL;
  2215. } else {
  2216. InfName = pSetupStringTableStringFromId(OcManager->InfListStringTable,
  2217. Oc.InfStringId);
  2218. }
  2219. b = pOcInstallSetupComponents(
  2220. &Oc,
  2221. OcManager,
  2222. ComponentName,
  2223. Oc.InstallationDllName,
  2224. InfName,
  2225. NULL,
  2226. NULL
  2227. );
  2228. if(!b) {
  2229. _LogError(OcManager,OcErrLevFatal,MSG_OC_CANT_INSTALL_SETUP,ComponentName);
  2230. }
  2231. }
  2232. }
  2233. //
  2234. // Free string tables.
  2235. //
  2236. pOcDestroyPerOcData(OcManager);
  2237. pSetupStringTableDestroy(OcManager->ComponentStringTable);
  2238. pSetupStringTableDestroy(OcManager->InfListStringTable);
  2239. //
  2240. // Free the wizard page ordering arrays.
  2241. //
  2242. for(u=0; u<WizPagesTypeMax; u++) {
  2243. if(OcManager->WizardPagesOrder[u]) {
  2244. pSetupFree(OcManager->WizardPagesOrder[u]);
  2245. }
  2246. }
  2247. //
  2248. // Tear down the private data store.
  2249. //
  2250. pOcManagerTearDownPrivateDataStore(OcManager);
  2251. //
  2252. // Free the master oc inf and finally the oc manager context structure itself.
  2253. //
  2254. sapiAssert(OcManager->MasterOcInf != INVALID_HANDLE_VALUE);
  2255. SetupCloseInfFile(OcManager->MasterOcInf);
  2256. if (OcManager->UnattendedInf && OcManager->UnattendedInf != INVALID_HANDLE_VALUE)
  2257. SetupCloseInfFile(OcManager->UnattendedInf);
  2258. // If this is a remove all then Delete the master inf file too!
  2259. if ( !(OcManager->InternalFlags & OCMFLAG_USERCANCELED)
  2260. && ( (OcManager->SetupMode & SETUPMODE_PRIVATE_MASK)
  2261. == SETUPMODE_REMOVEALL )) {
  2262. TCHAR InFSuitePath[MAX_PATH];
  2263. // Se do it this way, so if you run remove all from the
  2264. // orginal source location we don't blow away that copy of the
  2265. // suite inf file.
  2266. pOcFormSuitePath(NULL,OcManager->MasterOcInfPath,InFSuitePath);
  2267. DeleteFile(InFSuitePath);
  2268. }
  2269. // free up the list of aborted components
  2270. if (OcManager->AbortedComponentIds) {
  2271. pSetupFree(OcManager->AbortedComponentIds);
  2272. }
  2273. if (OcManager->TopLevelOcStringIds) {
  2274. pSetupFree(OcManager->TopLevelOcStringIds);
  2275. }
  2276. if (OcManager->TopLevelParentOcStringIds) {
  2277. pSetupFree(OcManager->TopLevelParentOcStringIds);
  2278. }
  2279. //
  2280. // free the oc manager context structure itself.
  2281. //
  2282. pSetupFree(OcManager);
  2283. gLastOcManager = NULL;
  2284. }
  2285. BOOL
  2286. OcSubComponentsPresent(
  2287. IN PVOID OcManagerContext
  2288. )
  2289. /*++
  2290. Routine Description:
  2291. This routine tells the caller if there are any
  2292. subcomponents available on the details page.
  2293. Arguments:
  2294. OcManager - supplies pointer to OC Manager context structure.
  2295. Return Value:
  2296. TRUE = yes, there are subcomponents
  2297. FALSE = no way
  2298. --*/
  2299. {
  2300. POC_MANAGER OcManager = (POC_MANAGER)OcManagerContext;
  2301. if (!OcManagerContext) {
  2302. return FALSE;
  2303. }
  2304. return OcManager->SubComponentsPresent;
  2305. }
  2306. VOID
  2307. pOcDestroyPerOcData(
  2308. IN POC_MANAGER OcManager
  2309. )
  2310. /*++
  2311. Routine Description:
  2312. This routine frees all data allocated as part of the per-subcomponent
  2313. data structures. The component list string table is enumerated;
  2314. the OPTIONAL_COMPONENT structures have several pointers for arrays
  2315. that must be freed.
  2316. Arguments:
  2317. OcManager - supplies pointer to OC Manager context structure.
  2318. Return Value:
  2319. None.
  2320. --*/
  2321. {
  2322. OPTIONAL_COMPONENT OptionalComponent;
  2323. pSetupStringTableEnum(
  2324. OcManager->ComponentStringTable,
  2325. &OptionalComponent,
  2326. sizeof(OPTIONAL_COMPONENT),
  2327. pOcDestroyPerOcDataStringCB,
  2328. 0
  2329. );
  2330. }
  2331. BOOL
  2332. pOcDestroyPerOcDataStringCB(
  2333. IN PVOID StringTable,
  2334. IN LONG StringId,
  2335. IN PCTSTR String,
  2336. IN POPTIONAL_COMPONENT Oc,
  2337. IN UINT OcSize,
  2338. IN LPARAM Unused
  2339. )
  2340. /*++
  2341. Routine Description:
  2342. String table callback routine that is the worker routine for
  2343. pOcDestroyPerOcData.
  2344. Arguments:
  2345. Standard string table callback arguments.
  2346. Return Value:
  2347. Always returns TRUE to continue enumeration.
  2348. --*/
  2349. {
  2350. UNREFERENCED_PARAMETER(StringTable);
  2351. UNREFERENCED_PARAMETER(StringId);
  2352. UNREFERENCED_PARAMETER(String);
  2353. UNREFERENCED_PARAMETER(OcSize);
  2354. UNREFERENCED_PARAMETER(Unused);
  2355. if(Oc->NeedsStringIds) {
  2356. pSetupFree(Oc->NeedsStringIds);
  2357. }
  2358. if(Oc->NeededByStringIds) {
  2359. pSetupFree(Oc->NeededByStringIds);
  2360. }
  2361. if (Oc->ExcludeStringIds){
  2362. pSetupFree(Oc->ExcludeStringIds);
  2363. }
  2364. if(Oc->ExcludedByStringIds){
  2365. pSetupFree(Oc->ExcludedByStringIds);
  2366. }
  2367. if (Oc->HelperContext) {
  2368. pSetupFree(Oc->HelperContext);
  2369. }
  2370. return(TRUE);
  2371. }
  2372. BOOL
  2373. pOcClearAllErrorStatesCB(
  2374. IN PVOID StringTable,
  2375. IN LONG StringId,
  2376. IN PCTSTR String,
  2377. IN POPTIONAL_COMPONENT Oc,
  2378. IN UINT OcSize,
  2379. IN LPARAM OcManager
  2380. )
  2381. {
  2382. UNREFERENCED_PARAMETER(StringTable);
  2383. UNREFERENCED_PARAMETER(StringId);
  2384. UNREFERENCED_PARAMETER(String);
  2385. UNREFERENCED_PARAMETER(OcSize);
  2386. OcHelperClearExternalError ((POC_MANAGER)OcManager, StringId ,0);
  2387. return(TRUE);
  2388. }
  2389. VOID
  2390. pOcClearAllErrorStates(
  2391. IN POC_MANAGER OcManager
  2392. )
  2393. /*++
  2394. Routine Description:
  2395. This routine clears out the past registry entries for error reports
  2396. for all components
  2397. Arguments:
  2398. OcManagerContext - in input, supplies a pointer to a context value returned
  2399. by OcInitialize. On output, receives NULL.
  2400. Return Value:
  2401. None.
  2402. --*/
  2403. {
  2404. OPTIONAL_COMPONENT OptionalComponent;
  2405. pSetupStringTableEnum(
  2406. OcManager->ComponentStringTable,
  2407. &OptionalComponent,
  2408. sizeof(OPTIONAL_COMPONENT),
  2409. pOcClearAllErrorStatesCB,
  2410. (LPARAM)OcManager
  2411. );
  2412. }
  2413. BOOL
  2414. pOcRemoveComponent(
  2415. IN POC_MANAGER OcManager,
  2416. IN LONG ComponentId,
  2417. IN DWORD PhaseId
  2418. )
  2419. /*++
  2420. Routine Description:
  2421. This routine adds a specified component to the list of aborted components,
  2422. preventing it's entry function from being called any more.
  2423. Arguments:
  2424. OcManager - in input, supplies a pointer to a context value returned
  2425. by OcInitialize. On output, receives NULL.
  2426. ComponentId - in input, this string names the faulty component to be removed
  2427. Return Value:
  2428. None.
  2429. --*/
  2430. {
  2431. PVOID p;
  2432. OPTIONAL_COMPONENT Oc;
  2433. // test for valid component to remove
  2434. if (ComponentId <= 0)
  2435. return FALSE;
  2436. if (pOcComponentWasRemoved(OcManager, ComponentId))
  2437. return FALSE;
  2438. // add component to list of aborted components
  2439. if (!OcManager->AbortedCount) {
  2440. OcManager->AbortedComponentIds = pSetupMalloc(sizeof(UINT));
  2441. if (!OcManager->AbortedComponentIds)
  2442. return FALSE;
  2443. }
  2444. OcManager->AbortedCount++;
  2445. p = pSetupRealloc(OcManager->AbortedComponentIds, sizeof(UINT) * OcManager->AbortedCount);
  2446. if (!p) {
  2447. OcManager->AbortedCount--;
  2448. return FALSE;
  2449. }
  2450. OcManager->AbortedComponentIds = (UINT *)p;
  2451. OcManager->AbortedComponentIds[OcManager->AbortedCount - 1] = ComponentId;
  2452. // stop display of component in the listbox, if it isn't too late
  2453. pSetupStringTableGetExtraData(
  2454. OcManager->ComponentStringTable,
  2455. ComponentId,
  2456. &Oc,
  2457. sizeof(OPTIONAL_COMPONENT)
  2458. );
  2459. Oc.InternalFlags |= OCFLAG_HIDE;
  2460. pSetupStringTableSetExtraData(
  2461. OcManager->ComponentStringTable,
  2462. ComponentId,
  2463. &Oc,
  2464. sizeof(OPTIONAL_COMPONENT)
  2465. );
  2466. _LogError(OcManager,
  2467. OcErrLevInfo | OcErrBatch,
  2468. MSG_OC_REMOVE_COMPONENT,
  2469. pSetupStringTableStringFromId(OcManager->ComponentStringTable,ComponentId),
  2470. PhaseId
  2471. );
  2472. return TRUE;
  2473. }
  2474. BOOL
  2475. pOcComponentWasRemoved(
  2476. IN POC_MANAGER OcManager,
  2477. IN LONG ComponentId
  2478. )
  2479. /*++
  2480. Routine Description:
  2481. This routine indicates if a components has been aborted.
  2482. Arguments:
  2483. OcManager - in input, supplies a pointer to a context value returned
  2484. by OcInitialize. On output, receives NULL.
  2485. ComponentId - in input, this string names the component to check for
  2486. Return Value:
  2487. BOOL - true if it was aborted - else false
  2488. --*/
  2489. {
  2490. UINT i;
  2491. for (i = 0; i < OcManager->AbortedCount; i++) {
  2492. if (OcManager->AbortedComponentIds[i] == ComponentId) {
  2493. return TRUE;
  2494. }
  2495. }
  2496. return FALSE;
  2497. }