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.

3275 lines
101 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. ocpage.c
  5. Abstract:
  6. Routines to run an optional component selection wizard page
  7. and friends (details, have disk, etc).
  8. Author:
  9. Ted Miller (tedm) 17-Sep-1996
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. //
  15. // Maximum number of levels in the OC hierarchy.
  16. // 10 is really generous.
  17. //
  18. #define MAX_OC_LEVELS 10
  19. //
  20. // Max number of depenedent components displayed
  21. // in the remove components Msgbox
  22. //
  23. #define MAX_DISPLAY_IDS 10
  24. //
  25. // Window messages.
  26. //
  27. #define WMX_SELSTATECHANGE (WM_APP+0)
  28. //
  29. // Internal flag to force routines to turn components on or off
  30. //
  31. #define OCQ_FORCE 0x40000000
  32. #define OCQ_SKIPDISKCALC 0x20000000
  33. #define OCQ_COLLECT_NEEDS 0x10000000
  34. #define OCO_COLLECT_NODEPENDENT OCQ_DEPENDENT_SELECTION
  35. //
  36. // Structure used to track parentage within the optional component page.
  37. //
  38. typedef struct _OCPAGE {
  39. //
  40. // OC Manager structure.
  41. //
  42. POC_MANAGER OcManager;
  43. //
  44. // Parent string id.
  45. //
  46. LONG ParentStringId;
  47. //
  48. // Information about the dialog controls on main wizard page
  49. // and on "details" pages.
  50. //
  51. OC_PAGE_CONTROLS WizardPageControlsInfo;
  52. OC_PAGE_CONTROLS DetailsPageControlsInfo;
  53. //
  54. // Pointer to actual set of controls in use.
  55. //
  56. POC_PAGE_CONTROLS ControlsInfo;
  57. //
  58. // Disk space list to use when interacting with OC DLLs.
  59. //
  60. HDSKSPC DiskSpaceList;
  61. //
  62. // Flag indicating whether we've set initial states.
  63. //
  64. BOOL AlreadySetInitialStates;
  65. //
  66. // Format string for 'space needed' text, fetched from the
  67. // dialog at init time (something like "%u.%u MB").
  68. //
  69. TCHAR SpaceNeededTextFormat[64];
  70. //
  71. // Format string for 'x or y components selected' text, fetched from the
  72. // dialog at init time (something like "%u of %u components selected").
  73. //
  74. TCHAR InstalledCountTextFormat[100];
  75. //
  76. // String ids that we collect during selection changes to ask
  77. // the user if it is Ok to change these as well
  78. //
  79. PLONG StringIds;
  80. UINT StringIdsCount;
  81. //
  82. // Values we sock away in case the user cancels at an OC details page,
  83. // so we can easily restore things.
  84. //
  85. HDSKSPC OldDiskSpaceList;
  86. PVOID OldComponentStrTab;
  87. } OCPAGE, *POCPAGE;
  88. //
  89. // Structure used when enumerating the component string table to populate
  90. // the list box.
  91. //
  92. typedef struct _POPULATE_ENUM_PARAMS {
  93. //
  94. // Master context structure.
  95. //
  96. POCPAGE OcPage;
  97. //
  98. // List box being populated.
  99. //
  100. HWND ListBox;
  101. //
  102. // String ID of desired parent. This is how we deal with only
  103. // those subcomponents we actually care about.
  104. //
  105. LONG DesiredParent;
  106. } POPULATE_ENUM_PARAMS, *PPOPULATE_ENUM_PARAMS;
  107. WNDPROC OldListBoxProc;
  108. INT_PTR
  109. CALLBACK
  110. pOcPageDlgProc(
  111. IN HWND hdlg,
  112. IN UINT msg,
  113. IN WPARAM wParam,
  114. IN LPARAM lParam
  115. );
  116. BOOL
  117. pAskUserOkToChange(
  118. IN HWND hDlg,
  119. IN LONG OcStringId,
  120. IN POCPAGE OcPage,
  121. IN BOOL TurningOn
  122. );
  123. VOID
  124. pOcDrawLineInListBox(
  125. IN POCPAGE OcPage,
  126. IN DRAWITEMSTRUCT *Params
  127. );
  128. VOID
  129. pOcListBoxHighlightChanged(
  130. IN HWND hdlg,
  131. IN OUT POCPAGE OcPage,
  132. IN HWND ListBox
  133. );
  134. VOID
  135. pOcSetInstalledCountText(
  136. IN HWND hdlg,
  137. IN POCPAGE OcPage,
  138. IN POPTIONAL_COMPONENT OptionalComponent, OPTIONAL
  139. IN LONG OcStringId
  140. );
  141. VOID
  142. pOcListBoxChangeSelectionState(
  143. IN HWND hdlg,
  144. IN OUT POCPAGE OcPage,
  145. IN HWND ListBox
  146. );
  147. VOID
  148. pOcInvalidateRectInListBox(
  149. IN HWND ListBox,
  150. IN LPCTSTR OptionalComponent OPTIONAL
  151. );
  152. BOOL
  153. pChangeSubcomponentState(
  154. IN POCPAGE OcPage,
  155. IN HWND ListBox,
  156. IN LONG SubcomponentStringId,
  157. IN UINT Pass,
  158. IN UINT NewState,
  159. IN UINT Flags
  160. );
  161. VOID
  162. pOcUpdateParentSelectionStates(
  163. IN POC_MANAGER OcManager,
  164. IN HWND ListBox, OPTIONAL
  165. IN LONG SubcomponentStringId
  166. );
  167. VOID
  168. pOcUpdateSpaceNeededText(
  169. IN POCPAGE OcPage,
  170. IN HWND hdlg
  171. );
  172. BOOL
  173. pOcIsDiskSpaceOk(
  174. IN POCPAGE OcPage,
  175. IN HWND hdlg
  176. );
  177. LRESULT
  178. pOcListBoxSubClassWndProc(
  179. IN HWND hwnd,
  180. IN UINT msg,
  181. IN WPARAM wParam,
  182. IN LPARAM lParam
  183. );
  184. BOOL
  185. pOcPagePopulateListBox(
  186. IN POCPAGE OcPage,
  187. IN HWND ListBox,
  188. IN LONG DesiredParent
  189. );
  190. BOOL
  191. pOcPopulateListBoxStringTableCB(
  192. IN PVOID StringTable,
  193. IN LONG StringId,
  194. IN LPCTSTR String,
  195. IN POPTIONAL_COMPONENT OptionalComponent,
  196. IN UINT OptionalComponentSize,
  197. IN PPOPULATE_ENUM_PARAMS Params
  198. );
  199. LONG
  200. pOcGetTopLevelComponent(
  201. IN POC_MANAGER OcManager,
  202. IN LONG StringId
  203. );
  204. VOID
  205. pOcGetMbAndMbTenths(
  206. IN LONGLONG Number,
  207. OUT PUINT MbCount,
  208. OUT PUINT MbTenthsCount
  209. );
  210. VOID
  211. pOcSetStates(
  212. IN OUT POCPAGE OcPage
  213. );
  214. BOOL
  215. pOcSetStatesStringWorker(
  216. IN LONG StringId,
  217. IN UINT OverRideState,
  218. IN POCPAGE OcPage
  219. );
  220. BOOL
  221. pOcSetStatesStringCB(
  222. IN PVOID StringTable,
  223. IN LONG StringId,
  224. IN LPCTSTR String,
  225. IN POPTIONAL_COMPONENT Oc,
  226. IN UINT OcSize,
  227. IN LPARAM lParam
  228. );
  229. BOOL
  230. pOcSetStatesStringCB2(
  231. IN PVOID StringTable,
  232. IN LONG StringId,
  233. IN LPCTSTR String,
  234. IN POPTIONAL_COMPONENT Oc,
  235. IN UINT OcSize,
  236. IN LPARAM lParam
  237. );
  238. BOOL
  239. pOcSetNeededComponentState(
  240. IN LONG StringId,
  241. IN UINT OverRideState,
  242. IN POCPAGE OcPage
  243. );
  244. UINT
  245. GetComponentState(
  246. IN POCPAGE OcPage,
  247. IN LONG StringId
  248. );
  249. #ifdef _OC_DBG
  250. VOID
  251. pOcPrintStates(
  252. IN POCPAGE OcPage
  253. );
  254. #endif
  255. HPROPSHEETPAGE
  256. OcCreateOcPage(
  257. IN PVOID OcManagerContext,
  258. IN POC_PAGE_CONTROLS WizardPageControlsInfo,
  259. IN POC_PAGE_CONTROLS DetailsPageControlsInfo
  260. )
  261. /*++
  262. Routine Description:
  263. This routine creates the optional component selection page using
  264. a particular dialog template.
  265. Arguments:
  266. OcManagerContext - supplies Optional Component Manager context,
  267. as returned by OcInitialize().
  268. WizardPageControlsInfo - supplies information about the controls in the
  269. template for the top-level/wizard page.
  270. DetailsPageControlsInfo - supplies information about the controls in the
  271. template for the top-level/wizard page.
  272. Return Value:
  273. Handle to newly created property sheet page, or NULL if failure
  274. (assume out of memory in this case).
  275. --*/
  276. {
  277. PROPSHEETPAGE Page;
  278. HPROPSHEETPAGE hPage;
  279. POCPAGE OcPage;
  280. TCHAR buffer[256];
  281. //
  282. // Allocate and initialize the OCPAGE structure.
  283. //
  284. OcPage = pSetupMalloc(sizeof(OCPAGE));
  285. if (!OcPage) {
  286. goto c0;
  287. }
  288. ZeroMemory(OcPage,sizeof(OCPAGE));
  289. OcPage->OcManager = OcManagerContext;
  290. OcPage->WizardPageControlsInfo = *WizardPageControlsInfo;
  291. OcPage->DetailsPageControlsInfo = *DetailsPageControlsInfo;
  292. OcPage->ControlsInfo = &OcPage->WizardPageControlsInfo;
  293. OcPage->ParentStringId = -1;
  294. //
  295. // Create the disk space list object.
  296. //
  297. OcPage->DiskSpaceList = SetupCreateDiskSpaceList(0,0,SPDSL_DISALLOW_NEGATIVE_ADJUST);
  298. if (!OcPage->DiskSpaceList) {
  299. goto c1;
  300. }
  301. //
  302. // Initialize the property sheet page parameters.
  303. //
  304. Page.dwSize = sizeof(PROPSHEETPAGE);
  305. Page.dwFlags = PSP_DEFAULT;
  306. Page.hInstance = WizardPageControlsInfo->TemplateModule;
  307. Page.pszTemplate = WizardPageControlsInfo->TemplateResource;
  308. Page.pfnDlgProc = pOcPageDlgProc;
  309. Page.lParam = (LPARAM)OcPage;
  310. Page.pszHeaderTitle = NULL;
  311. Page.pszHeaderSubTitle = NULL;
  312. if (WizardPageControlsInfo->HeaderText) {
  313. if (LoadString(Page.hInstance,
  314. WizardPageControlsInfo->HeaderText,
  315. buffer,
  316. sizeof(buffer) / sizeof(TCHAR)))
  317. {
  318. Page.dwFlags |= PSP_USEHEADERTITLE;
  319. Page.pszHeaderTitle = _tcsdup(buffer);
  320. }
  321. }
  322. if (WizardPageControlsInfo->SubheaderText) {
  323. if (LoadString(Page.hInstance,
  324. WizardPageControlsInfo->SubheaderText,
  325. buffer,
  326. sizeof(buffer) / sizeof(TCHAR)))
  327. {
  328. Page.dwFlags |= PSP_USEHEADERSUBTITLE;
  329. Page.pszHeaderSubTitle = _tcsdup(buffer);
  330. }
  331. }
  332. //
  333. // Create the property sheet page itself.
  334. //
  335. hPage = CreatePropertySheetPage(&Page);
  336. if (!hPage) {
  337. goto c2;
  338. }
  339. return (hPage);
  340. c2:
  341. if (Page.pszHeaderTitle) {
  342. free((LPTSTR)Page.pszHeaderTitle);
  343. }
  344. if (Page.pszHeaderSubTitle) {
  345. free((LPTSTR)Page.pszHeaderSubTitle);
  346. }
  347. SetupDestroyDiskSpaceList(OcPage->DiskSpaceList);
  348. c1:
  349. pSetupFree(OcPage);
  350. c0:
  351. return (NULL);
  352. }
  353. INT_PTR
  354. CALLBACK
  355. pOcPageDlgProc(
  356. IN HWND hdlg,
  357. IN UINT msg,
  358. IN WPARAM wParam,
  359. IN LPARAM lParam
  360. )
  361. /*++
  362. Routine Description:
  363. Dialog procedure for the OC selection page.
  364. Arguments:
  365. Standard dialog procedure arguments.
  366. Return Value:
  367. Standard dialog procedure return value.
  368. --*/
  369. {
  370. BOOL b;
  371. POCPAGE OcPage;
  372. NMHDR *NotifyParams;
  373. HWND ListBox;
  374. HIMAGELIST ImageList;
  375. static BOOL UserClickedCancelOnThisPage = FALSE;
  376. MSG msgTemp;
  377. HCURSOR OldCursor;
  378. //
  379. // Get pointer to OcPage data structure. If we haven't processed
  380. // WM_INITDIALOG yet, then this will be NULL, but it's still pretty
  381. // convenient to do this here once instead of all over the place below.
  382. //
  383. if (OcPage = (POCPAGE)GetWindowLongPtr(hdlg,DWLP_USER)) {
  384. ListBox = GetDlgItem(hdlg,OcPage->ControlsInfo->ListBox);
  385. } else {
  386. ListBox = NULL;
  387. }
  388. b = FALSE;
  389. switch (msg) {
  390. case WM_INITDIALOG:
  391. //
  392. // Get the pointer to the OC Manager context structure and stick it
  393. // in a window long.
  394. //
  395. OcPage = (POCPAGE)((PROPSHEETPAGE *)lParam)->lParam;
  396. ListBox = GetDlgItem(hdlg,OcPage->ControlsInfo->ListBox);
  397. SetWindowLongPtr(hdlg,DWLP_USER,(LPARAM)OcPage);
  398. //
  399. // Subclass the listview.
  400. //
  401. OldListBoxProc = (WNDPROC)SetWindowLongPtr(ListBox,GWLP_WNDPROC,(LONG_PTR)pOcListBoxSubClassWndProc);
  402. //
  403. // Populate the listbox.
  404. //
  405. pOcPagePopulateListBox(OcPage,ListBox,OcPage->ParentStringId);
  406. //
  407. // Fetch the space needed text.
  408. //
  409. GetDlgItemText(
  410. hdlg,
  411. OcPage->ControlsInfo->SpaceNeededText,
  412. OcPage->SpaceNeededTextFormat,
  413. sizeof(OcPage->SpaceNeededTextFormat)/sizeof(TCHAR)
  414. );
  415. GetDlgItemText(
  416. hdlg,
  417. OcPage->ControlsInfo->InstalledCountText,
  418. OcPage->InstalledCountTextFormat,
  419. sizeof(OcPage->InstalledCountTextFormat)/sizeof(TCHAR)
  420. );
  421. pOcUpdateSpaceNeededText(OcPage,hdlg);
  422. //
  423. // If this has a parent component, then assume it's a details page
  424. // and set the window title to the description of the parent.
  425. // If it has no parent, then assume it's the top-level guy and
  426. // set the instructions text, which is too long for the rc file.
  427. //
  428. if (OcPage->ParentStringId == -1) {
  429. TCHAR Instr[1024];
  430. FormatMessage(
  431. FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS,
  432. MyModuleHandle,
  433. MSG_OC_PAGE_INSTRUCTIONS,
  434. 0,
  435. Instr,
  436. sizeof(Instr)/sizeof(TCHAR),
  437. NULL
  438. );
  439. SetDlgItemText(hdlg,OcPage->ControlsInfo->InstructionsText,Instr);
  440. } else {
  441. OPTIONAL_COMPONENT Oc;
  442. pSetupStringTableGetExtraData(
  443. OcPage->OcManager->ComponentStringTable,
  444. OcPage->ParentStringId,
  445. &Oc,
  446. sizeof(OPTIONAL_COMPONENT)
  447. );
  448. SetWindowText(hdlg,Oc.Description);
  449. //
  450. // Set component list header
  451. //
  452. {
  453. TCHAR FormatString[150];
  454. TCHAR Title[1000];
  455. LoadString(
  456. MyModuleHandle,
  457. IDS_SUBCOMP_OF,
  458. FormatString,
  459. sizeof(FormatString)/sizeof(TCHAR)
  460. );
  461. wsprintf(Title,FormatString,Oc.Description);
  462. SetDlgItemText(hdlg,OcPage->ControlsInfo->ComponentHeaderText,Title);
  463. }
  464. }
  465. b = TRUE;
  466. break;
  467. case WM_DESTROY:
  468. if (OcPage && OcPage->ControlsInfo == &OcPage->WizardPageControlsInfo) {
  469. if (UserClickedCancelOnThisPage) {
  470. pOcFreeOcSetupPage(OcPage->OcManager->OcSetupPage);
  471. OcPage->OcManager->OcSetupPage = NULL;
  472. }
  473. SetupDestroyDiskSpaceList(OcPage->DiskSpaceList);
  474. OcPage->DiskSpaceList = NULL;
  475. if (OcPage->StringIds) {
  476. pSetupFree(OcPage->StringIds);
  477. OcPage->StringIds = NULL;
  478. }
  479. pSetupFree(OcPage);
  480. SetWindowLongPtr(hdlg,DWLP_USER,(LPARAM)NULL);
  481. break;
  482. }
  483. break;
  484. case WM_MEASUREITEM:
  485. //
  486. // Height is height of text/small icon, plus space for a border.
  487. //
  488. {
  489. HDC hdc;
  490. SIZE size;
  491. int cy;
  492. hdc = GetDC(hdlg);
  493. if (hdc) {
  494. SelectObject(hdc,(HFONT)SendMessage(GetParent(hdlg),WM_GETFONT,0,0));
  495. GetTextExtentPoint32(hdc,TEXT("W"),1,&size);
  496. ReleaseDC(hdlg,hdc);
  497. } else {
  498. size.cy = 0;
  499. }
  500. cy = GetSystemMetrics(SM_CYSMICON);
  501. ((MEASUREITEMSTRUCT *)lParam)->itemHeight = max(size.cy,cy)
  502. + (2*GetSystemMetrics(SM_CYBORDER));
  503. }
  504. b = TRUE;
  505. break;
  506. case WM_DRAWITEM:
  507. pOcDrawLineInListBox(OcPage,(DRAWITEMSTRUCT *)lParam);
  508. b = TRUE;
  509. break;
  510. case WM_COMMAND:
  511. switch (LOWORD(wParam)) {
  512. case IDOK:
  513. if (HIWORD(wParam) == BN_CLICKED) {
  514. //
  515. // Only possible from details dialog.
  516. //
  517. EndDialog(hdlg,TRUE);
  518. b = TRUE;
  519. }
  520. break;
  521. case IDCANCEL:
  522. if (HIWORD(wParam) == BN_CLICKED) {
  523. //
  524. // Only possible from details dialog.
  525. //
  526. EndDialog(hdlg,FALSE);
  527. b = TRUE;
  528. }
  529. break;
  530. default:
  531. if ((LOWORD(wParam) == OcPage->ControlsInfo->DetailsButton) && (HIWORD(wParam) == BN_CLICKED)) {
  532. //
  533. // Details button. Fake out WM_INITDIALOG so lParam is right.
  534. //
  535. OCPAGE NewOcPage;
  536. PROPSHEETPAGE Page;
  537. int i;
  538. SetCursor(LoadCursor(NULL,IDC_WAIT));
  539. i = (int)SendMessage(ListBox,LB_GETCURSEL,0,0);
  540. NewOcPage = *OcPage;
  541. NewOcPage.ControlsInfo = &NewOcPage.DetailsPageControlsInfo;
  542. NewOcPage.ParentStringId = (LONG)SendMessage(ListBox,LB_GETITEMDATA,i,0);
  543. //
  544. // Preserve the disk space list and component string table
  545. // in case the user cancels the details page. Then we can
  546. // easily restore things.
  547. //
  548. OcPage->OldDiskSpaceList = SetupDuplicateDiskSpaceList(
  549. NewOcPage.DiskSpaceList,
  550. 0,0,0
  551. );
  552. OcPage->OldComponentStrTab = pSetupStringTableDuplicate(
  553. OcPage->OcManager->ComponentStringTable
  554. );
  555. Page.lParam = (LPARAM)&NewOcPage;
  556. i = (int)DialogBoxParam(
  557. NewOcPage.DetailsPageControlsInfo.TemplateModule,
  558. NewOcPage.DetailsPageControlsInfo.TemplateResource,
  559. hdlg,
  560. pOcPageDlgProc,
  561. (LPARAM)&Page
  562. );
  563. if (i == TRUE) {
  564. SetupDestroyDiskSpaceList(OcPage->OldDiskSpaceList);
  565. OcPage->DiskSpaceList = NewOcPage.DiskSpaceList;
  566. pSetupStringTableDestroy(OcPage->OldComponentStrTab);
  567. OcPage->OldComponentStrTab = NULL;
  568. //
  569. // Force repaint of the listbox, which redraws the checkboxes.
  570. //
  571. pOcInvalidateRectInListBox(ListBox,NULL);
  572. //
  573. // Update count of installed subcomponents.
  574. //
  575. pOcSetInstalledCountText(
  576. hdlg,
  577. OcPage,
  578. NULL,
  579. (LONG)SendMessage(ListBox,LB_GETITEMDATA,SendMessage(ListBox,LB_GETCURSEL,0,0),0)
  580. );
  581. } else {
  582. pSetupStringTableDestroy(OcPage->OcManager->ComponentStringTable);
  583. OcPage->OcManager->ComponentStringTable = OcPage->OldComponentStrTab;
  584. SetupDestroyDiskSpaceList(NewOcPage.DiskSpaceList);
  585. NewOcPage.DiskSpaceList = NULL;
  586. OcPage->DiskSpaceList = OcPage->OldDiskSpaceList;
  587. }
  588. OcPage->OldDiskSpaceList = NULL;
  589. OcPage->OldComponentStrTab = NULL;
  590. //
  591. // It won't hurt anything to do this even in the cancel/failure case,
  592. // and this will update the space available.
  593. //
  594. pOcUpdateSpaceNeededText(OcPage,hdlg);
  595. SetCursor(LoadCursor(NULL,IDC_ARROW));
  596. b = TRUE;
  597. }
  598. if (LOWORD(wParam) == OcPage->ControlsInfo->ListBox) {
  599. switch (HIWORD(wParam)) {
  600. case LBN_DBLCLK:
  601. //
  602. // Double-click is the same as hitting the details button.
  603. // First make sure the details button is enabled.
  604. //
  605. if (IsWindowEnabled(GetDlgItem(hdlg,OcPage->ControlsInfo->DetailsButton))) {
  606. SetCursor(LoadCursor(NULL,IDC_WAIT));
  607. PostMessage(
  608. hdlg,
  609. WM_COMMAND,
  610. MAKEWPARAM(OcPage->ControlsInfo->DetailsButton,BN_CLICKED),
  611. (LPARAM)GetDlgItem(hdlg,OcPage->ControlsInfo->DetailsButton)
  612. );
  613. SetCursor(LoadCursor(NULL,IDC_ARROW));
  614. }
  615. b = TRUE;
  616. break;
  617. case LBN_SELCHANGE:
  618. SetCursor(LoadCursor(NULL,IDC_WAIT));
  619. pOcListBoxHighlightChanged(hdlg,OcPage,ListBox);
  620. SetCursor(LoadCursor(NULL,IDC_ARROW));
  621. b = TRUE;
  622. break;
  623. }
  624. }
  625. }
  626. break;
  627. case WM_NOTIFY:
  628. NotifyParams = (NMHDR *)lParam;
  629. switch (NotifyParams->code) {
  630. case PSN_QUERYCANCEL:
  631. if (OcPage->OcManager->SetupData.OperationFlags & SETUPOP_STANDALONE) {
  632. b = FALSE;
  633. OcPage->OcManager->InternalFlags |= OCMFLAG_USERCANCELED;
  634. UserClickedCancelOnThisPage = TRUE;
  635. SetWindowLongPtr(
  636. hdlg,
  637. DWLP_MSGRESULT,
  638. b
  639. );
  640. }
  641. b = TRUE;
  642. break;
  643. case PSN_SETACTIVE:
  644. //
  645. // Set states based on mode bits, if necessary.
  646. //
  647. OldCursor = SetCursor(LoadCursor (NULL, IDC_WAIT));
  648. if (!OcPage->AlreadySetInitialStates) {
  649. if ( OcPage->DiskSpaceList ) {
  650. SetupDestroyDiskSpaceList(OcPage->DiskSpaceList);
  651. OcPage->DiskSpaceList=NULL;
  652. }
  653. OcPage->DiskSpaceList = SetupCreateDiskSpaceList(0,0,SPDSL_DISALLOW_NEGATIVE_ADJUST);
  654. sapiAssert(OcPage->DiskSpaceList);
  655. pOcSetStates(OcPage);
  656. OcPage->AlreadySetInitialStates = TRUE;
  657. }
  658. #ifdef _OC_DBG
  659. pOcPrintStates(OcPage);
  660. #endif
  661. pOcUpdateSpaceNeededText(OcPage,hdlg);
  662. //
  663. // we want to empty the message cue to make sure that
  664. // people will see this page, and not accidentally click
  665. // next because they were antsy
  666. //
  667. while (PeekMessage(&msgTemp,NULL,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE));
  668. while (PeekMessage(&msgTemp,NULL,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE));
  669. SetCursor(OldCursor);
  670. if (OcPage->OcManager->SetupData.OperationFlags & SETUPOP_STANDALONE) {
  671. ShowWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),SW_SHOW);
  672. EnableWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),TRUE);
  673. } else {
  674. ShowWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),SW_HIDE);
  675. EnableWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),FALSE);
  676. }
  677. // turn off 'back' button if this is the first page
  678. PropSheet_SetWizButtons(GetParent(hdlg),
  679. (OcPage->OcManager->InternalFlags & OCMFLAG_NOPREOCPAGES) ? PSWIZB_NEXT : PSWIZB_BACK | PSWIZB_NEXT);
  680. //
  681. // See whether any component wants to skip this page
  682. // or if we are running in unattended mode.
  683. // If so, disallow activation and move to next page;
  684. // if not then fall through to allow activation of the page.
  685. //
  686. if (((OcPage->OcManager->SetupData.OperationFlags & SETUPOP_BATCH)
  687. || pOcDoesAnyoneWantToSkipPage(OcPage->OcManager,OcPageComponentHierarchy))
  688. && pOcIsDiskSpaceOk(OcPage,hdlg)) {
  689. //
  690. // Skiping this page...
  691. // Set Initial State to false because when we
  692. // back up from the next page we will go to the
  693. // Previos page.
  694. //
  695. OcPage->AlreadySetInitialStates = FALSE;
  696. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,-1);
  697. } else {
  698. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,0);
  699. }
  700. b = TRUE;
  701. break;
  702. case PSN_WIZNEXT:
  703. //
  704. // Check disk space. If not OK, stop here.
  705. // Otherwise allow advancing.
  706. //
  707. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,pOcIsDiskSpaceOk(OcPage,hdlg) ? 0 : -1);
  708. b = TRUE;
  709. break;
  710. case PSN_KILLACTIVE:
  711. //
  712. // Restore the wizard's cancel button if we removed it earlier
  713. //
  714. if (OcPage->OcManager->SetupData.OperationFlags & SETUPOP_STANDALONE) {
  715. ShowWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),SW_SHOW);
  716. EnableWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),TRUE);
  717. }
  718. // pass through
  719. case PSN_WIZBACK:
  720. case PSN_WIZFINISH:
  721. //
  722. // Allow activation/motion.
  723. //
  724. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,0);
  725. b = TRUE;
  726. break;
  727. }
  728. break;
  729. case WMX_SELSTATECHANGE:
  730. //
  731. // User changed the selection state of an item.
  732. //
  733. SetCursor(LoadCursor(NULL,IDC_WAIT));
  734. pOcListBoxChangeSelectionState(hdlg,OcPage,ListBox);
  735. pOcSetInstalledCountText(
  736. hdlg,
  737. OcPage,
  738. NULL,
  739. (LONG)SendMessage(ListBox,LB_GETITEMDATA,SendMessage(ListBox,LB_GETCURSEL,0,0),0)
  740. );
  741. SetCursor(LoadCursor(NULL,IDC_ARROW));
  742. b = TRUE;
  743. break;
  744. }
  745. return (b);
  746. }
  747. LRESULT
  748. pOcListBoxSubClassWndProc(
  749. IN HWND hwnd,
  750. IN UINT msg,
  751. IN WPARAM wParam,
  752. IN LPARAM lParam
  753. )
  754. /*++
  755. Routine Description:
  756. Subclass window procecure for listbox controls to handle the following:
  757. - Highlighting/selection of an item when the user clicks its state icon
  758. - Spacebar needs to be interpreted as a click on the state icon.
  759. Arguments:
  760. Standard window procedure arguments.
  761. Return Value:
  762. Standard window procedure return value.
  763. --*/
  764. {
  765. int index;
  766. LRESULT l;
  767. if (OldListBoxProc == NULL) {
  768. OutputDebugString(TEXT("Warning: old list box proc is NULL\n"));
  769. sapiAssert(FALSE && "Warning: old list box proc is NULL\n");
  770. }
  771. switch (msg) {
  772. case WM_LBUTTONDOWN:
  773. //
  774. // We want to let the standard list box window proc
  775. // set selection regardless of what else we do.
  776. //
  777. l = CallWindowProc(OldListBoxProc,hwnd,msg,wParam,lParam);
  778. //
  779. // If we're over a state icon, then toggle selection state.
  780. //
  781. if (LOWORD(lParam) < GetSystemMetrics(SM_CXSMICON)) {
  782. if (SendMessage(hwnd, LB_ITEMFROMPOINT, 0, lParam) < SendMessage(hwnd, LB_GETCOUNT, 0, 0)) {
  783. PostMessage(GetParent(hwnd),WMX_SELSTATECHANGE,0,0);
  784. }
  785. }
  786. break;
  787. case WM_LBUTTONDBLCLK:
  788. //
  789. // Ignore double-clicks over the state icon.
  790. //
  791. if (LOWORD(lParam) < GetSystemMetrics(SM_CXSMICON)) {
  792. l = 0;
  793. } else {
  794. l = CallWindowProc(OldListBoxProc,hwnd,msg,wParam,lParam);
  795. }
  796. break;
  797. case WM_KEYDOWN:
  798. //
  799. // Catch space bar and treat as a click on the state icon.
  800. //
  801. if (wParam == VK_SPACE) {
  802. PostMessage(GetParent(hwnd),WMX_SELSTATECHANGE,0,0);
  803. l = 0;
  804. } else {
  805. l = CallWindowProc(OldListBoxProc,hwnd,msg,wParam,lParam);
  806. }
  807. break;
  808. default:
  809. //
  810. // Let the standard listview window proc handle it.
  811. //
  812. l = CallWindowProc(OldListBoxProc,hwnd,msg,wParam,lParam);
  813. break;
  814. }
  815. return (l);
  816. }
  817. VOID
  818. pOcDrawLineInListBox(
  819. IN POCPAGE OcPage,
  820. IN DRAWITEMSTRUCT *Params
  821. )
  822. /*++
  823. Routine Description:
  824. Paint a line in the owner-draw listbox, including a state icon,
  825. mini-icon, and text.
  826. Arguments:
  827. OcPage - supplies OC page context.
  828. Params - supplies the draw-item structure.
  829. Return Value:
  830. None.
  831. --*/
  832. {
  833. TCHAR Text[MAXOCDESC];
  834. TCHAR Text2[128];
  835. SIZE Size;
  836. int OldMode;
  837. DWORD OldBackColor,OldTextColor;
  838. OPTIONAL_COMPONENT Oc;
  839. UINT IconId;
  840. int x;
  841. UINT Length;
  842. UINT Mb,Tenths;
  843. TCHAR Dll[MAX_PATH];
  844. LPCTSTR pDll,Resource;
  845. LPTSTR p;
  846. if ((int)Params->itemID < 0) {
  847. return;
  848. }
  849. pSetupStringTableGetExtraData(
  850. OcPage->OcManager->ComponentStringTable,
  851. (LONG)Params->itemData,
  852. &Oc,
  853. sizeof(OPTIONAL_COMPONENT)
  854. );
  855. Length = (UINT)SendMessage(Params->hwndItem,LB_GETTEXT,Params->itemID,(LPARAM)Text),
  856. GetTextExtentPoint32(Params->hDC,Text,Length,&Size);
  857. if (Params->itemAction != ODA_FOCUS) {
  858. OldMode = GetBkMode(Params->hDC);
  859. OldBackColor = SetBkColor(
  860. Params->hDC,
  861. GetSysColor((Params->itemState & ODS_SELECTED) ? COLOR_HIGHLIGHT : COLOR_WINDOW)
  862. );
  863. OldTextColor = SetTextColor(
  864. Params->hDC,
  865. GetSysColor((Params->itemState & ODS_SELECTED) ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT)
  866. );
  867. //
  868. // Fill in the background (before mini-icon is drawn!)
  869. //
  870. ExtTextOut(Params->hDC,0,0,ETO_OPAQUE,&Params->rcItem,NULL,0,NULL);
  871. //
  872. // Draw check box mini-icon.
  873. //
  874. switch (Oc.SelectionState) {
  875. case SELSTATE_NO:
  876. IconId = 13;
  877. break;
  878. case SELSTATE_YES:
  879. IconId = 12;
  880. break;
  881. case SELSTATE_PARTIAL:
  882. IconId = 25;
  883. break;
  884. default:
  885. IconId = 0;
  886. break;
  887. }
  888. x = SetupDiDrawMiniIcon(
  889. Params->hDC,
  890. Params->rcItem,
  891. IconId,
  892. (Params->itemState & ODS_SELECTED) ? MAKELONG(DMI_BKCOLOR, COLOR_HIGHLIGHT) : 0
  893. );
  894. Params->rcItem.left += x;
  895. //
  896. // Draw mini-icon for this OC and move string accordingly
  897. //
  898. if ((INT)Oc.IconIndex < 0) {
  899. //
  900. // Component-supplied miniicon. We query the component dll for the bitmap,
  901. // which gets added to the mini icon list in setupapi, and thus we can
  902. // use SetupDiDrawMiniIcon(). Save the index for future use -- we only
  903. // go through this code path once per subcomponent.
  904. //
  905. if (Oc.IconIndex == (UINT)(-2)) {
  906. pOcFormSuitePath(OcPage->OcManager->SuiteName,Oc.IconDll,Dll);
  907. pDll = Dll;
  908. Resource = MAKEINTRESOURCE(_tcstoul(Oc.IconResource,&p,10));
  909. //
  910. // If the char that stopped the conversion in _tcstoul is
  911. // not the terminating nul then the value is not a valid
  912. // base-10 number; assume it's a name in string form.
  913. //
  914. if (*p) {
  915. Resource = Oc.IconResource;
  916. }
  917. } else {
  918. pDll = NULL;
  919. Resource = NULL;
  920. }
  921. Oc.IconIndex = pOcCreateComponentSpecificMiniIcon(
  922. OcPage->OcManager,
  923. pOcGetTopLevelComponent(OcPage->OcManager,(LONG)Params->itemData),
  924. pSetupStringTableStringFromId(
  925. OcPage->OcManager->ComponentStringTable,
  926. (LONG)Params->itemData
  927. ),
  928. x-2,
  929. GetSystemMetrics(SM_CYSMICON),
  930. pDll,
  931. Resource
  932. );
  933. pSetupStringTableSetExtraData(
  934. OcPage->OcManager->ComponentStringTable,
  935. (LONG)Params->itemData,
  936. &Oc,
  937. sizeof(OPTIONAL_COMPONENT)
  938. );
  939. }
  940. x = SetupDiDrawMiniIcon(
  941. Params->hDC,
  942. Params->rcItem,
  943. Oc.IconIndex,
  944. (Params->itemState & ODS_SELECTED) ? MAKELONG(DMI_BKCOLOR, COLOR_HIGHLIGHT) : 0
  945. );
  946. //
  947. // Draw the text transparently on top of the background
  948. //
  949. SetBkMode(Params->hDC,TRANSPARENT);
  950. ExtTextOut(
  951. Params->hDC,
  952. x + Params->rcItem.left,
  953. Params->rcItem.top + ((Params->rcItem.bottom - Params->rcItem.top) - Size.cy) / 2,
  954. 0,
  955. NULL,
  956. Text,
  957. Length,
  958. NULL
  959. );
  960. pOcGetMbAndMbTenths(Oc.SizeApproximation,&Mb,&Tenths);
  961. LoadString(MyModuleHandle,IDS_MB_AND_TENTHS,Text2,sizeof(Text2)/sizeof(TCHAR));
  962. wsprintf(Text,Text2,Mb,locale.DecimalSeparator,Tenths);
  963. GetTextExtentPoint32(Params->hDC,Text,lstrlen(Text),&Size);
  964. Params->rcItem.left = Params->rcItem.right - Size.cx - 8;
  965. ExtTextOut(
  966. Params->hDC,
  967. Params->rcItem.left,
  968. Params->rcItem.top + ((Params->rcItem.bottom - Params->rcItem.top) - Size.cy) / 2,
  969. 0,
  970. NULL,
  971. Text,
  972. lstrlen(Text),
  973. NULL
  974. );
  975. //
  976. // Restore hdc colors.
  977. //
  978. SetBkColor(Params->hDC,OldBackColor);
  979. SetTextColor(Params->hDC,OldTextColor);
  980. SetBkMode(Params->hDC,OldMode);
  981. }
  982. if ((Params->itemAction == ODA_FOCUS) || (Params->itemState & ODS_FOCUS)) {
  983. DrawFocusRect(Params->hDC,&Params->rcItem);
  984. }
  985. }
  986. VOID
  987. pOcListBoxHighlightChanged(
  988. IN HWND hdlg,
  989. IN OUT POCPAGE OcPage,
  990. IN HWND ListBox
  991. )
  992. /*++
  993. Routine Description:
  994. This routine handles a change in the highlight in the listbox
  995. control in the oc page. It enables or disables the details button
  996. based on whether the newly selected component has children
  997. subcomponents, and changes the tip text.
  998. Arguments:
  999. hdlg - supplies window handle of OC page
  1000. OcPage - supplies OC page context structure
  1001. ListBox - supplies window handle of list view control in hdlg
  1002. Return Value:
  1003. None.
  1004. --*/
  1005. {
  1006. int i;
  1007. OPTIONAL_COMPONENT Oc;
  1008. //
  1009. // Fetch the optional component data for the highlighted/slected item.
  1010. //
  1011. i = (int)SendMessage(ListBox,LB_GETCURSEL,0,0);
  1012. if (i < 0) {
  1013. return;
  1014. }
  1015. pSetupStringTableGetExtraData(
  1016. OcPage->OcManager->ComponentStringTable,
  1017. (LONG)SendMessage(ListBox,LB_GETITEMDATA,i,0),
  1018. &Oc,
  1019. sizeof(OPTIONAL_COMPONENT)
  1020. );
  1021. //
  1022. // Enable/disable the details button.
  1023. // The selected item's lParam is the string id for the selected item.
  1024. //
  1025. EnableWindow(
  1026. GetDlgItem(hdlg,OcPage->ControlsInfo->DetailsButton),
  1027. Oc.FirstChildStringId != -1
  1028. );
  1029. //
  1030. // Change the tip text.
  1031. //
  1032. SetDlgItemText(hdlg,OcPage->ControlsInfo->TipText,Oc.Tip);
  1033. //
  1034. // Set up the count of installed subcomponents.
  1035. //
  1036. pOcSetInstalledCountText(hdlg,OcPage,&Oc,0);
  1037. }
  1038. VOID
  1039. pOcSetInstalledCountText(
  1040. IN HWND hdlg,
  1041. IN POCPAGE OcPage,
  1042. IN POPTIONAL_COMPONENT OptionalComponent, OPTIONAL
  1043. IN LONG OcStringId
  1044. )
  1045. {
  1046. TCHAR Text[256];
  1047. UINT TotalCount;
  1048. UINT SelectedCount;
  1049. HWND TextWindow;
  1050. DWORD Args[2];
  1051. OPTIONAL_COMPONENT Oc;
  1052. BOOL b;
  1053. if (OptionalComponent) {
  1054. Oc = *OptionalComponent;
  1055. } else {
  1056. pSetupStringTableGetExtraData(
  1057. OcPage->OcManager->ComponentStringTable,
  1058. OcStringId,
  1059. &Oc,
  1060. sizeof(OPTIONAL_COMPONENT)
  1061. );
  1062. }
  1063. TextWindow = GetDlgItem(hdlg,OcPage->ControlsInfo->InstalledCountText);
  1064. //
  1065. // Set up the count ("1 of 3 items selected").
  1066. // If this is not a parent component, then hide that text item.
  1067. //
  1068. if (Oc.FirstChildStringId == -1) {
  1069. ShowWindow(TextWindow,SW_HIDE);
  1070. } else {
  1071. ShowWindow(TextWindow,SW_SHOW);
  1072. //
  1073. // Examine all child components to see how many of them are in
  1074. // a selected state (selected or partially selected). We only count
  1075. // direct children, not children of children, etc.
  1076. //
  1077. TotalCount = 0;
  1078. SelectedCount = 0;
  1079. b = TRUE;
  1080. pSetupStringTableGetExtraData(
  1081. OcPage->OcManager->ComponentStringTable,
  1082. Oc.FirstChildStringId,
  1083. &Oc,
  1084. sizeof(OPTIONAL_COMPONENT)
  1085. );
  1086. do {
  1087. TotalCount++;
  1088. if (Oc.SelectionState != SELSTATE_NO) {
  1089. SelectedCount++;
  1090. }
  1091. if (Oc.NextSiblingStringId == -1) {
  1092. b = FALSE;
  1093. } else {
  1094. pSetupStringTableGetExtraData(
  1095. OcPage->OcManager->ComponentStringTable,
  1096. Oc.NextSiblingStringId,
  1097. &Oc,
  1098. sizeof(OPTIONAL_COMPONENT)
  1099. );
  1100. }
  1101. } while (b);
  1102. Args[0] = SelectedCount;
  1103. Args[1] = TotalCount;
  1104. //
  1105. // Use FormatMessage since order of numbers could change from
  1106. // language to language; wsprintf isn't good enough.
  1107. //
  1108. FormatMessage(
  1109. FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1110. OcPage->InstalledCountTextFormat,
  1111. 0,
  1112. 0,
  1113. Text,
  1114. sizeof(Text)/sizeof(TCHAR),
  1115. (va_list *)Args
  1116. );
  1117. SetWindowText(TextWindow,Text);
  1118. }
  1119. }
  1120. VOID
  1121. pOcListBoxChangeSelectionState(
  1122. IN HWND hdlg,
  1123. IN OUT POCPAGE OcPage,
  1124. IN HWND ListBox
  1125. )
  1126. /*++
  1127. Routine Description:
  1128. This routine handles a change in selection state for an item.
  1129. Selection state refers to whether the user has placed or cleared
  1130. a checkbox next to an item in the listbox.
  1131. It is assumed that the currently highlighted item is the one
  1132. we want to operate on.
  1133. Selecting/deselecting a component involves calling through the
  1134. installation DLL interface to inform the component's installation DLL
  1135. that a change in selection state has taken place, updating disk space
  1136. requirements, etc.
  1137. Arguments:
  1138. hdlg - supplies window handle of OC page
  1139. OcPage - supplies OC page context structure
  1140. ListBox - supplies window handle of listbox control in hdlg
  1141. Return Value:
  1142. None.
  1143. --*/
  1144. {
  1145. OPTIONAL_COMPONENT Oc;
  1146. BOOL TurningOn;
  1147. DWORD b;
  1148. // UINT state;
  1149. int i;
  1150. LONG StringId;
  1151. //
  1152. // Fetch the optional component data for the highlighted/slected item.
  1153. //
  1154. i = (int)SendMessage(ListBox,LB_GETCURSEL,0,0);
  1155. if (i < 0) {
  1156. return;
  1157. }
  1158. StringId = (LONG)SendMessage(ListBox,LB_GETITEMDATA,i,0);
  1159. //
  1160. // Figure out whether the item is being turned on or off.
  1161. // If the state is deselected then we're turning it on.
  1162. // Otherwise it's partially or fully selected and we're turning it off.
  1163. //
  1164. pSetupStringTableGetExtraData(
  1165. OcPage->OcManager->ComponentStringTable,
  1166. StringId,
  1167. &Oc,
  1168. sizeof(OPTIONAL_COMPONENT)
  1169. );
  1170. TurningOn = (Oc.SelectionState == SELSTATE_NO);
  1171. //
  1172. // Tell the user about needs and validate that he wants to continue.
  1173. // turn on or off the needed components.
  1174. //
  1175. OcPage->StringIds = NULL;
  1176. OcPage->StringIdsCount = 0;
  1177. //
  1178. // Do it.
  1179. //
  1180. if (TurningOn) {
  1181. b = pChangeSubcomponentState(OcPage,
  1182. ListBox,
  1183. StringId,
  1184. 1,
  1185. SELSTATE_YES,
  1186. OCQ_ACTUAL_SELECTION|OCQ_COLLECT_NEEDS);
  1187. if (b) {
  1188. if (b = pAskUserOkToChange(hdlg, StringId, OcPage, TurningOn)) {
  1189. pChangeSubcomponentState(OcPage,
  1190. ListBox,
  1191. StringId,
  1192. 2,
  1193. SELSTATE_YES,
  1194. OCQ_ACTUAL_SELECTION);
  1195. }
  1196. }
  1197. } else {
  1198. b = pChangeSubcomponentState(OcPage,
  1199. ListBox,
  1200. StringId,
  1201. 1,
  1202. SELSTATE_NO,
  1203. OCQ_ACTUAL_SELECTION|OCQ_COLLECT_NEEDS);
  1204. if (b) {
  1205. if (b = pAskUserOkToChange(hdlg, StringId, OcPage, TurningOn)) {
  1206. pChangeSubcomponentState(OcPage,
  1207. ListBox,
  1208. StringId,
  1209. 2,
  1210. SELSTATE_NO,
  1211. OCQ_ACTUAL_SELECTION);
  1212. }
  1213. }
  1214. }
  1215. if (b) {
  1216. //
  1217. // Refresh space needed text.
  1218. //
  1219. pOcUpdateSpaceNeededText(OcPage,hdlg);
  1220. }
  1221. }
  1222. BOOL
  1223. pAskUserOkToChange(
  1224. IN HWND hDlg,
  1225. IN LONG SubcomponentStringId,
  1226. IN POCPAGE OcPage,
  1227. IN BOOL AddComponents
  1228. )
  1229. /*++
  1230. Routine Description:
  1231. This routine asks the user if it ok to turn off all needed subcomponents
  1232. Arguments:
  1233. hDlg - parent dialog handle for the messagebox
  1234. SubcomponentStringId - string id of the component that is being changed
  1235. OcPage - supplies OC page context info.
  1236. AddComponents - TRUE if we're adding components, FALSE if they are being
  1237. removed
  1238. Return Value:
  1239. Boolean value indicating whether the routine was successful.
  1240. --*/
  1241. {
  1242. BOOL b = TRUE;
  1243. UINT n;
  1244. UINT Id;
  1245. TCHAR buffer[2024];
  1246. TCHAR caption[256];
  1247. LPCTSTR pArgs;
  1248. OPTIONAL_COMPONENT OptionalComponent;
  1249. //
  1250. // Only display warning if there are dependents or
  1251. // user is removing components
  1252. //
  1253. if ( OcPage->StringIdsCount == 0 || AddComponents ) {
  1254. return b;
  1255. }
  1256. pSetupStringTableGetExtraData(
  1257. OcPage->OcManager->ComponentStringTable,
  1258. SubcomponentStringId,
  1259. &OptionalComponent,
  1260. sizeof(OPTIONAL_COMPONENT));
  1261. //
  1262. // Format the first Half of the message with the component name
  1263. //
  1264. pArgs = OptionalComponent.Description;
  1265. n = FormatMessage(
  1266. FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1267. MyModuleHandle,
  1268. MSG_OC_PAGE_DEPENDENTS1,
  1269. 0,
  1270. buffer,
  1271. sizeof(buffer)/sizeof(TCHAR),
  1272. (va_list *)&pArgs
  1273. );
  1274. //
  1275. // Add each dependent component to the message
  1276. // Only add as many components as we have room for
  1277. // Leave roon on the end of buffer for the last message.
  1278. //
  1279. for (Id = 0; Id < OcPage->StringIdsCount
  1280. && n < (sizeof(buffer)/sizeof(TCHAR) - 200 ); Id++) {
  1281. //
  1282. // Only allow so many components in the messgebox, otherwise will
  1283. // be larger then a VGA display
  1284. //
  1285. if ( Id > MAX_DISPLAY_IDS ) {
  1286. n = lstrlen(buffer);
  1287. FormatMessage(
  1288. FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1289. MyModuleHandle,
  1290. MSG_OC_PAGE_DEPENDENTS2,
  1291. 0,
  1292. &buffer[n],
  1293. (sizeof(buffer)-n)/sizeof(TCHAR),
  1294. (va_list *)NULL
  1295. );
  1296. break;
  1297. }
  1298. pSetupStringTableGetExtraData(
  1299. OcPage->OcManager->ComponentStringTable,
  1300. OcPage->StringIds[Id],
  1301. &OptionalComponent,
  1302. sizeof(OPTIONAL_COMPONENT)
  1303. );
  1304. //
  1305. // Skip this item if it is a dependent of the Parent, we can arrive
  1306. // at this situation when dependents of the parent needs other
  1307. // dependents. The Collection code can not detect this.
  1308. //
  1309. if ( OptionalComponent.ParentStringId != SubcomponentStringId ) {
  1310. OPTIONAL_COMPONENT ParentOc;
  1311. UINT ParentId;
  1312. //
  1313. // Scan the parentenal chain until we find a match or run out of parents
  1314. // if there is a match then this dependent is the same dependent as the
  1315. // the target component
  1316. //
  1317. ParentId = OptionalComponent.ParentStringId;
  1318. while (ParentId != -1) {
  1319. pSetupStringTableGetExtraData(
  1320. OcPage->OcManager->ComponentStringTable,
  1321. ParentId,
  1322. &ParentOc,
  1323. sizeof(OPTIONAL_COMPONENT)
  1324. );
  1325. if ( ParentOc.ParentStringId == SubcomponentStringId ) {
  1326. goto skip;
  1327. }
  1328. ParentId = ParentOc.ParentStringId;
  1329. }
  1330. n += lstrlen(OptionalComponent.Description);
  1331. lstrcat(buffer, OptionalComponent.Description);
  1332. lstrcat(buffer, _T("\n"));
  1333. b = FALSE;
  1334. skip:;
  1335. }
  1336. }
  1337. //
  1338. // Continue if any components got by the Parent and dependent screen
  1339. //
  1340. if ( ! b ) {
  1341. //
  1342. // Add the last half of the message
  1343. //
  1344. n = lstrlen(buffer);
  1345. FormatMessage(
  1346. FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1347. MyModuleHandle,
  1348. MSG_OC_PAGE_DEPENDENTS3,
  1349. 0,
  1350. &buffer[n],
  1351. (sizeof(buffer)-n)/sizeof(TCHAR),
  1352. (va_list *)NULL
  1353. );
  1354. //
  1355. // Returns codes from MessageBox()
  1356. //
  1357. *caption = 0;
  1358. LoadString(MyModuleHandle, IDS_SETUP, caption, sizeof(caption)/sizeof(TCHAR));
  1359. sapiAssert(*caption);
  1360. b = (MessageBox(hDlg,
  1361. buffer,
  1362. caption,
  1363. MB_APPLMODAL | MB_ICONINFORMATION | MB_YESNO) == IDYES);
  1364. }
  1365. if (OcPage->StringIds) {
  1366. pSetupFree(OcPage->StringIds);
  1367. OcPage->StringIds = NULL;
  1368. OcPage->StringIdsCount = 0;
  1369. }
  1370. return b;
  1371. }
  1372. BOOL
  1373. pChangeSubcomponentState(
  1374. IN POCPAGE OcPage,
  1375. IN HWND ListBox,
  1376. IN LONG SubcomponentStringId,
  1377. IN UINT Pass,
  1378. IN UINT NewState,
  1379. IN UINT Flags
  1380. )
  1381. /*++
  1382. Routine Description:
  1383. This routine turns on or off a subcomponent and all needed subcomponents
  1384. and child subcomponents.
  1385. Arguments:
  1386. OcPage - supplies OC page context info.
  1387. SubcomponentStringId - supplies string id for subcomponent to be turned on.
  1388. Pass - Supplies an ordinal value that controls operation of this routine.
  1389. Pass = 1: do not actually turn on the subcomponents, but instead
  1390. perform a dry-run wherein subcomponent installation DLLs
  1391. are asked whether they will allow the selection.
  1392. Pass = 2: actually turn on the subcomponents and update the
  1393. selection state in the optional component structure.
  1394. NewState - indicates the new state, SELSTATE_YES or SELSTATE_NO.
  1395. Flags - supplies misc flags
  1396. Return Value:
  1397. Boolean value indicating whether the routine was successful.
  1398. --*/
  1399. {
  1400. UINT n;
  1401. BOOL b;
  1402. BOOL any;
  1403. LONG l;
  1404. UINT SaveState;
  1405. UINT state;
  1406. OPTIONAL_COMPONENT Subcomponent;
  1407. OPTIONAL_COMPONENT OptionalComponent;
  1408. state = NewState;
  1409. pSetupStringTableGetExtraData(
  1410. OcPage->OcManager->ComponentStringTable,
  1411. SubcomponentStringId,
  1412. &OptionalComponent,
  1413. sizeof(OPTIONAL_COMPONENT)
  1414. );
  1415. //
  1416. // If the subcomponent is already in the desired state, do nothing.
  1417. //
  1418. if ((OptionalComponent.SelectionState == NewState)
  1419. || (OptionalComponent.InternalFlags & OCFLAG_STATECHANGE)) {
  1420. return (TRUE);
  1421. }
  1422. //
  1423. // Save the state so we can back out in case of failure,
  1424. // then set the "state change in progress" flag.
  1425. //
  1426. SaveState = OptionalComponent.SelectionState;
  1427. OptionalComponent.InternalFlags |= OCFLAG_STATECHANGE;
  1428. pSetupStringTableSetExtraData(
  1429. OcPage->OcManager->ComponentStringTable,
  1430. SubcomponentStringId,
  1431. &OptionalComponent,
  1432. sizeof(OPTIONAL_COMPONENT)
  1433. );
  1434. // ask the component whether it will allow being turned on.
  1435. b = OcInterfaceQueryChangeSelState(
  1436. OcPage->OcManager,
  1437. pOcGetTopLevelComponent(OcPage->OcManager,SubcomponentStringId),
  1438. pSetupStringTableStringFromId(OcPage->OcManager->ComponentStringTable,SubcomponentStringId),
  1439. (NewState != SELSTATE_NO),
  1440. (Pass == 1) ? Flags : Flags & ~(OCQ_ACTUAL_SELECTION)
  1441. );
  1442. if (!b)
  1443. goto Backout_ExtraData;
  1444. //
  1445. // Next, turn on needed/needed-by components.
  1446. // and turn off excluded/excluded-by components
  1447. //
  1448. if (NewState == SELSTATE_YES) {
  1449. for (n=0; n<OptionalComponent.NeedsCount; n++) {
  1450. b = pChangeSubcomponentState(
  1451. OcPage,
  1452. ListBox,
  1453. OptionalComponent.NeedsStringIds[n],
  1454. Pass,
  1455. NewState,
  1456. Flags & ~(OCQ_ACTUAL_SELECTION|OCO_COLLECT_NODEPENDENT));
  1457. if (!b) {
  1458. goto Backout_ExtraData;
  1459. }
  1460. }
  1461. } else if (NewState == SELSTATE_NO) {
  1462. for (n=0; n<OptionalComponent.NeededByCount; n++) {
  1463. b = pChangeSubcomponentState(
  1464. OcPage,
  1465. ListBox,
  1466. OptionalComponent.NeededByStringIds[n],
  1467. Pass,
  1468. NewState,
  1469. Flags & ~(OCQ_ACTUAL_SELECTION|OCO_COLLECT_NODEPENDENT));
  1470. if (!b) {
  1471. goto Backout_ExtraData;
  1472. }
  1473. }
  1474. }
  1475. // handle exclusives
  1476. if (NewState != SELSTATE_NO) {
  1477. for (n=0; n<OptionalComponent.ExcludedByCount; n++) {
  1478. b = pChangeSubcomponentState(
  1479. OcPage,
  1480. ListBox,
  1481. OptionalComponent.ExcludedByStringIds[n],
  1482. Pass,
  1483. SELSTATE_NO,
  1484. Flags & OCO_COLLECT_NODEPENDENT & ~(OCQ_ACTUAL_SELECTION));
  1485. if (!b) {
  1486. goto Backout_ExtraData;
  1487. }
  1488. }
  1489. for (n=0; n<OptionalComponent.ExcludeCount; n++) {
  1490. b = pChangeSubcomponentState(
  1491. OcPage,
  1492. ListBox,
  1493. OptionalComponent.ExcludeStringIds[n],
  1494. Pass,
  1495. SELSTATE_NO,
  1496. Flags & OCO_COLLECT_NODEPENDENT & ~(OCQ_ACTUAL_SELECTION));
  1497. if (!b) {
  1498. goto Backout_ExtraData;
  1499. }
  1500. }
  1501. }
  1502. //
  1503. // Turn off Collect needs if this is the top level selection or the
  1504. // dependent of the toplevel item
  1505. //
  1506. if ( Flags & OCQ_ACTUAL_SELECTION ) {
  1507. Flags |= OCO_COLLECT_NODEPENDENT;
  1508. }
  1509. //
  1510. // Now turn on/off all subcomponents.
  1511. //
  1512. any = (OptionalComponent.FirstChildStringId == -1) ? TRUE : FALSE;
  1513. for (l = OptionalComponent.FirstChildStringId; l != -1; l = Subcomponent.NextSiblingStringId) {
  1514. b = pChangeSubcomponentState(
  1515. OcPage,
  1516. ListBox,
  1517. l,
  1518. Pass,
  1519. NewState,
  1520. Flags & ~OCQ_ACTUAL_SELECTION);
  1521. if (b)
  1522. any = TRUE;
  1523. pSetupStringTableGetExtraData(
  1524. OcPage->OcManager->ComponentStringTable,
  1525. l,
  1526. &Subcomponent,
  1527. sizeof(OPTIONAL_COMPONENT)
  1528. );
  1529. }
  1530. // if all changes were rejected - fail
  1531. if (!any) {
  1532. b = FALSE;
  1533. goto Backout_ExtraData;
  1534. }
  1535. // load the return value and do the work
  1536. b = TRUE;
  1537. switch (Pass) {
  1538. case 1:
  1539. //
  1540. // Component says it's ok add this string ID to the list of Dependents
  1541. // Only if the user is making the selection
  1542. //
  1543. if ( (Flags & OCQ_COLLECT_NEEDS) // Are we checking
  1544. && !(Flags & OCO_COLLECT_NODEPENDENT ) // dependents of the Selection
  1545. && !(Flags & OCQ_ACTUAL_SELECTION ) // The current selections
  1546. ) {
  1547. LONG *p;
  1548. INT count = (INT)OcPage->StringIdsCount;
  1549. BOOL Found = FALSE;
  1550. //
  1551. // Search the list of dependent components
  1552. // Skip if the current component or the parent of the current component
  1553. // All ready is in the list
  1554. //
  1555. while (count-- ) {
  1556. if ( (OcPage->StringIds[count] == SubcomponentStringId)
  1557. || (OcPage->StringIds[count] == OptionalComponent.ParentStringId) ){
  1558. Found = TRUE;
  1559. break;
  1560. }
  1561. }
  1562. if ( !Found ) {
  1563. if (OcPage->StringIds) {
  1564. p = pSetupRealloc(
  1565. OcPage->StringIds,
  1566. (OcPage->StringIdsCount+1) * sizeof(LONG)
  1567. );
  1568. } else {
  1569. OcPage->StringIdsCount = 0;
  1570. p = pSetupMalloc(sizeof(LONG));
  1571. }
  1572. if (p) {
  1573. OcPage->StringIds = (PVOID)p;
  1574. OcPage->StringIds[OcPage->StringIdsCount++] = SubcomponentStringId;
  1575. } else {
  1576. _LogError(OcPage->OcManager,OcErrLevFatal,MSG_OC_OOM);
  1577. return (FALSE);
  1578. }
  1579. }
  1580. }
  1581. goto Backout_ExtraData;
  1582. break;
  1583. case 2:
  1584. //
  1585. // In pass 2, we update the states in the optional component structures
  1586. // and request the component DLL put its stuff on the disk space list.
  1587. // (The component itself is called only for leaf nodes. We do not call
  1588. // down to the subcomponent's DLL for parent components).
  1589. //
  1590. // check one more time to see if the state change wasn't as expected
  1591. if (OptionalComponent.FirstChildStringId != -1)
  1592. state = GetComponentState(OcPage, SubcomponentStringId);
  1593. OptionalComponent.SelectionState = state;
  1594. OptionalComponent.InternalFlags &= ~OCFLAG_STATECHANGE;
  1595. pSetupStringTableSetExtraData(
  1596. OcPage->OcManager->ComponentStringTable,
  1597. SubcomponentStringId,
  1598. &OptionalComponent,
  1599. sizeof(OPTIONAL_COMPONENT)
  1600. );
  1601. if (ListBox) {
  1602. pOcInvalidateRectInListBox(ListBox,OptionalComponent.Description);
  1603. }
  1604. if ((OptionalComponent.FirstChildStringId == -1) && !(Flags & OCQ_SKIPDISKCALC)) {
  1605. OcInterfaceCalcDiskSpace(
  1606. OcPage->OcManager,
  1607. pOcGetTopLevelComponent(OcPage->OcManager,SubcomponentStringId),
  1608. pSetupStringTableStringFromId(OcPage->OcManager->ComponentStringTable,SubcomponentStringId),
  1609. OcPage->DiskSpaceList,
  1610. (NewState != SELSTATE_NO)
  1611. );
  1612. }
  1613. pOcUpdateParentSelectionStates(OcPage->OcManager,ListBox,SubcomponentStringId);
  1614. b = TRUE;
  1615. break;
  1616. }
  1617. return (b);
  1618. Backout_ExtraData:
  1619. OptionalComponent.SelectionState = SaveState;
  1620. OptionalComponent.InternalFlags &= ~OCFLAG_STATECHANGE;
  1621. pSetupStringTableSetExtraData(
  1622. OcPage->OcManager->ComponentStringTable,
  1623. SubcomponentStringId,
  1624. &OptionalComponent,
  1625. sizeof(OPTIONAL_COMPONENT)
  1626. );
  1627. return (b);
  1628. }
  1629. VOID
  1630. pOcUpdateParentSelectionStates(
  1631. IN POC_MANAGER OcManager,
  1632. IN HWND ListBox, OPTIONAL
  1633. IN LONG SubcomponentStringId
  1634. )
  1635. /*++
  1636. Routine Description:
  1637. Examines parent subcomponents of a given component and determines
  1638. the parent states. For example if only some of a parent's children
  1639. are selected, then the parent's state is partially selected.
  1640. Structures are updated and if necessary the relevent items in the
  1641. list box are invalidated to force their checkboxes to be repainted.
  1642. Arguments:
  1643. OcManager - supplies OC Manager page context.
  1644. ListBox - supplies window handle of list box.
  1645. SubcomponentStringId - supplies string identifier in the component
  1646. string table, for the subcomponent whose parent(s) state(s) are
  1647. to be checked and updated.
  1648. Return Value:
  1649. None.
  1650. --*/
  1651. {
  1652. UINT Count;
  1653. UINT FullySelectedCount;
  1654. UINT DeselectedCount;
  1655. LONG l,m;
  1656. OPTIONAL_COMPONENT OptionalComponent,Subcomponent;
  1657. BOOL Changed;
  1658. pSetupStringTableGetExtraData(
  1659. OcManager->ComponentStringTable,
  1660. SubcomponentStringId,
  1661. &OptionalComponent,
  1662. sizeof(OPTIONAL_COMPONENT)
  1663. );
  1664. for (l = OptionalComponent.ParentStringId; l != -1; l = OptionalComponent.ParentStringId) {
  1665. pSetupStringTableGetExtraData(
  1666. OcManager->ComponentStringTable,
  1667. l,
  1668. &OptionalComponent,
  1669. sizeof(OPTIONAL_COMPONENT)
  1670. );
  1671. //
  1672. // Examine all children of this parent subcomponent.
  1673. // If all of them are fully selected, then the parent state is
  1674. // fully selected. If all of them are deselected then the parent state
  1675. // is deselected. Any other case means partially selected.
  1676. //
  1677. Count = 0;
  1678. FullySelectedCount = 0;
  1679. DeselectedCount = 0;
  1680. for (m = OptionalComponent.FirstChildStringId; m != -1; m = Subcomponent.NextSiblingStringId) {
  1681. pSetupStringTableGetExtraData(
  1682. OcManager->ComponentStringTable,
  1683. m,
  1684. &Subcomponent,
  1685. sizeof(OPTIONAL_COMPONENT)
  1686. );
  1687. //
  1688. // Only count viewable components
  1689. //
  1690. if (!(Subcomponent.InternalFlags & OCFLAG_HIDE)) {
  1691. Count++;
  1692. if (Subcomponent.SelectionState == SELSTATE_YES) {
  1693. FullySelectedCount++;
  1694. } else {
  1695. if (Subcomponent.SelectionState == SELSTATE_NO) {
  1696. DeselectedCount++;
  1697. }
  1698. }
  1699. }
  1700. }
  1701. if (Count && (Count == FullySelectedCount)) {
  1702. Changed = (OptionalComponent.SelectionState != SELSTATE_YES);
  1703. OptionalComponent.SelectionState = SELSTATE_YES;
  1704. } else {
  1705. if (Count == DeselectedCount) {
  1706. Changed = (OptionalComponent.SelectionState != SELSTATE_NO);
  1707. OptionalComponent.SelectionState = SELSTATE_NO;
  1708. } else {
  1709. Changed = (OptionalComponent.SelectionState != SELSTATE_PARTIAL);
  1710. OptionalComponent.SelectionState = SELSTATE_PARTIAL;
  1711. }
  1712. }
  1713. pSetupStringTableSetExtraData(
  1714. OcManager->ComponentStringTable,
  1715. l,
  1716. &OptionalComponent,
  1717. sizeof(OPTIONAL_COMPONENT)
  1718. );
  1719. //
  1720. // Force repaint of the list to get the checkbox state right
  1721. // if the state changed and the item is in the current listbox.
  1722. //
  1723. if (Changed && ListBox) {
  1724. pOcInvalidateRectInListBox(ListBox,OptionalComponent.Description);
  1725. }
  1726. }
  1727. }
  1728. VOID
  1729. pOcInvalidateRectInListBox(
  1730. IN HWND ListBox,
  1731. IN LPCTSTR OptionalComponentName OPTIONAL
  1732. )
  1733. {
  1734. int i;
  1735. RECT Rect;
  1736. if (OptionalComponentName) {
  1737. i = (int)SendMessage(
  1738. ListBox,
  1739. LB_FINDSTRINGEXACT,
  1740. (WPARAM)(-1),
  1741. (LPARAM)OptionalComponentName
  1742. );
  1743. if (i >= 0) {
  1744. SendMessage(ListBox,LB_GETITEMRECT,i,(LPARAM)&Rect);
  1745. InvalidateRect(ListBox,&Rect,FALSE);
  1746. }
  1747. } else {
  1748. InvalidateRect(ListBox,NULL,FALSE);
  1749. }
  1750. }
  1751. VOID
  1752. pOcUpdateSpaceNeededText(
  1753. IN POCPAGE OcPage,
  1754. IN HWND hdlg
  1755. )
  1756. /*++
  1757. Routine Description:
  1758. Updates the space needed/space available text on the current
  1759. oc page. Assumes that space needed and available refer to the drive
  1760. where the system is installed.
  1761. Arguments:
  1762. OcPage - supplies OC page context.
  1763. hdlg - supplies handle to current oc page dialog.
  1764. Return Value:
  1765. None.
  1766. --*/
  1767. {
  1768. TCHAR Text[128];
  1769. LONGLONG Value;
  1770. DWORD ValueMB;
  1771. DWORD ValueMBTenths;
  1772. TCHAR Drive[MAX_PATH];
  1773. BOOL b;
  1774. DWORD spc,bps,freeclus,totalclus;
  1775. // We check the return code of GetWindowsDirectory to make Prefix happy.
  1776. if (0 == GetWindowsDirectory(Drive,MAX_PATH))
  1777. return;
  1778. //
  1779. // Needed first.
  1780. //
  1781. Drive[2] = 0;
  1782. b = SetupQuerySpaceRequiredOnDrive(OcPage->DiskSpaceList,Drive,&Value,0,0);
  1783. if (!b || (Value < 0)) {
  1784. Value = 0;
  1785. }
  1786. pOcGetMbAndMbTenths(Value,&ValueMB,&ValueMBTenths);
  1787. wsprintf(Text,OcPage->SpaceNeededTextFormat,ValueMB,locale.DecimalSeparator,ValueMBTenths);
  1788. SetDlgItemText(hdlg,OcPage->ControlsInfo->SpaceNeededText,Text);
  1789. //
  1790. // Available next.
  1791. //
  1792. Drive[2] = TEXT('\\');
  1793. Drive[3] = 0;
  1794. if (GetDiskFreeSpace(Drive,&spc,&bps,&freeclus,&totalclus)) {
  1795. Value = ((LONGLONG)(spc*bps)) * freeclus;
  1796. } else {
  1797. Value = 0;
  1798. }
  1799. pOcGetMbAndMbTenths(Value,&ValueMB,&ValueMBTenths);
  1800. wsprintf(Text,OcPage->SpaceNeededTextFormat,ValueMB,locale.DecimalSeparator,ValueMBTenths);
  1801. SetDlgItemText(hdlg,OcPage->ControlsInfo->SpaceAvailableText,Text);
  1802. }
  1803. BOOL
  1804. pOcIsDiskSpaceOk(
  1805. IN POCPAGE OcPage,
  1806. IN HWND hdlg
  1807. )
  1808. /*++
  1809. Routine Description:
  1810. This routine checks the space required against the space available,
  1811. for the system drive only (that's the only one the user sees on the
  1812. oc page so it's the only one we check here).
  1813. If there's not enough space, a message box is generated.
  1814. Arguments:
  1815. OcPage - supplies OC page context structure.
  1816. hdlg - supplies handle to page in oc manager wizard.
  1817. Return Value:
  1818. Boolean value indicating whether disk space is sufficient.
  1819. --*/
  1820. {
  1821. BOOL b;
  1822. TCHAR Drive[3*MAX_PATH];
  1823. TCHAR caption[256];
  1824. LONGLONG FreeSpace,NeededSpace;
  1825. ULARGE_INTEGER freespace,totalspace,unused;
  1826. DWORD spc,bps,freeclus,totclus;
  1827. HMODULE k32;
  1828. BOOL (WINAPI * pGetSpace)(LPCTSTR,PULARGE_INTEGER,PULARGE_INTEGER,PULARGE_INTEGER);
  1829. if (!GetWindowsDirectory(Drive,MAX_PATH)) {
  1830. return(FALSE);
  1831. }
  1832. b = FALSE;
  1833. if (k32 = LoadLibrary(TEXT("KERNEL32"))) {
  1834. pGetSpace = (PVOID)GetProcAddress(
  1835. k32,
  1836. #ifdef UNICODE
  1837. "GetDiskFreeSpaceExW"
  1838. #else
  1839. "GetDiskFreeSpaceExA"
  1840. #endif
  1841. );
  1842. if (pGetSpace) {
  1843. if (b = pGetSpace(Drive,&freespace,&totalspace,&unused)) {
  1844. FreeSpace = (LONGLONG)freespace.QuadPart;
  1845. }
  1846. }
  1847. FreeLibrary(k32);
  1848. }
  1849. if (!b) {
  1850. Drive[3] = 0;
  1851. if (GetDiskFreeSpace(Drive,&spc,&bps,&freeclus,&totclus)) {
  1852. FreeSpace = (LONGLONG)(spc * bps * (DWORDLONG)freeclus);
  1853. } else {
  1854. FreeSpace = 0;
  1855. }
  1856. }
  1857. Drive[2] = 0;
  1858. b = SetupQuerySpaceRequiredOnDrive(OcPage->DiskSpaceList,Drive,&NeededSpace,0,0);
  1859. if (!b || (NeededSpace < 0)) {
  1860. NeededSpace = 0;
  1861. }
  1862. if (FreeSpace < NeededSpace) {
  1863. spc = (DWORD)(UCHAR)Drive[0];
  1864. FormatMessage(
  1865. FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1866. MyModuleHandle,
  1867. MSG_OC_PAGE_NODISKSPACE,
  1868. 0,
  1869. Drive,
  1870. sizeof(Drive)/sizeof(TCHAR),
  1871. (va_list *)&spc
  1872. );
  1873. OcPage->OcManager->Callbacks.LogError(OcErrLevInfo, Drive, NULL);
  1874. //
  1875. // If Batch mode log the error and ignore
  1876. //
  1877. if ( OcPage->OcManager->SetupData.OperationFlags & SETUPOP_BATCH ) {
  1878. b = TRUE;
  1879. } else {
  1880. *caption = 0;
  1881. LoadString(MyModuleHandle, IDS_SETUP, caption, sizeof(caption)/sizeof(TCHAR));
  1882. sapiAssert(*caption);
  1883. MessageBox(WizardDialogHandle,
  1884. Drive,
  1885. caption,
  1886. MB_ICONINFORMATION | MB_OK);
  1887. b = FALSE;
  1888. }
  1889. } else {
  1890. b = TRUE;
  1891. }
  1892. return (b);
  1893. }
  1894. BOOL
  1895. pOcPagePopulateListBox(
  1896. IN POCPAGE OcPage,
  1897. IN HWND ListBox,
  1898. IN LONG DesiredParent
  1899. )
  1900. /*++
  1901. Routine Description:
  1902. This routine add one item to a listbox control for every subcomponent
  1903. that has a given subcomponent as its parent. (In other words it populates
  1904. the listbox for a specific level in the hierarchy.)
  1905. This includes handling the small icons and selection state icons.
  1906. The 0th element is selected.
  1907. Arguments:
  1908. OcPage - supplies OC page context structure.
  1909. List - supplies handle to list box control to be populated.
  1910. DesiredParent - supplies string id of subcomponent that is the parent
  1911. of the level we care about. -1 indicates the topmost level.
  1912. Return Value:
  1913. Boolean value indicating whether population was successful.
  1914. If FALSE, the caller can assume OOM.
  1915. --*/
  1916. {
  1917. OPTIONAL_COMPONENT OptionalComponent;
  1918. POPULATE_ENUM_PARAMS EnumParams;
  1919. BOOL b;
  1920. //
  1921. // The string table enum callback does the real work.
  1922. //
  1923. EnumParams.OcPage = OcPage;
  1924. EnumParams.ListBox = ListBox;
  1925. EnumParams.DesiredParent = DesiredParent;
  1926. b = pSetupStringTableEnum(
  1927. OcPage->OcManager->ComponentStringTable,
  1928. &OptionalComponent,
  1929. sizeof(OPTIONAL_COMPONENT),
  1930. (PSTRTAB_ENUM_ROUTINE)pOcPopulateListBoxStringTableCB,
  1931. (LPARAM)&EnumParams
  1932. );
  1933. SendMessage(ListBox,LB_SETCURSEL,0,0);
  1934. PostMessage(
  1935. GetParent(ListBox),
  1936. WM_COMMAND,
  1937. MAKEWPARAM(OcPage->ControlsInfo->ListBox,LBN_SELCHANGE),
  1938. (LPARAM)ListBox
  1939. );
  1940. return (b);
  1941. }
  1942. BOOL
  1943. pOcPopulateListBoxStringTableCB(
  1944. IN PVOID StringTable,
  1945. IN LONG StringId,
  1946. IN LPCTSTR String,
  1947. IN POPTIONAL_COMPONENT OptionalComponent,
  1948. IN UINT OptionalComponentSize,
  1949. IN PPOPULATE_ENUM_PARAMS Params
  1950. )
  1951. /*++
  1952. Routine Description:
  1953. String table enumeration callback routine, used when populating
  1954. the listbox with items for subcomponents that are relevent at
  1955. a given level in the OC hierarchy.
  1956. We check to see whether the parent of the optional component is
  1957. the parent we care about before processing. If so, we add the item
  1958. to the listbox.
  1959. Arguments:
  1960. Standard string table enumeration callback routine arguments.
  1961. Return Value:
  1962. Boolean value indicating whether enumeration should continue.
  1963. --*/
  1964. {
  1965. int i;
  1966. BOOL b;
  1967. //
  1968. // If the parent is not the desired parent, nothing to do.
  1969. //
  1970. if ((OptionalComponent->InfStringId == -1)
  1971. || (OptionalComponent->ParentStringId != Params->DesiredParent)
  1972. || (OptionalComponent->InternalFlags & OCFLAG_HIDE)) {
  1973. return (TRUE);
  1974. }
  1975. //
  1976. // Initialize the item structure that tells the listview control
  1977. // what to do.
  1978. //
  1979. b = FALSE;
  1980. i = (int)SendMessage(Params->ListBox,LB_ADDSTRING,0,(LPARAM)OptionalComponent->Description);
  1981. if (i != -1) {
  1982. b = (SendMessage(Params->ListBox,LB_SETITEMDATA,i,StringId) != LB_ERR);
  1983. }
  1984. return (b);
  1985. }
  1986. LONG
  1987. pOcGetTopLevelComponent(
  1988. IN POC_MANAGER OcManager,
  1989. IN LONG StringId
  1990. )
  1991. /*++
  1992. Routine Description:
  1993. Given a string id for an optional component subcomponent,
  1994. locate the top-level component for the subcomponent.
  1995. The top-level component is the subcomponent whose parent is -1.
  1996. Arguments:
  1997. OcManager - supplies OC Manager context structure.
  1998. StringId - supplies id for subcomponent whose top-level parent is desired.
  1999. Note that StringId may itself be a top-level subcomponent.
  2000. Return Value:
  2001. String ID of top-level subcomponent.
  2002. --*/
  2003. {
  2004. OPTIONAL_COMPONENT Oc;
  2005. pSetupStringTableGetExtraData(
  2006. OcManager->ComponentStringTable,
  2007. StringId,
  2008. &Oc,
  2009. sizeof(OPTIONAL_COMPONENT)
  2010. );
  2011. // if the result is 0, then the component is
  2012. // a top level component without an inf file
  2013. if (!Oc.TopLevelStringId)
  2014. return StringId;
  2015. else
  2016. return Oc.TopLevelStringId;
  2017. }
  2018. VOID
  2019. pOcGetMbAndMbTenths(
  2020. IN LONGLONG Number,
  2021. OUT PUINT MbCount,
  2022. OUT PUINT MbTenthsCount
  2023. )
  2024. /*++
  2025. Routine Description:
  2026. This routine figures out how many MB and how many tenths of a MB
  2027. are in a number. These values are properly rounded (not truncated)
  2028. and are based on 1MB = 1024*1024.
  2029. Arguments:
  2030. Number - supplies number to be examined.
  2031. MbCount - receives rounded number of MB units in Number.
  2032. MbTenthsCount - receives rounded number of tenths of MB in Number.
  2033. Return Value:
  2034. None. MbCount and MbTenthsCount filled are in.
  2035. --*/
  2036. {
  2037. UINT ValueMB;
  2038. UINT ValueMBTenths;
  2039. UINT ValueMBHundredths;
  2040. #define _1MB (1024*1024)
  2041. //
  2042. // Figure out how many whole 1MB units are in the number.
  2043. //
  2044. ValueMB = (UINT)(Number / _1MB);
  2045. //
  2046. // Figure out how many whole hundredths of 1MB units are in
  2047. // the number. Do it in such a way as to not lose any accuracy.
  2048. // ValueMBHundredths will be 0-99 and ValueMBTenths will be 0-9.
  2049. //
  2050. ValueMBHundredths = (UINT)(((Number % _1MB) * 100) / _1MB);
  2051. ValueMBTenths = ValueMBHundredths / 10;
  2052. //
  2053. // If the one's place in the number of hundredths is >=5,
  2054. // then round up the tenths. That might in turn cause is to round
  2055. // up the the next whole # of MB.
  2056. //
  2057. if ((ValueMBHundredths % 10) >= 5) {
  2058. if (++ValueMBTenths == 10) {
  2059. ValueMBTenths = 0;
  2060. ValueMB++;
  2061. }
  2062. }
  2063. //
  2064. // Done.
  2065. //
  2066. *MbCount = ValueMB;
  2067. *MbTenthsCount = ValueMBTenths;
  2068. }
  2069. UINT
  2070. OcGetUnattendComponentSpec(
  2071. IN POC_MANAGER OcManager,
  2072. IN LPCTSTR Component
  2073. )
  2074. {
  2075. LPCTSTR p;
  2076. LPCTSTR szOn = TEXT("ON");
  2077. LPCTSTR szOff = TEXT("OFF");
  2078. LPCTSTR szDefault = TEXT("DEFAULT");
  2079. extern LPCTSTR szComponents; // defined in ocmanage.c
  2080. INFCONTEXT InfLine;
  2081. UINT NewState = SubcompUseOcManagerDefault;
  2082. if (SetupFindFirstLine(OcManager->UnattendedInf,szComponents,Component,&InfLine)) {
  2083. //
  2084. // Get State parameter from as the first field
  2085. //
  2086. if (p = pSetupGetField(&InfLine,1)) {
  2087. //
  2088. // Found Something now Decode it
  2089. //
  2090. if (!lstrcmpi(p,szOn)) {
  2091. NewState = SubcompOn;
  2092. } else if (!lstrcmpi(p,szOff)) {
  2093. NewState = SubcompOff;
  2094. } else if (!lstrcmpi(p,szDefault)) {
  2095. NewState = SubcompUseOcManagerDefault;
  2096. } else {
  2097. WRN((TEXT("OcGetUnattendComponentSpec: Unknown Component State(%s)\n"),p));
  2098. }
  2099. }
  2100. }
  2101. return NewState;
  2102. }
  2103. BOOL
  2104. pOcClearStateChange(
  2105. IN PVOID StringTable,
  2106. IN LONG StringId,
  2107. IN LPCTSTR String,
  2108. IN POPTIONAL_COMPONENT Oc,
  2109. IN UINT OcSize,
  2110. IN LPARAM lParam
  2111. )
  2112. {
  2113. POCPAGE OcPage = (POCPAGE) lParam;
  2114. int i;
  2115. UNREFERENCED_PARAMETER(StringTable);
  2116. UNREFERENCED_PARAMETER(OcSize);
  2117. //
  2118. // clear the State change flag
  2119. //
  2120. Oc->InternalFlags &= ~OCFLAG_STATECHANGE;
  2121. pSetupStringTableSetExtraData(
  2122. OcPage->OcManager->ComponentStringTable,
  2123. StringId,
  2124. Oc,
  2125. sizeof(OPTIONAL_COMPONENT)
  2126. );
  2127. return TRUE;
  2128. }
  2129. VOID
  2130. pOcSetStates(
  2131. IN OUT POCPAGE OcPage
  2132. )
  2133. /*++
  2134. Routine Description:
  2135. Set current states for all components.
  2136. If all components were initially off (indicating that this is a
  2137. first-time install) then this routine initializes the current states
  2138. of each leaf component based on the mode bits gathered from the
  2139. per-component infs.
  2140. Otherwise (not a first-time install) query the dll if any
  2141. to determine the current state.
  2142. No confirmations are sent to component dlls as subcomponents are
  2143. set to the selected state, but we do send the calcdiskspace
  2144. notifications.
  2145. Arguments:
  2146. OcPage - supplies current oc context.
  2147. Return Value:
  2148. None.
  2149. --*/
  2150. {
  2151. OPTIONAL_COMPONENT Oc;
  2152. UINT i;
  2153. UINT tli;
  2154. UINT StringID;
  2155. //
  2156. // Process each top level parent item in the tree
  2157. //
  2158. for ( tli = 0; tli < OcPage->OcManager->TopLevelOcCount; tli++)
  2159. for (i=0; i<OcPage->OcManager->TopLevelParentOcCount; i++) {
  2160. pSetupStringTableGetExtraData(
  2161. OcPage->OcManager->ComponentStringTable,
  2162. OcPage->OcManager->TopLevelParentOcStringIds[i],
  2163. &Oc,
  2164. sizeof(OPTIONAL_COMPONENT)
  2165. );
  2166. //
  2167. // Traverse the list in the order defined inf fil
  2168. //
  2169. if ( OcPage->OcManager->TopLevelOcStringIds[tli]
  2170. == pOcGetTopLevelComponent(OcPage->OcManager,OcPage->OcManager->TopLevelParentOcStringIds[i])) {
  2171. //
  2172. // Call each top level item, Each top level item then will call it's
  2173. // suboridiates and Needs and or Needed by components
  2174. //
  2175. pOcSetStatesStringWorker(OcPage->OcManager->TopLevelParentOcStringIds[i], SubcompUseOcManagerDefault, OcPage );
  2176. }
  2177. }
  2178. //
  2179. // Clear the OCFLAG_STATECHANGE Flag
  2180. //
  2181. pSetupStringTableEnum(
  2182. OcPage->OcManager->ComponentStringTable,
  2183. &Oc,
  2184. sizeof(OPTIONAL_COMPONENT),
  2185. pOcSetStatesStringCB2,
  2186. (LPARAM)OcPage
  2187. );
  2188. }
  2189. BOOL
  2190. pOcSetStatesStringWorker(
  2191. IN LONG StringId,
  2192. IN UINT OverRideState,
  2193. IN POCPAGE OcPage
  2194. )
  2195. {
  2196. OPTIONAL_COMPONENT Oc, Subcomponent;
  2197. LPCTSTR String;
  2198. SubComponentState s;
  2199. UINT NewState;
  2200. UINT l;
  2201. pSetupStringTableGetExtraData(
  2202. OcPage->OcManager->ComponentStringTable,
  2203. StringId,
  2204. &Oc,
  2205. sizeof(OPTIONAL_COMPONENT)
  2206. );
  2207. //
  2208. // Deal only with leaf components.
  2209. //
  2210. if (Oc.FirstChildStringId != -1) {
  2211. //
  2212. // Now turn on all subcomponents.
  2213. //
  2214. for (l = Oc.FirstChildStringId; l != -1; l = Oc.NextSiblingStringId) {
  2215. pOcSetStatesStringWorker( l, OverRideState, OcPage );
  2216. //
  2217. // Get the next Depenend in the list
  2218. //
  2219. pSetupStringTableGetExtraData(
  2220. OcPage->OcManager->ComponentStringTable,
  2221. l,
  2222. &Oc,
  2223. sizeof(OPTIONAL_COMPONENT)
  2224. );
  2225. }
  2226. pOcUpdateParentSelectionStates(OcPage->OcManager,NULL,StringId);
  2227. } else {
  2228. //
  2229. // Don't process the same node twice
  2230. //
  2231. if ( Oc.InternalFlags & OCFLAG_STATECHANGE ) {
  2232. return TRUE;
  2233. }
  2234. String = pSetupStringTableStringFromId(OcPage->OcManager->ComponentStringTable,StringId);
  2235. //
  2236. // Not initial install case. Call out to component dll to find out
  2237. // whether state needs to be set.
  2238. //
  2239. s = OcInterfaceQueryState(
  2240. OcPage->OcManager,
  2241. pOcGetTopLevelComponent(OcPage->OcManager,StringId),String, OCSELSTATETYPE_CURRENT);
  2242. if ( (OcPage->OcManager->SetupMode & SETUPMODE_PRIVATE_MASK) == SETUPMODE_REMOVEALL )
  2243. {
  2244. // If Remove all Override all install states and mark the compoent to be
  2245. // removed
  2246. NewState = SELSTATE_NO;
  2247. } else {
  2248. //
  2249. // If needs or Needby relationtionships are driving this path
  2250. // OverRideState May be something other then Default
  2251. //
  2252. if ( OverRideState != SubcompUseOcManagerDefault ) {
  2253. s = OverRideState;
  2254. }
  2255. //
  2256. // If the component returned Default and we are in Batch Mode
  2257. // Get the the Spec from the Unattended file
  2258. //
  2259. if ( s == SubcompUseOcManagerDefault
  2260. && OcPage->OcManager->SetupData.OperationFlags & SETUPOP_BATCH ){
  2261. s = OcGetUnattendComponentSpec(OcPage->OcManager, String);
  2262. }
  2263. if (s == SubcompUseOcManagerDefault) {
  2264. if (Oc.InternalFlags & (OCFLAG_ANYORIGINALLYON | OCFLAG_ANYORIGINALLYOFF)) {
  2265. NewState = Oc.OriginalSelectionState;
  2266. } else {
  2267. if ((1 << (OcPage->OcManager->SetupMode & SETUPMODE_STANDARD_MASK)) & Oc.ModeBits) {
  2268. //
  2269. // Allow Modes= lines to act an override condition if it ON
  2270. //
  2271. NewState = SELSTATE_YES;
  2272. s = SubcompOn;
  2273. } else {
  2274. NewState = SELSTATE_NO;
  2275. }
  2276. }
  2277. } else {
  2278. NewState = (s == SubcompOn ? SELSTATE_YES: SELSTATE_NO);
  2279. }
  2280. }
  2281. DBGOUT((
  2282. TEXT("SubComp=%s, Original=%d, Current=%d, NewState=%s\n"),
  2283. String,
  2284. Oc.OriginalSelectionState,
  2285. s,
  2286. (NewState == SELSTATE_YES) ? TEXT("ON") : TEXT("OFF")
  2287. ));
  2288. //
  2289. // Save the current state of the component
  2290. //
  2291. Oc.SelectionState = NewState;
  2292. Oc.InternalFlags |= OCFLAG_STATECHANGE;
  2293. if ( NewState == SELSTATE_YES ) {
  2294. //
  2295. // Make a pass over the Needs
  2296. //
  2297. for (l=0; l<Oc.NeedsCount; l++) {
  2298. if (!pOcSetNeededComponentState( Oc.NeedsStringIds[l], OverRideState, OcPage ))
  2299. return TRUE;
  2300. pSetupStringTableGetExtraData(
  2301. OcPage->OcManager->ComponentStringTable,
  2302. Oc.NeedsStringIds[l],
  2303. &Subcomponent,
  2304. sizeof(OPTIONAL_COMPONENT)
  2305. );
  2306. }
  2307. }
  2308. pSetupStringTableSetExtraData(
  2309. OcPage->OcManager->ComponentStringTable,
  2310. StringId,
  2311. &Oc,
  2312. sizeof(OPTIONAL_COMPONENT)
  2313. );
  2314. if ( NewState == SELSTATE_YES ) {
  2315. //
  2316. // Make a pass over the Needs
  2317. //
  2318. for (l=0; l<Oc.NeedsCount; l++) {
  2319. pOcSetStatesStringWorker( Oc.NeedsStringIds[l], s, OcPage );
  2320. pSetupStringTableGetExtraData(
  2321. OcPage->OcManager->ComponentStringTable,
  2322. Oc.NeedsStringIds[l],
  2323. &Subcomponent,
  2324. sizeof(OPTIONAL_COMPONENT)
  2325. );
  2326. }
  2327. } else {
  2328. //
  2329. // Make a pass over the NeedsBy - turning off components
  2330. //
  2331. for (l=0; l<Oc.NeededByCount; l++) {
  2332. pOcSetStatesStringWorker( Oc.NeededByStringIds[l], s, OcPage );
  2333. pSetupStringTableGetExtraData(
  2334. OcPage->OcManager->ComponentStringTable,
  2335. Oc.NeededByStringIds[l],
  2336. &Subcomponent,
  2337. sizeof(OPTIONAL_COMPONENT)
  2338. );
  2339. }
  2340. }
  2341. }
  2342. pOcUpdateParentSelectionStates(OcPage->OcManager,NULL,StringId);
  2343. return TRUE;
  2344. }
  2345. BOOL
  2346. pOcSetNeededComponentState(
  2347. IN LONG StringId,
  2348. IN UINT OverRideState,
  2349. IN POCPAGE OcPage
  2350. )
  2351. {
  2352. OPTIONAL_COMPONENT Oc, Subcomponent;
  2353. LPCTSTR String;
  2354. SubComponentState s;
  2355. UINT NewState;
  2356. UINT l;
  2357. BOOL b;
  2358. // first find any components this one needs
  2359. pSetupStringTableGetExtraData(
  2360. OcPage->OcManager->ComponentStringTable,
  2361. StringId,
  2362. &Oc,
  2363. sizeof(OPTIONAL_COMPONENT)
  2364. );
  2365. for (l=0; l<Oc.NeedsCount; l++) {
  2366. if (!pOcSetNeededComponentState( Oc.NeedsStringIds[l], OverRideState, OcPage ))
  2367. return TRUE;
  2368. pSetupStringTableGetExtraData(
  2369. OcPage->OcManager->ComponentStringTable,
  2370. Oc.NeedsStringIds[l],
  2371. &Subcomponent,
  2372. sizeof(OPTIONAL_COMPONENT)
  2373. );
  2374. }
  2375. // now handle this one
  2376. pSetupStringTableGetExtraData(
  2377. OcPage->OcManager->ComponentStringTable,
  2378. StringId,
  2379. &Oc,
  2380. sizeof(OPTIONAL_COMPONENT)
  2381. );
  2382. String = pSetupStringTableStringFromId(OcPage->OcManager->ComponentStringTable,StringId);
  2383. b = OcInterfaceQueryChangeSelState(
  2384. OcPage->OcManager,
  2385. pOcGetTopLevelComponent(OcPage->OcManager,StringId),
  2386. String,
  2387. TRUE,
  2388. 0
  2389. );
  2390. if (b) {
  2391. NewState = SELSTATE_YES;
  2392. s = SubcompOn;
  2393. } else {
  2394. NewState = SELSTATE_NO;
  2395. s = SubcompOff;
  2396. }
  2397. DBGOUT(( TEXT("SubComp=%s, Original=%d, Current=%d, NewState=%s\n"),
  2398. String,
  2399. Oc.OriginalSelectionState,
  2400. s,
  2401. (NewState == SELSTATE_YES) ? TEXT("ON") : TEXT("OFF")
  2402. ));
  2403. //
  2404. // Save the current state of the component
  2405. //
  2406. Oc.SelectionState = NewState;
  2407. Oc.InternalFlags |= OCFLAG_STATECHANGE;
  2408. pSetupStringTableSetExtraData(
  2409. OcPage->OcManager->ComponentStringTable,
  2410. StringId,
  2411. &Oc,
  2412. sizeof(OPTIONAL_COMPONENT)
  2413. );
  2414. pOcUpdateParentSelectionStates(OcPage->OcManager,NULL,StringId);
  2415. return b;
  2416. }
  2417. BOOL
  2418. pOcSetStatesStringCB2(
  2419. IN PVOID StringTable,
  2420. IN LONG StringId,
  2421. IN LPCTSTR String,
  2422. IN POPTIONAL_COMPONENT Oc,
  2423. IN UINT OcSize,
  2424. IN LPARAM lParam
  2425. )
  2426. {
  2427. POCPAGE OcPage;
  2428. int i;
  2429. UNREFERENCED_PARAMETER(StringTable);
  2430. UNREFERENCED_PARAMETER(OcSize);
  2431. OcPage = (POCPAGE)lParam;
  2432. //
  2433. // clear the State change flag left over from
  2434. // the pOcSetStatesStringWorker
  2435. //
  2436. Oc->InternalFlags &= ~OCFLAG_STATECHANGE;
  2437. pSetupStringTableSetExtraData(
  2438. OcPage->OcManager->ComponentStringTable,
  2439. StringId,
  2440. Oc,
  2441. sizeof(OPTIONAL_COMPONENT)
  2442. );
  2443. //
  2444. // Deal only with leaf components.
  2445. //
  2446. if (Oc->FirstChildStringId != -1) {
  2447. return (TRUE);
  2448. }
  2449. i = 0;
  2450. if (OcPage->OcManager->InternalFlags & OCMFLAG_ANYORIGINALLYON) {
  2451. //
  2452. // Not initial install case. Deal with disk space based on
  2453. // original state.
  2454. //
  2455. if (Oc->OriginalSelectionState == SELSTATE_YES) {
  2456. if (Oc->SelectionState == SELSTATE_NO) {
  2457. //
  2458. // Turning off what was previously on
  2459. //
  2460. i = 1;
  2461. }
  2462. } else {
  2463. if (Oc->SelectionState == SELSTATE_YES) {
  2464. //
  2465. // Turning on what was previous off
  2466. //
  2467. i = 2;
  2468. }
  2469. }
  2470. } else {
  2471. //
  2472. // Initial install case. If a component is on, do its disk space calc.
  2473. // If a component is off, we assume it's not already there and so
  2474. // we do nothing relating to its disk space requirements.
  2475. //
  2476. if (Oc->SelectionState == SELSTATE_YES) {
  2477. i = 2;
  2478. }
  2479. }
  2480. if (i) {
  2481. OcInterfaceCalcDiskSpace(
  2482. OcPage->OcManager,
  2483. pOcGetTopLevelComponent(OcPage->OcManager,StringId),
  2484. String,
  2485. OcPage->DiskSpaceList,
  2486. i-1
  2487. );
  2488. }
  2489. return (TRUE);
  2490. }
  2491. BOOL
  2492. pOcDoesAnyoneWantToSkipPage(
  2493. IN OUT POC_MANAGER OcManager,
  2494. IN OcManagerPage WhichPage
  2495. )
  2496. {
  2497. UINT u;
  2498. for (u=0; u<OcManager->TopLevelOcCount; u++) {
  2499. OPTIONAL_COMPONENT Oc;
  2500. pSetupStringTableGetExtraData(
  2501. OcManager->ComponentStringTable,
  2502. OcManager->TopLevelOcStringIds[u],
  2503. &Oc,
  2504. sizeof(OPTIONAL_COMPONENT)
  2505. );
  2506. if ((Oc.InternalFlags & OCFLAG_NOQUERYSKIPPAGES) == 0) {
  2507. if (OcInterfaceQuerySkipPage(OcManager,OcManager->TopLevelOcStringIds[u],WhichPage)) {
  2508. return (TRUE);
  2509. }
  2510. }
  2511. }
  2512. return (FALSE);
  2513. }
  2514. UINT
  2515. GetComponentState(
  2516. IN POCPAGE OcPage,
  2517. IN LONG StringId
  2518. )
  2519. {
  2520. LONG id;
  2521. UINT rc;
  2522. UINT state;
  2523. SubComponentState s;
  2524. OPTIONAL_COMPONENT Oc;
  2525. pSetupStringTableGetExtraData(
  2526. OcPage->OcManager->ComponentStringTable,
  2527. StringId,
  2528. &Oc,
  2529. sizeof(OPTIONAL_COMPONENT)
  2530. );
  2531. if (Oc.FirstChildStringId == -1)
  2532. return Oc.SelectionState;
  2533. // We have a parent; do all the children
  2534. rc = SELSTATE_INIT;
  2535. for (id = Oc.FirstChildStringId; id != -1; id = Oc.NextSiblingStringId) {
  2536. state = GetComponentState(OcPage, id);
  2537. if (state == SELSTATE_PARTIAL)
  2538. return state;
  2539. if (rc == SELSTATE_INIT)
  2540. rc = state;
  2541. if (rc != state)
  2542. return SELSTATE_PARTIAL;
  2543. pSetupStringTableGetExtraData(
  2544. OcPage->OcManager->ComponentStringTable,
  2545. id,
  2546. &Oc,
  2547. sizeof(OPTIONAL_COMPONENT)
  2548. );
  2549. }
  2550. return rc;
  2551. }
  2552. #ifdef _OC_DBG
  2553. VOID
  2554. pOcPrintStatesWorker(
  2555. IN LPCTSTR Offset,
  2556. IN POCPAGE OcPage,
  2557. IN LONG StringId
  2558. )
  2559. {
  2560. SubComponentState s;
  2561. OPTIONAL_COMPONENT Oc;
  2562. pSetupStringTableGetExtraData(
  2563. OcPage->OcManager->ComponentStringTable,
  2564. StringId,
  2565. &Oc,
  2566. sizeof(OPTIONAL_COMPONENT)
  2567. );
  2568. DBGOUT(( TEXT("%32s\n"),
  2569. pSetupStringTableStringFromId(OcPage->OcManager->ComponentStringTable,StringId)
  2570. ));
  2571. //
  2572. // Deal only with leaf components.
  2573. //
  2574. if (Oc.FirstChildStringId == -1) {
  2575. DBGOUT((
  2576. TEXT(" Orignial(%s) Current(%s) ANYORIGINALLYON (%s) Mode (%d)\n"),
  2577. (Oc.OriginalSelectionState == SELSTATE_YES ? TEXT("Yes") : TEXT("No")),
  2578. (Oc.SelectionState == SELSTATE_YES ? TEXT("Yes") : TEXT("No")),
  2579. (Oc.InternalFlags & OCFLAG_ANYORIGINALLYON) ? TEXT("TRUE") : TEXT("FALSE"),
  2580. SETUPMODE_STANDARD_MASK & Oc.ModeBits
  2581. ));
  2582. } else {
  2583. //
  2584. // We have a parent; do all the children
  2585. //
  2586. LONG Id;
  2587. for (Id = Oc.FirstChildStringId; Id != -1; Id = Oc.NextSiblingStringId) {
  2588. pOcPrintStatesWorker(
  2589. Offset,
  2590. OcPage,
  2591. Id
  2592. );
  2593. pSetupStringTableGetExtraData(
  2594. OcPage->OcManager->ComponentStringTable,
  2595. Id,
  2596. &Oc,
  2597. sizeof(OPTIONAL_COMPONENT)
  2598. );
  2599. }
  2600. }
  2601. }
  2602. VOID
  2603. pOcPrintStates(
  2604. IN POCPAGE OcPage
  2605. )
  2606. {
  2607. OPTIONAL_COMPONENT Oc;
  2608. DWORD i;
  2609. for (i=0; i<OcPage->OcManager->TopLevelOcCount; i++) {
  2610. pOcPrintStatesWorker(
  2611. TEXT(" "),
  2612. OcPage,
  2613. OcPage->OcManager->TopLevelOcStringIds[i]
  2614. );
  2615. }
  2616. }
  2617. #endif