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.

2341 lines
73 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. #include <stdio.h>
  4. typedef struct _SETUP_PAGE {
  5. POC_MANAGER OcManager;
  6. SETUP_PAGE_CONTROLS ControlsInfo;
  7. HSPFILEQ FileQueue;
  8. PVOID QueueContext;
  9. UINT StepCount;
  10. BOOL ForceExternalProgressIndicator;
  11. PUINT ComponentTickCounts;
  12. PUINT ComponentMaxTickCounts;
  13. LONG CurrentTopLevelComponentIndex;
  14. BOOL AllowCancel;
  15. HWND hdlg;
  16. BOOL UserClickedCancel;
  17. DWORD RefCount;
  18. // Boolean to track NeedMedia requests. NeedMedia notification is sent always by Setupapi the first time it
  19. // tries to access a new media. We need to figure out if the media is actually inaccessible by checking if setupapi
  20. // called us a second time on the same media. The Boolean is checked and set in NeedMedia and cleared on an
  21. // SPFILENOTIFY_ENDCOPY or SPFILENOTIFY_STARTSUBQUEUE.
  22. BOOL SecondNeedMedia;
  23. } SETUP_PAGE, *PSETUP_PAGE;
  24. #define WMX_SETUP (WM_APP+4537)
  25. #define WMX_TICK (WM_APP+4538)
  26. #define OCSETUPSTATE_INIT 0
  27. #define OCSETUPSTATE_QUEUE 1
  28. #define OCSETUPSTATE_GETSTEP 2
  29. #define OCSETUPSTATE_DOIT 3
  30. #define OCSETUPSTATE_COPYDONE 4
  31. #define OCSETUPSTATE_DONE 100
  32. #define OCSETUPSTATE_COPYABORT 101
  33. typedef struct _GEN_THREAD_PARAMS {
  34. HWND hdlg;
  35. PSETUP_PAGE SetupPage;
  36. BOOL Async;
  37. } GEN_THREAD_PARAMS, *PGEN_THREAD_PARAMS;
  38. TCHAR g_LastFileCopied[MAX_PATH];
  39. #ifdef UNICODE
  40. HANDLE hSfp = NULL;
  41. #endif
  42. HANDLE WorkerThreadHandle = NULL;
  43. INT_PTR
  44. SetupPageDialogProc(
  45. IN HWND hdlg,
  46. IN UINT msg,
  47. IN WPARAM wParam,
  48. IN LPARAM lParam
  49. );
  50. BOOL
  51. pOcSetupInitialize(
  52. IN OUT PSETUP_PAGE SetupPage,
  53. IN HWND hdlg
  54. );
  55. VOID
  56. pOcSetupStartWorkerThread(
  57. IN OUT PSETUP_PAGE SetupPage,
  58. IN HWND hdlg,
  59. IN LPTHREAD_START_ROUTINE ThreadRoutine
  60. );
  61. DWORD
  62. pOcSetupQueue(
  63. IN PGEN_THREAD_PARAMS Params
  64. );
  65. UINT
  66. pOcSetupQueueWorker(
  67. IN PSETUP_PAGE SetupPage,
  68. IN LONG StringId,
  69. IN LONG TopLevelStringId
  70. );
  71. DWORD
  72. pOcSetupGetStepCount(
  73. IN PGEN_THREAD_PARAMS Params
  74. );
  75. UINT
  76. pOcSetupGetStepCountWorker(
  77. IN PSETUP_PAGE SetupPage,
  78. IN LONG StringId,
  79. IN LONG TopLevelStringId
  80. );
  81. DWORD
  82. pOcSetupDoIt(
  83. IN PGEN_THREAD_PARAMS Params
  84. );
  85. VOID
  86. pOcPreOrPostCommitProcessing(
  87. IN OUT PSETUP_PAGE SetupPage,
  88. IN BOOL PreCommit
  89. );
  90. VOID
  91. pOcTopLevelPreOrPostCommitProcessing(
  92. IN PSETUP_PAGE SetupPage,
  93. IN BOOL PreCommit
  94. );
  95. VOID
  96. pOcSetupDoItWorker(
  97. IN PSETUP_PAGE SetupPage,
  98. IN LONG StringId,
  99. IN LONG TopLevelStringId,
  100. IN BOOL PreCommit
  101. );
  102. BOOL
  103. pOcMarkUnprocessedStringCB(
  104. IN PVOID StringTable,
  105. IN LONG StringId,
  106. IN PCTSTR String,
  107. IN POPTIONAL_COMPONENT Oc,
  108. IN UINT OcSize,
  109. IN LPARAM Unused
  110. );
  111. VOID
  112. _pOcExternalProgressIndicator(
  113. IN PSETUP_PAGE SetupPage,
  114. IN BOOL ExternalIndicator,
  115. IN HWND hdlg
  116. );
  117. extern POC_MANAGER gLastOcManager;
  118. WNDPROC OldProgressProc;
  119. BOOL
  120. NewProgessProc(
  121. IN HWND hdlg,
  122. IN UINT msg,
  123. IN WPARAM wParam,
  124. IN LPARAM lParam
  125. )
  126. {
  127. switch (msg)
  128. {
  129. case PBM_DELTAPOS:
  130. case PBM_SETRANGE:
  131. case PBM_SETRANGE32:
  132. case PBM_STEPIT:
  133. case PBM_SETPOS:
  134. case PBM_SETSTEP:
  135. // If we have a callback, use it.
  136. if ((gLastOcManager) &&
  137. (gLastOcManager->Callbacks.BillboardProgressCallback))
  138. {
  139. gLastOcManager->Callbacks.BillboardProgressCallback(msg, wParam, lParam);
  140. }
  141. break;
  142. }
  143. return (BOOL)CallWindowProc(OldProgressProc,hdlg,msg,wParam,lParam);
  144. }
  145. HPROPSHEETPAGE
  146. OcCreateSetupPage(
  147. IN PVOID OcManagerContext,
  148. IN PSETUP_PAGE_CONTROLS ControlsInfo
  149. )
  150. /*++
  151. Routine Description:
  152. This routine creates the wizard page used for progress and installation
  153. completion.
  154. Arguments:
  155. OcManagerContext - supplies OC Manager context returned by OcInitialize.
  156. ControlsInfo - supplies information about the dialog template and
  157. control information.
  158. Return Value:
  159. Handle to property sheet page, or NULL if error (such as out of memory).
  160. --*/
  161. {
  162. PROPSHEETPAGE Page;
  163. HPROPSHEETPAGE PageHandle;
  164. PSETUP_PAGE SetupPage;
  165. TCHAR buffer[256];
  166. POC_MANAGER OcManager = (POC_MANAGER)OcManagerContext;
  167. SetupPage = pSetupMalloc(sizeof(SETUP_PAGE));
  168. if (!SetupPage) {
  169. return (NULL);
  170. }
  171. ZeroMemory(SetupPage,sizeof(SETUP_PAGE));
  172. SetupPage->OcManager = OcManagerContext;
  173. SetupPage->ControlsInfo = *ControlsInfo;
  174. SetupPage->CurrentTopLevelComponentIndex = -1;
  175. SetupPage->ForceExternalProgressIndicator = ControlsInfo->ForceExternalProgressIndicator;
  176. SetupPage->AllowCancel = ControlsInfo->AllowCancel;
  177. SetupPage->SecondNeedMedia = FALSE;
  178. InterlockedIncrement( &SetupPage->RefCount );
  179. SetupPage->ComponentTickCounts = pSetupMalloc(SetupPage->OcManager->TopLevelOcCount * sizeof(UINT));
  180. if (!SetupPage->ComponentTickCounts) {
  181. pSetupFree(SetupPage);
  182. return (NULL);
  183. }
  184. SetupPage->ComponentMaxTickCounts = pSetupMalloc(SetupPage->OcManager->TopLevelOcCount * sizeof(UINT));
  185. if (!SetupPage->ComponentMaxTickCounts) {
  186. pSetupFree(SetupPage->ComponentTickCounts);
  187. pSetupFree(SetupPage);
  188. return (NULL);
  189. }
  190. Page.dwSize = sizeof(PROPSHEETPAGE);
  191. Page.dwFlags = PSP_DEFAULT;
  192. Page.hInstance = ControlsInfo->TemplateModule;
  193. Page.pszTemplate = ControlsInfo->TemplateResource;
  194. Page.pfnDlgProc = SetupPageDialogProc;
  195. Page.lParam = (LPARAM)SetupPage;
  196. Page.pszHeaderTitle = NULL;
  197. Page.pszHeaderSubTitle = NULL;
  198. if (SetupPage->OcManager->SetupPageTitle[0]) {
  199. Page.dwFlags |= PSP_USETITLE;
  200. Page.pszTitle = SetupPage->OcManager->SetupPageTitle;
  201. }
  202. if (ControlsInfo->HeaderText) {
  203. if (LoadString(Page.hInstance,
  204. ControlsInfo->HeaderText,
  205. buffer,
  206. sizeof(buffer) / sizeof(TCHAR)))
  207. {
  208. Page.dwFlags |= PSP_USEHEADERTITLE;
  209. Page.pszHeaderTitle = _tcsdup(buffer);
  210. }
  211. }
  212. if (ControlsInfo->SubheaderText) {
  213. if (LoadString(Page.hInstance,
  214. ControlsInfo->SubheaderText,
  215. buffer,
  216. sizeof(buffer) / sizeof(TCHAR)))
  217. {
  218. Page.dwFlags |= PSP_USEHEADERSUBTITLE;
  219. Page.pszHeaderSubTitle = _tcsdup(buffer);
  220. }
  221. }
  222. PageHandle = CreatePropertySheetPage(&Page);
  223. if (!PageHandle) {
  224. pSetupFree(SetupPage->ComponentTickCounts);
  225. pSetupFree(SetupPage->ComponentMaxTickCounts);
  226. pSetupFree(SetupPage);
  227. if (Page.pszHeaderTitle) {
  228. free((LPTSTR)Page.pszHeaderTitle);
  229. }
  230. if (Page.pszHeaderSubTitle) {
  231. free((LPTSTR)Page.pszHeaderSubTitle);
  232. }
  233. } else {
  234. OcManager->OcSetupPage = (PVOID) SetupPage;
  235. }
  236. return (PageHandle);
  237. }
  238. VOID
  239. pOcFreeOcSetupPage(
  240. IN PVOID pSetupPage
  241. )
  242. /*++
  243. Routine Description:
  244. This routine frees the setup page when it's not needed anymore.
  245. The routine uses a ref-count, and the page is only freed when the
  246. refcount drops to zero.
  247. Arguments:
  248. SetupPage - pointer to structure to be freed
  249. Return Value:
  250. None.
  251. --*/
  252. {
  253. PSETUP_PAGE SetupPage = (PSETUP_PAGE)pSetupPage;
  254. sapiAssert( SetupPage != NULL );
  255. // TRACE(( TEXT("pOcFreeOcSetupPage: Refcount = %d\n"), SetupPage->RefCount ));
  256. if (!InterlockedDecrement( &SetupPage->RefCount )) {
  257. // TRACE(( TEXT("pOcFreeOcSetupPage: Refcount = 0, freeing SetupPage\n") ));
  258. if (SetupPage->QueueContext) {
  259. SetupTermDefaultQueueCallback(SetupPage->QueueContext);
  260. }
  261. if (SetupPage->FileQueue) {
  262. SetupCloseFileQueue(SetupPage->FileQueue);
  263. }
  264. pSetupFree(SetupPage->ComponentTickCounts);
  265. pSetupFree(SetupPage->ComponentMaxTickCounts);
  266. pSetupFree(SetupPage);
  267. }
  268. return;
  269. }
  270. BOOL
  271. pOcDisableCancel(
  272. IN HWND hdlg
  273. )
  274. /*++
  275. Routine Description:
  276. This routine disables cancelling of ocm setup.
  277. Arguments:
  278. hdlg - window handle to the ocm dialog
  279. Return Value:
  280. TRUE if we succeed, else FALSE
  281. --*/
  282. {
  283. HMENU hMenu;
  284. //
  285. // hide the cancel button
  286. //
  287. EnableWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),FALSE);
  288. ShowWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),SW_HIDE);
  289. if(hMenu = GetSystemMenu(GetParent(hdlg),FALSE)) {
  290. EnableMenuItem(hMenu,SC_CLOSE,MF_BYCOMMAND|MF_GRAYED);
  291. }
  292. return TRUE;
  293. }
  294. VOID
  295. PumpMessageQueue(
  296. VOID
  297. )
  298. {
  299. MSG msg;
  300. while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
  301. DispatchMessage(&msg);
  302. }
  303. }
  304. INT_PTR
  305. SetupPageDialogProc(
  306. IN HWND hdlg,
  307. IN UINT msg,
  308. IN WPARAM wParam,
  309. IN LPARAM lParam
  310. )
  311. {
  312. BOOL b;
  313. NMHDR *NotifyParams;
  314. PSETUP_PAGE SetupPage;
  315. DWORD Timeout;
  316. DWORD WaitProcStatus;
  317. BOOL KeepWaiting = TRUE;
  318. //
  319. // Get pointer to SetupPage data structure. If we haven't processed
  320. // WM_INITDIALOG yet, then this will be NULL, but it's still pretty
  321. // convenient to do this here once instead of all over the place below.
  322. //
  323. SetupPage = (PSETUP_PAGE)GetWindowLongPtr(hdlg,DWLP_USER);
  324. b = FALSE;
  325. switch (msg) {
  326. case WM_INITDIALOG:
  327. //
  328. // Get the pointer to the Setup Page context structure and stick it
  329. // in a window long.
  330. //
  331. SetWindowLongPtr(hdlg,DWLP_USER,((PROPSHEETPAGE *)lParam)->lParam);
  332. b = TRUE;
  333. //
  334. // eat any extra press button messages
  335. // this is necessary because netsetup is broken
  336. // it is posting an extra PSM_PRESSBUTTON message
  337. // to the wizard.
  338. //
  339. {
  340. MSG msg;
  341. HWND hwnd=GetParent(hdlg);
  342. while (PeekMessage(&msg,hwnd,PSM_PRESSBUTTON,PSM_PRESSBUTTON,PM_REMOVE)){}
  343. }
  344. break;
  345. case WM_SYSCOMMAND:
  346. if (!SetupPage->AllowCancel && wParam == SC_CLOSE) {
  347. return TRUE;
  348. }
  349. b = FALSE;
  350. break;
  351. case WM_DESTROY:
  352. PumpMessageQueue();
  353. if (WorkerThreadHandle) {
  354. BOOL Done = FALSE;
  355. do{
  356. switch (MsgWaitForMultipleObjects( 1, &WorkerThreadHandle, FALSE, 60*1000*20, QS_ALLINPUT)){
  357. case WAIT_OBJECT_0+1:
  358. //
  359. // Messages in the queue.
  360. //
  361. PumpMessageQueue();
  362. break;
  363. case WAIT_TIMEOUT:
  364. case WAIT_OBJECT_0:
  365. default:
  366. Done = TRUE;
  367. break;
  368. }
  369. }while( !Done );
  370. CloseHandle( WorkerThreadHandle );
  371. }
  372. if (SetupPage) {
  373. pOcFreeOcSetupPage( SetupPage );
  374. }
  375. SetWindowLongPtr(hdlg,DWLP_USER,(LPARAM)NULL);
  376. break;
  377. case WM_NOTIFY:
  378. NotifyParams = (NMHDR *)lParam;
  379. switch (NotifyParams->code) {
  380. case PSN_SETACTIVE:
  381. #ifdef UNICODE
  382. if (SetupPage->OcManager->Callbacks.SetupPerfData)
  383. SetupPage->OcManager->Callbacks.SetupPerfData(TEXT(__FILE__),__LINE__,L"BEGIN_SECTION",L"OCSetup");
  384. #endif
  385. // activate the cancel button accordingly
  386. if (SetupPage->AllowCancel) {
  387. ShowWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),SW_SHOW);
  388. EnableWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),TRUE);
  389. } else {
  390. ShowWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),SW_HIDE);
  391. EnableWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),FALSE);
  392. }
  393. if (SetupPage->OcManager->Callbacks.ShowHideWizardPage)
  394. {
  395. // If we have a callback, hide the wizard.
  396. SetupPage->OcManager->Callbacks.ShowHideWizardPage(FALSE);
  397. }
  398. OldProgressProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hdlg,SetupPage->ControlsInfo.ProgressBar),
  399. GWLP_WNDPROC,
  400. (LONG_PTR)NewProgessProc);
  401. //
  402. // Post a message that causes us to start the installation process.
  403. //
  404. PostMessage(hdlg,WMX_SETUP,OCSETUPSTATE_INIT,0);
  405. //
  406. // Accept activation.
  407. //
  408. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,0);
  409. b = TRUE;
  410. break;
  411. case PSN_KILLACTIVE:
  412. //
  413. // Restore the wizard's cancel button if we removed it earlier
  414. //
  415. if (!SetupPage->AllowCancel) {
  416. ShowWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),SW_SHOW);
  417. EnableWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),TRUE);
  418. }
  419. //
  420. // Accept deactivation.
  421. //
  422. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,0);
  423. b = TRUE;
  424. break;
  425. case PSN_QUERYCANCEL:
  426. if (!SetupPage->AllowCancel) {
  427. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,TRUE);
  428. return(TRUE);
  429. }
  430. if ( (SetupPage->OcManager->InternalFlags & OCMFLAG_FILEABORT )
  431. || (OcHelperConfirmCancel(hdlg) )){
  432. b = TRUE;
  433. SetupPage->OcManager->InternalFlags |= OCMFLAG_USERCANCELED;
  434. SetupPage->UserClickedCancel = TRUE;
  435. }
  436. SetWindowLongPtr(hdlg,DWLP_MSGRESULT,!b);
  437. b = TRUE;
  438. break;
  439. }
  440. break;
  441. case WMX_SETUP:
  442. switch (wParam) {
  443. case OCSETUPSTATE_INIT:
  444. //
  445. // Initialize.
  446. //
  447. if (SetupPage->ForceExternalProgressIndicator) {
  448. _pOcExternalProgressIndicator(SetupPage,TRUE,hdlg);
  449. }
  450. PropSheet_SetWizButtons(GetParent(hdlg),0);
  451. //
  452. // If this a remove all, disable the cancel button early
  453. //
  454. if ((SetupPage->OcManager->SetupMode & SETUPMODE_PRIVATE_MASK) == SETUPMODE_REMOVEALL) {
  455. if (!SetupPage->AllowCancel) {
  456. EnableWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),FALSE);
  457. ShowWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),SW_HIDE);
  458. }
  459. }
  460. if (pOcSetupInitialize(SetupPage,hdlg)) {
  461. PostMessage(hdlg,WMX_SETUP,OCSETUPSTATE_QUEUE,0);
  462. } else {
  463. PostMessage(hdlg,WMX_SETUP,OCSETUPSTATE_COPYABORT,0);
  464. }
  465. break;
  466. case OCSETUPSTATE_QUEUE:
  467. //
  468. // Queue files for installation.
  469. //
  470. pOcSetupStartWorkerThread(SetupPage,hdlg,pOcSetupQueue);
  471. break;
  472. case OCSETUPSTATE_GETSTEP:
  473. //
  474. // Figure out step counts.
  475. //
  476. pOcSetupStartWorkerThread(SetupPage,hdlg,pOcSetupGetStepCount);
  477. break;
  478. case OCSETUPSTATE_DOIT:
  479. //
  480. // Quick init of the gas guage here, because the file queue could be
  481. // empty, in which case we never get WMX_TICK with wParam=0.
  482. //
  483. SendDlgItemMessage(
  484. hdlg,
  485. SetupPage->ControlsInfo.ProgressBar,
  486. PBM_SETRANGE,
  487. 0,
  488. MAKELPARAM(0,SetupPage->StepCount)
  489. );
  490. SendDlgItemMessage(
  491. hdlg,
  492. SetupPage->ControlsInfo.ProgressBar,
  493. PBM_SETPOS,
  494. 0,
  495. 0
  496. );
  497. SetCursor(LoadCursor(NULL,IDC_ARROW));
  498. //
  499. // Commit the file queue and let the OCs install themselves.
  500. //
  501. pOcSetupStartWorkerThread(SetupPage,hdlg,pOcSetupDoIt);
  502. break;
  503. //
  504. // Unrecoverable error in copyfile phase, abort the setup
  505. //
  506. case OCSETUPSTATE_COPYABORT:
  507. SetupPage->OcManager->InternalFlags |= OCMFLAG_FILEABORT;
  508. if (SetupPage->AllowCancel
  509. && SetupPage->OcManager->SetupData.OperationFlags & SETUPOP_STANDALONE) {
  510. PropSheet_PressButton(GetParent(hdlg),PSBTN_CANCEL);
  511. } else {
  512. PropSheet_PressButton(GetParent(hdlg),PSBTN_NEXT);
  513. }
  514. break;
  515. case OCSETUPSTATE_COPYDONE:
  516. //
  517. // Get rid of the wizard's cancel button
  518. //
  519. //
  520. // AndrewR -- we've already committed the file queue
  521. // at this point, so we should not allow the user to cancel
  522. // (since:
  523. // a) in an uninstall scenario the file state and
  524. // configuration state will be out of sync
  525. // b) we don't call all of the OC components to let them know
  526. // about the cancel event, and we don't want only some of the
  527. // components to get a complete installation callback
  528. //
  529. //if(!SetupPage->AllowCancel) {
  530. SetupPage->AllowCancel = FALSE;
  531. pOcDisableCancel(hdlg);
  532. // }
  533. break;
  534. case OCSETUPSTATE_DONE:
  535. //
  536. // Done. Advance to next page in wizard.
  537. //
  538. PropSheet_SetWizButtons(GetParent(hdlg),PSWIZB_NEXT);
  539. PropSheet_PressButton(GetParent(hdlg),PSBTN_NEXT);
  540. #ifdef UNICODE
  541. if (SetupPage->OcManager->Callbacks.SetupPerfData)
  542. SetupPage->OcManager->Callbacks.SetupPerfData(TEXT(__FILE__),__LINE__,L"END_SECTION",L"OCSetup");
  543. #endif
  544. // un-subclass the progress bar. just in case
  545. SetWindowLongPtr(GetDlgItem(hdlg,SetupPage->ControlsInfo.ProgressBar),
  546. GWLP_WNDPROC,
  547. (LONG_PTR)OldProgressProc);
  548. //
  549. // Clear user canceled flag,
  550. //
  551. SetupPage->OcManager->InternalFlags &= ~ OCMFLAG_USERCANCELED;
  552. break;
  553. }
  554. b = TRUE;
  555. break;
  556. case WMX_TICK:
  557. switch (wParam) {
  558. case 0:
  559. //
  560. // The setup API queue commit routine is telling us how many
  561. // files are to be copied. We do nothing in this case, as we
  562. // set the progress guage manually so that we also count
  563. // delete operations in our progress guage.
  564. //
  565. break;
  566. case 1:
  567. //
  568. // File copied.
  569. //
  570. SendDlgItemMessage(hdlg,SetupPage->ControlsInfo.ProgressBar,PBM_DELTAPOS,1,0);
  571. break;
  572. case 10:
  573. //
  574. // We got our private message telling us how many files are
  575. // to be processed. see comments above in the 0 case.
  576. //
  577. SendDlgItemMessage(
  578. hdlg,
  579. SetupPage->ControlsInfo.ProgressBar,
  580. PBM_SETRANGE,
  581. 0,
  582. MAKELPARAM(0,lParam)
  583. );
  584. break;
  585. case 500:
  586. //
  587. // Incoming tick request from component dll. Don't allow a broken component dll
  588. // to tick the gauge more than it said it wanted to.
  589. //
  590. if ((SetupPage->CurrentTopLevelComponentIndex != -1)
  591. && (SetupPage->ComponentTickCounts[SetupPage->CurrentTopLevelComponentIndex]
  592. < SetupPage->ComponentMaxTickCounts[SetupPage->CurrentTopLevelComponentIndex])) {
  593. SetupPage->ComponentTickCounts[SetupPage->CurrentTopLevelComponentIndex]++;
  594. SendDlgItemMessage(hdlg,SetupPage->ControlsInfo.ProgressBar,PBM_DELTAPOS,1,0);
  595. }
  596. break;
  597. }
  598. b = TRUE;
  599. break;
  600. }
  601. return (b);
  602. }
  603. VOID
  604. pOcTickSetupGauge(
  605. IN POC_MANAGER OcManager
  606. )
  607. /*++
  608. Routine Description:
  609. The tick gauge OC helper/callback routine calls this routine.
  610. Arguments:
  611. OcManager - supplies OC Manager context.
  612. Return Value:
  613. None.
  614. --*/
  615. {
  616. //
  617. // The ProgressTextWindow is non-NULL if we are in
  618. // the installation-completion phase.
  619. //
  620. if (OcManager->ProgressTextWindow) {
  621. SendMessage(GetParent(OcManager->ProgressTextWindow),WMX_TICK,500,0);
  622. }
  623. }
  624. BOOL
  625. pOcSetupInitialize(
  626. IN OUT PSETUP_PAGE SetupPage,
  627. IN HWND hdlg
  628. )
  629. {
  630. TCHAR Text[128];
  631. LoadString(MyModuleHandle,IDS_INITIALIZING,Text,sizeof(Text)/sizeof(TCHAR));
  632. SetDlgItemText(hdlg,SetupPage->ControlsInfo.ProgressText,Text);
  633. // If, update the text on the billboard for the progress bar.
  634. if (SetupPage->OcManager->Callbacks.BillBoardSetProgressText)
  635. {
  636. SetupPage->OcManager->Callbacks.BillBoardSetProgressText(Text);
  637. }
  638. //
  639. // Create a setup file queue.
  640. //
  641. SetupPage->FileQueue = SetupOpenFileQueue();
  642. if (SetupPage->FileQueue == INVALID_HANDLE_VALUE) {
  643. _LogError(SetupPage->OcManager,OcErrLevFatal,MSG_OC_OOM);
  644. SetupPage->FileQueue = NULL;
  645. return (FALSE);
  646. }
  647. SetupPage->QueueContext = SetupInitDefaultQueueCallbackEx(hdlg,hdlg,WMX_TICK,0,0);
  648. if (!SetupPage->QueueContext) {
  649. _LogError(SetupPage->OcManager,OcErrLevFatal,MSG_OC_OOM);
  650. SetupCloseFileQueue(SetupPage->FileQueue);
  651. SetupPage->FileQueue = NULL;
  652. return (FALSE);
  653. }
  654. return (TRUE);
  655. }
  656. VOID
  657. pOcSetupStartWorkerThread(
  658. IN OUT PSETUP_PAGE SetupPage,
  659. IN HWND hdlg,
  660. IN LPTHREAD_START_ROUTINE ThreadRoutine
  661. )
  662. {
  663. PGEN_THREAD_PARAMS pParams;
  664. GEN_THREAD_PARAMS Params;
  665. HANDLE h;
  666. DWORD id;
  667. if (WorkerThreadHandle) {
  668. CloseHandle( WorkerThreadHandle );
  669. WorkerThreadHandle = NULL;
  670. }
  671. if (pParams = pSetupMalloc(sizeof(GEN_THREAD_PARAMS))) {
  672. pParams->SetupPage = SetupPage;
  673. pParams->SetupPage->hdlg = hdlg;
  674. pParams->hdlg = hdlg;
  675. pParams->Async = TRUE;
  676. h = CreateThread(NULL,0,ThreadRoutine,pParams,0,&id);
  677. if (!h) {
  678. pSetupFree(pParams);
  679. } else {
  680. WorkerThreadHandle = h;
  681. }
  682. } else {
  683. h = NULL;
  684. }
  685. if (!h) {
  686. //
  687. // Just try it synchronously.
  688. //
  689. Params.SetupPage = SetupPage;
  690. Params.hdlg = hdlg;
  691. Params.Async = FALSE;
  692. ThreadRoutine(&Params);
  693. }
  694. }
  695. //
  696. // a debugging routine that makes it easy to cancel at any phase of setup
  697. //
  698. /*
  699. VOID CancelRoutine(
  700. VOID
  701. )
  702. {
  703. static int i = 0;
  704. TCHAR dbg[100];
  705. wsprintf( dbg, TEXT("cancel routine iteration number %i \n"), i);
  706. OutputDebugString( dbg );
  707. OutputDebugString( TEXT(" waiting 5 seconds for cancel ... \n" ));
  708. Sleep( 1000 * 5 );
  709. OutputDebugString( TEXT(" done waiting for cancel ... \n" ));
  710. i++;
  711. }
  712. */
  713. BOOL
  714. CheckForQueueCancel(
  715. PSETUP_PAGE SetupPage
  716. )
  717. {
  718. BOOL bRet;
  719. //CancelRoutine();
  720. bRet = SetupPage->UserClickedCancel;
  721. return (bRet);
  722. }
  723. DWORD
  724. pOcSetupQueue(
  725. IN PGEN_THREAD_PARAMS Params
  726. )
  727. {
  728. UINT Err;
  729. unsigned i,child;
  730. OPTIONAL_COMPONENT Oc;
  731. TCHAR Text[128];
  732. DWORD RetVal;
  733. InterlockedIncrement( &Params->SetupPage->RefCount );
  734. LoadString(MyModuleHandle,IDS_BUILDINGCOPYLIST,Text,sizeof(Text)/sizeof(TCHAR));
  735. #ifdef UNICODE
  736. if (Params->SetupPage->OcManager->Callbacks.SetupPerfData)
  737. Params->SetupPage->OcManager->Callbacks.SetupPerfData(TEXT(__FILE__),__LINE__,L"BEGIN_SECTION",Text);
  738. // If, update the text on the billboard for the progress bar.
  739. if (Params->SetupPage->OcManager->Callbacks.BillBoardSetProgressText)
  740. {
  741. Params->SetupPage->OcManager->Callbacks.BillBoardSetProgressText(Text);
  742. }
  743. #endif
  744. SetDlgItemText(Params->hdlg,Params->SetupPage->ControlsInfo.ProgressText,Text);
  745. if (CheckForQueueCancel(Params->SetupPage)) {
  746. RetVal = NO_ERROR;
  747. goto exit;
  748. }
  749. //
  750. // Handle each component.
  751. //
  752. for (i=0; i<Params->SetupPage->OcManager->TopLevelOcCount; i++) {
  753. pSetupStringTableGetExtraData(
  754. Params->SetupPage->OcManager->ComponentStringTable,
  755. Params->SetupPage->OcManager->TopLevelOcStringIds[i],
  756. &Oc,
  757. sizeof(OPTIONAL_COMPONENT)
  758. );
  759. //
  760. // Call the component dll once for the entire component.
  761. //
  762. Err = OcInterfaceQueueFileOps(
  763. Params->SetupPage->OcManager,
  764. Params->SetupPage->OcManager->TopLevelOcStringIds[i],
  765. NULL,
  766. Params->SetupPage->FileQueue
  767. );
  768. if (Err != NO_ERROR) {
  769. //
  770. // Notify user and continue.
  771. //
  772. _LogError(
  773. Params->SetupPage->OcManager,
  774. OcErrLevError,
  775. MSG_OC_CANT_QUEUE_FILES,
  776. Oc.Description,
  777. Err
  778. );
  779. }
  780. if (CheckForQueueCancel(Params->SetupPage)) {
  781. RetVal = NO_ERROR;
  782. goto exit;
  783. }
  784. //
  785. // Process each top level parent item in the tree
  786. //
  787. for (child=0; child<Params->SetupPage->OcManager->TopLevelParentOcCount; child++) {
  788. Err = pOcSetupQueueWorker(
  789. Params->SetupPage,
  790. Params->SetupPage->OcManager->TopLevelParentOcStringIds[child],
  791. Params->SetupPage->OcManager->TopLevelOcStringIds[i]
  792. );
  793. if (Err != NO_ERROR) {
  794. //
  795. // Notification is handled in the worker routine so nothing to do here.
  796. //
  797. }
  798. }
  799. if (CheckForQueueCancel(Params->SetupPage)) {
  800. RetVal = NO_ERROR;
  801. goto exit;
  802. }
  803. }
  804. if (CheckForQueueCancel(Params->SetupPage)) {
  805. RetVal = NO_ERROR;
  806. goto exit;
  807. }
  808. PostMessage(Params->hdlg,WMX_SETUP,OCSETUPSTATE_GETSTEP,0);
  809. exit:
  810. #ifdef UNICODE
  811. if (Params->SetupPage->OcManager->Callbacks.SetupPerfData)
  812. Params->SetupPage->OcManager->Callbacks.SetupPerfData(TEXT(__FILE__),__LINE__,L"END_SECTION",Text);
  813. #endif
  814. pOcFreeOcSetupPage( Params->SetupPage );
  815. if (Params->Async) {
  816. pSetupFree(Params);
  817. }
  818. return (RetVal);
  819. }
  820. UINT
  821. pOcSetupQueueWorker(
  822. IN PSETUP_PAGE SetupPage,
  823. IN LONG StringId,
  824. IN LONG TopLevelStringId
  825. )
  826. {
  827. OPTIONAL_COMPONENT Oc;
  828. UINT Err;
  829. LONG Id;
  830. //
  831. // Fetch extra data for this subcomponent.
  832. //
  833. pSetupStringTableGetExtraData(
  834. SetupPage->OcManager->ComponentStringTable,
  835. StringId,
  836. &Oc,
  837. sizeof(OPTIONAL_COMPONENT)
  838. );
  839. //
  840. // If it's a child, call the component dll.
  841. // If it's a parent, then spin through its children.
  842. //
  843. if (Oc.FirstChildStringId == -1) {
  844. if (TopLevelStringId == pOcGetTopLevelComponent(SetupPage->OcManager,StringId)) {
  845. Err = OcInterfaceQueueFileOps(
  846. SetupPage->OcManager,
  847. pOcGetTopLevelComponent(SetupPage->OcManager,StringId),
  848. pSetupStringTableStringFromId(SetupPage->OcManager->ComponentStringTable,StringId),
  849. SetupPage->FileQueue
  850. );
  851. if (Err != NO_ERROR) {
  852. //
  853. // Notify user and continue.
  854. //
  855. _LogError(
  856. SetupPage->OcManager,
  857. OcErrLevError,
  858. MSG_OC_CANT_QUEUE_FILES,
  859. Oc.Description,
  860. Err
  861. );
  862. }
  863. }
  864. } else {
  865. for (Id = Oc.FirstChildStringId; Id != -1; Id = Oc.NextSiblingStringId) {
  866. Err = pOcSetupQueueWorker(SetupPage,Id,TopLevelStringId);
  867. if (Err != NO_ERROR) {
  868. //
  869. // Notification is handled in the worker routine so nothing to do here.
  870. //
  871. }
  872. pSetupStringTableGetExtraData(
  873. SetupPage->OcManager->ComponentStringTable,
  874. Id,
  875. &Oc,
  876. sizeof(OPTIONAL_COMPONENT)
  877. );
  878. }
  879. }
  880. return (NO_ERROR);
  881. }
  882. DWORD
  883. pOcSetupGetStepCount(
  884. IN PGEN_THREAD_PARAMS Params
  885. )
  886. {
  887. UINT Err;
  888. unsigned i,child;
  889. OPTIONAL_COMPONENT Oc;
  890. UINT StepCount;
  891. TCHAR Text[128];
  892. UINT Count;
  893. InterlockedIncrement( &Params->SetupPage->RefCount );
  894. LoadString(MyModuleHandle,IDS_PREPARING,Text,sizeof(Text)/sizeof(TCHAR));
  895. SetDlgItemText(Params->hdlg,Params->SetupPage->ControlsInfo.ProgressText,Text);
  896. #ifdef UNICODE
  897. // If, update the text on the billboard for the progress bar.
  898. if (Params->SetupPage->OcManager->Callbacks.BillBoardSetProgressText)
  899. {
  900. Params->SetupPage->OcManager->Callbacks.BillBoardSetProgressText(Text);
  901. }
  902. if (Params->SetupPage->OcManager->Callbacks.SetupPerfData)
  903. Params->SetupPage->OcManager->Callbacks.SetupPerfData(TEXT(__FILE__),__LINE__,L"BEGIN_SECTION",Text);
  904. #endif
  905. Params->SetupPage->StepCount = 0;
  906. //
  907. // Handle each component.
  908. //
  909. for (i=0; i<Params->SetupPage->OcManager->TopLevelOcCount; i++) {
  910. //
  911. // Call the component dll once for the entire component.
  912. // Ignore any error. Later we call per-subcomponent and we'll
  913. // assume that any component that gives us an error has 1 step.
  914. //
  915. Err = OcInterfaceQueryStepCount(
  916. Params->SetupPage->OcManager,
  917. Params->SetupPage->OcManager->TopLevelOcStringIds[i],
  918. NULL,
  919. &Count
  920. );
  921. StepCount = ((Err == NO_ERROR) ? Count : 0);
  922. //
  923. // For each top level parent item in the tree find all the children
  924. // that belong to this component
  925. //
  926. for (child=0; child<Params->SetupPage->OcManager->TopLevelParentOcCount; child++) {
  927. //
  928. // Now call the component dll for each child subcomponent.
  929. //
  930. StepCount += pOcSetupGetStepCountWorker(
  931. Params->SetupPage,
  932. Params->SetupPage->OcManager->TopLevelParentOcStringIds[child],
  933. Params->SetupPage->OcManager->TopLevelOcStringIds[i]
  934. );
  935. }
  936. if (!StepCount) {
  937. //
  938. // Make sure each component has at least one step.
  939. //
  940. StepCount = 1;
  941. }
  942. Params->SetupPage->StepCount += StepCount;
  943. Params->SetupPage->ComponentTickCounts[i] = 0;
  944. Params->SetupPage->ComponentMaxTickCounts[i] = StepCount;
  945. }
  946. if (CheckForQueueCancel(Params->SetupPage)) {
  947. goto exit;
  948. }
  949. PostMessage(Params->hdlg,WMX_SETUP,OCSETUPSTATE_DOIT,0);
  950. exit:
  951. #ifdef UNICODE
  952. if (Params->SetupPage->OcManager->Callbacks.SetupPerfData)
  953. Params->SetupPage->OcManager->Callbacks.SetupPerfData(TEXT(__FILE__),__LINE__,L"END_SECTION",Text);
  954. #endif
  955. pOcFreeOcSetupPage( Params->SetupPage );
  956. if (Params->Async) {
  957. pSetupFree(Params);
  958. }
  959. return (0);
  960. }
  961. UINT
  962. pOcSetupGetStepCountWorker(
  963. IN PSETUP_PAGE SetupPage,
  964. IN LONG StringId,
  965. IN LONG TopLevelStringId
  966. )
  967. {
  968. OPTIONAL_COMPONENT Oc;
  969. UINT Err;
  970. LONG Id;
  971. UINT Count;
  972. UINT TotalCount;
  973. TotalCount = 0;
  974. Count = 0;
  975. //
  976. // Fetch extra data for this subcomponent.
  977. //
  978. pSetupStringTableGetExtraData(
  979. SetupPage->OcManager->ComponentStringTable,
  980. StringId,
  981. &Oc,
  982. sizeof(OPTIONAL_COMPONENT)
  983. );
  984. //
  985. // If it's a child, call the component dll.
  986. // If it's a parent, then spin through its children.
  987. //
  988. if (Oc.FirstChildStringId == -1) {
  989. //
  990. // Only call the leaf node if the top level component matches
  991. //
  992. if (TopLevelStringId == pOcGetTopLevelComponent(SetupPage->OcManager,StringId)) {
  993. Err = OcInterfaceQueryStepCount(
  994. SetupPage->OcManager,
  995. pOcGetTopLevelComponent(SetupPage->OcManager,StringId),
  996. pSetupStringTableStringFromId(SetupPage->OcManager->ComponentStringTable,StringId),
  997. &Count
  998. );
  999. if (Err == NO_ERROR) {
  1000. TotalCount = Count;
  1001. }
  1002. }
  1003. } else {
  1004. for (Id = Oc.FirstChildStringId; Id != -1; Id = Oc.NextSiblingStringId) {
  1005. TotalCount += pOcSetupGetStepCountWorker(SetupPage,Id,TopLevelStringId);
  1006. pSetupStringTableGetExtraData(
  1007. SetupPage->OcManager->ComponentStringTable,
  1008. Id,
  1009. &Oc,
  1010. sizeof(OPTIONAL_COMPONENT)
  1011. );
  1012. }
  1013. }
  1014. return (TotalCount);
  1015. }
  1016. BOOL
  1017. pOcSetRenamesFlag(
  1018. IN POC_MANAGER OcManager
  1019. )
  1020. {
  1021. HKEY hKey;
  1022. long rslt = ERROR_SUCCESS;
  1023. #ifdef UNICODE
  1024. rslt = RegOpenKeyEx(
  1025. HKEY_LOCAL_MACHINE,
  1026. TEXT("System\\CurrentControlSet\\Control\\Session Manager"),
  1027. 0,
  1028. KEY_SET_VALUE,
  1029. &hKey);
  1030. if (rslt == ERROR_SUCCESS) {
  1031. DWORD Value = 1;
  1032. rslt = RegSetValueEx(
  1033. hKey,
  1034. OC_ALLOWRENAME,
  1035. 0,
  1036. REG_DWORD,
  1037. (LPBYTE)&Value,
  1038. sizeof(DWORD));
  1039. RegCloseKey(hKey);
  1040. if (rslt != ERROR_SUCCESS) {
  1041. TRACE(( TEXT("couldn't RegSetValueEx, ec = %d\n"), rslt ));
  1042. }
  1043. } else {
  1044. TRACE(( TEXT("couldn't RegOpenKeyEx, ec = %d\n"), rslt ));
  1045. }
  1046. #endif
  1047. return (rslt == ERROR_SUCCESS);
  1048. }
  1049. BOOL
  1050. pOcAttemptQueueAbort(
  1051. IN UINT Notification,
  1052. IN PUINT rc
  1053. )
  1054. {
  1055. //
  1056. // user has asked to abort installation. We need to hand this request to
  1057. // setupapi, but setupapi only handles this request from certain
  1058. // notifications
  1059. //
  1060. BOOL bHandled = FALSE;
  1061. switch (Notification) {
  1062. case SPFILENOTIFY_STARTQUEUE:
  1063. case SPFILENOTIFY_STARTSUBQUEUE:
  1064. SetLastError(ERROR_CANCELLED);
  1065. *rc = 0;
  1066. bHandled = TRUE;
  1067. break;
  1068. case SPFILENOTIFY_STARTDELETE:
  1069. case SPFILENOTIFY_STARTBACKUP:
  1070. case SPFILENOTIFY_STARTRENAME:
  1071. case SPFILENOTIFY_STARTCOPY:
  1072. case SPFILENOTIFY_NEEDMEDIA:
  1073. case SPFILENOTIFY_COPYERROR:
  1074. case SPFILENOTIFY_DELETEERROR:
  1075. case SPFILENOTIFY_RENAMEERROR:
  1076. case SPFILENOTIFY_BACKUPERROR:
  1077. SetLastError(ERROR_CANCELLED);
  1078. *rc = FILEOP_ABORT;
  1079. bHandled = TRUE;
  1080. break;
  1081. case SPFILENOTIFY_FILEEXTRACTED:
  1082. case SPFILENOTIFY_NEEDNEWCABINET:
  1083. case SPFILENOTIFY_QUEUESCAN:
  1084. SetLastError(ERROR_CANCELLED);
  1085. *rc = ERROR_CANCELLED;
  1086. bHandled = TRUE;
  1087. break;
  1088. };
  1089. return (bHandled);
  1090. }
  1091. UINT
  1092. OcManagerQueueCallback1(
  1093. IN PVOID Context,
  1094. IN UINT Notification,
  1095. IN UINT_PTR Param1,
  1096. IN UINT_PTR Param2
  1097. )
  1098. {
  1099. PSETUP_PAGE SetupPage = Context;
  1100. UINT i;
  1101. BOOL b;
  1102. TCHAR Text[MAX_PATH*2];
  1103. PFILEPATHS pFile = (PFILEPATHS) Param1;
  1104. PSOURCE_MEDIA sm = (PSOURCE_MEDIA)Param1;
  1105. static BOOL UserClickedCancel;
  1106. UINT rc = 0;
  1107. UINT retval;
  1108. //
  1109. // We handle the user cancelling at the beginning of the queue callback.
  1110. // If the user has cancelled then we don't execute any code, we just return
  1111. // until we get a callback that allows us to cancel.
  1112. //
  1113. // There is a window in this code where the user might cancel after we
  1114. // check for cancelling but before the queue callback code executes. If we fall into
  1115. // the WM_DESTROY block in our window proc when this occurs, we cannot send any more
  1116. // messages to our window. Use PostMessage below to guard against that.
  1117. top:
  1118. if (UserClickedCancel) {
  1119. pOcAttemptQueueAbort(Notification,&rc);
  1120. return (rc);
  1121. }
  1122. if (SetupPage->UserClickedCancel) {
  1123. UserClickedCancel = TRUE;
  1124. }
  1125. if (UserClickedCancel) {
  1126. goto top;
  1127. }
  1128. switch (Notification) {
  1129. case SPFILENOTIFY_STARTSUBQUEUE:
  1130. //
  1131. // Tell the user what's going on.
  1132. //
  1133. switch (Param1) {
  1134. case FILEOP_DELETE:
  1135. i = IDS_DELETING;
  1136. break;
  1137. case FILEOP_RENAME:
  1138. i = IDS_RENAME;
  1139. break;
  1140. case FILEOP_COPY:
  1141. i = IDS_COPYING;
  1142. break;
  1143. default:
  1144. i = (UINT)(-1);
  1145. break;
  1146. }
  1147. if (i != (UINT)(-1)) {
  1148. LoadString(MyModuleHandle,i,Text,sizeof(Text)/sizeof(TCHAR));
  1149. SetDlgItemText(SetupPage->hdlg,SetupPage->ControlsInfo.ProgressText,Text);
  1150. // If, update the text on the billboard for the progress bar.
  1151. if (SetupPage->OcManager->Callbacks.BillBoardSetProgressText)
  1152. {
  1153. SetupPage->OcManager->Callbacks.BillBoardSetProgressText(Text);
  1154. }
  1155. }
  1156. //Reset SecondNeedMedia as we are about to begin copying for a particular queue
  1157. SetupPage->SecondNeedMedia = FALSE;
  1158. break;
  1159. case SPFILENOTIFY_STARTCOPY:
  1160. lstrcpy( g_LastFileCopied, pFile->Target );
  1161. #ifdef UNICODE
  1162. // fall through...
  1163. case SPFILENOTIFY_STARTDELETE:
  1164. case SPFILENOTIFY_STARTRENAME:
  1165. if ((SetupPage->OcManager->SetupData.OperationFlags & SETUPOP_STANDALONE)) {
  1166. if (!hSfp) {
  1167. hSfp = SfcConnectToServer( NULL );
  1168. }
  1169. if (hSfp) {
  1170. if (SfcIsFileProtected(hSfp,pFile->Target)) {
  1171. SfcFileException(
  1172. hSfp,
  1173. (PWSTR) pFile->Target,
  1174. SFC_ACTION_REMOVED
  1175. );
  1176. }
  1177. }
  1178. }
  1179. #endif
  1180. break;
  1181. case SPFILENOTIFY_ENDCOPY:
  1182. if (pFile->Win32Error == NO_ERROR) {
  1183. _LogError(SetupPage->OcManager,
  1184. OcErrLevInfo,
  1185. MSG_OC_LOG_FILE_COPIED,
  1186. pFile->Source,
  1187. pFile->Target);
  1188. } else {
  1189. TRACE(( TEXT("OC:OcManagerQueueCallback Copy Error: %s --> %s (%d)\n"),
  1190. pFile->Source,
  1191. pFile->Target,
  1192. pFile->Win32Error));
  1193. _LogError(SetupPage->OcManager,
  1194. OcErrLevInfo,
  1195. MSG_OC_LOG_FILE_COPY_FAILED,
  1196. pFile->Source,
  1197. pFile->Target,
  1198. pFile->Win32Error);
  1199. }
  1200. //Reset SecondNeedMedia as we are at the end of copying files for this media
  1201. SetupPage->SecondNeedMedia = FALSE;
  1202. break;
  1203. case SPFILENOTIFY_ENDDELETE: // fall through
  1204. case SPFILENOTIFY_ENDRENAME:
  1205. case SPFILENOTIFY_ENDBACKUP:
  1206. //
  1207. // tick the progress gauge manually since setupapi doesn't do it
  1208. // for us.
  1209. //
  1210. SendMessage(SetupPage->hdlg,WMX_TICK,1,0);
  1211. break;
  1212. case SPFILENOTIFY_DELETEERROR: // 0x00000007
  1213. TRACE(( TEXT("OC:OcManagerQueueCallback Delete Error: %s (%d)\n"),
  1214. pFile->Target,
  1215. pFile->Win32Error));
  1216. break;
  1217. case SPFILENOTIFY_RENAMEERROR: // 0x0000000a
  1218. TRACE(( TEXT("OC:OcManagerQueueCallback Rename Error: %s (%d)\n"),
  1219. pFile->Target,
  1220. pFile->Win32Error));
  1221. break;
  1222. case SPFILENOTIFY_COPYERROR: // 0x0000000d
  1223. TRACE(( TEXT("OC:OcManagerQueueCallback Copy Error: %s (%d)\n"),
  1224. pFile->Target,
  1225. pFile->Win32Error));
  1226. break;
  1227. case SPFILENOTIFY_NEEDMEDIA:
  1228. TRACE(( TEXT("OC:OcManagerQueueCallback Need Media: %s - %s (%s)\n"),
  1229. sm->SourcePath,
  1230. sm->SourceFile,
  1231. sm->Tagfile));
  1232. if (gLastOcManager && (gLastOcManager->InternalFlags & OCMFLAG_RUNQUIET)) {
  1233. // Check if this is the second time we are getting a
  1234. if (TRUE == SetupPage->SecondNeedMedia) {
  1235. SetupPage->SecondNeedMedia = FALSE;
  1236. return (FILEOP_ABORT);
  1237. }else{
  1238. SetupPage->SecondNeedMedia = TRUE;
  1239. return (FILEOP_DOIT);
  1240. }
  1241. }
  1242. break;
  1243. case SPFILENOTIFY_FILEOPDELAYED:
  1244. TRACE(( TEXT("OC:OcManagerQueueCallback FileOpDelayed: %s\n"), pFile->Target ));
  1245. //
  1246. // We want to remember that there was at least one file
  1247. // with a delayed-move, but we still want to let the
  1248. // default callback get this notification also.
  1249. //
  1250. SetupPage->OcManager->InternalFlags |= OCMFLAG_ANYDELAYEDMOVES;
  1251. SetupPage->OcManager->Callbacks.SetReboot();
  1252. pOcSetRenamesFlag(SetupPage->OcManager);
  1253. for (i=0; (i<SetupPage->OcManager->TopLevelOcCount); i++) {
  1254. OcInterfaceFileBusy(
  1255. SetupPage->OcManager,
  1256. SetupPage->OcManager->TopLevelOcStringIds[i],
  1257. (PFILEPATHS)Param1,
  1258. (LPTSTR)Param2
  1259. );
  1260. }
  1261. break;
  1262. }
  1263. return (SetupDefaultQueueCallback(SetupPage->QueueContext, Notification, Param1, Param2));
  1264. }
  1265. DWORD
  1266. pOcSetupDoIt(
  1267. IN PGEN_THREAD_PARAMS Params
  1268. )
  1269. {
  1270. BOOL b;
  1271. TCHAR Text[256];
  1272. TCHAR LogText[256];
  1273. OPTIONAL_COMPONENT Oc;
  1274. POC_MANAGER OcManager;
  1275. BOOL AllowCancel;
  1276. UINT LastError = ERROR_SUCCESS;
  1277. DWORD TotalFileCount,PartialCount;
  1278. TRACE(( TEXT("at pOcSetupDoIt entry\n") ));
  1279. InterlockedIncrement( &Params->SetupPage->RefCount );
  1280. //
  1281. // Call components to let them do pre-commit processing.
  1282. //
  1283. LoadString(MyModuleHandle,IDS_PREQUEUECONFIG,Text,sizeof(Text)/sizeof(TCHAR));
  1284. SetDlgItemText(Params->hdlg,Params->SetupPage->ControlsInfo.ProgressText,Text);
  1285. #ifdef UNICODE
  1286. // If, update the text on the billboard for the progress bar.
  1287. if (Params->SetupPage->OcManager->Callbacks.BillBoardSetProgressText)
  1288. {
  1289. Params->SetupPage->OcManager->Callbacks.BillBoardSetProgressText(Text);
  1290. }
  1291. // Save it, because "Text" is used below and we would not end up with a matchin END_SECTION
  1292. lstrcpy(LogText, Text);
  1293. if (Params->SetupPage->OcManager->Callbacks.SetupPerfData)
  1294. Params->SetupPage->OcManager->Callbacks.SetupPerfData(TEXT(__FILE__),__LINE__,L"BEGIN_SECTION",LogText);
  1295. #endif
  1296. Params->SetupPage->OcManager->ProgressTextWindow = GetDlgItem(
  1297. Params->hdlg,
  1298. Params->SetupPage->ControlsInfo.ProgressText
  1299. );
  1300. if (CheckForQueueCancel(Params->SetupPage)) {
  1301. goto exit;
  1302. }
  1303. //
  1304. // send OC_ABOUT_TO_COMMIT_QUEUE message
  1305. //
  1306. pOcPreOrPostCommitProcessing(Params->SetupPage,TRUE);
  1307. OcManager = Params->SetupPage->OcManager;
  1308. AllowCancel = Params->SetupPage->AllowCancel;
  1309. OcManager->ProgressTextWindow = NULL;
  1310. if (CheckForQueueCancel(Params->SetupPage)) {
  1311. goto exit;
  1312. }
  1313. //
  1314. // Commit the file queue. We get the total number of file operations
  1315. // so we can scale the progress indicator properly. We do this manually
  1316. // as setupapi only returns back the total number of copy operations, and
  1317. // we want status on delete operations as well.
  1318. //
  1319. TotalFileCount = 0;
  1320. PartialCount = 0;
  1321. if (SetupGetFileQueueCount(Params->SetupPage->FileQueue,
  1322. FILEOP_COPY,
  1323. &PartialCount)) {
  1324. TotalFileCount += PartialCount;
  1325. }
  1326. PartialCount = 0;
  1327. if (SetupGetFileQueueCount(Params->SetupPage->FileQueue,
  1328. FILEOP_RENAME,
  1329. &PartialCount)) {
  1330. TotalFileCount += PartialCount;
  1331. }
  1332. PartialCount = 0;
  1333. if (SetupGetFileQueueCount(Params->SetupPage->FileQueue,
  1334. FILEOP_DELETE,
  1335. &PartialCount)) {
  1336. TotalFileCount += PartialCount;
  1337. }
  1338. //
  1339. // if the OC file queue is ever backup aware, add in the count
  1340. // of files to be backed up here.
  1341. //
  1342. TRACE(( TEXT("OCM: %d file operations to complete\n"), TotalFileCount ));
  1343. //
  1344. // scale the progress gauge
  1345. //
  1346. PostMessage(Params->hdlg,
  1347. WMX_TICK,
  1348. 10,Params->SetupPage->StepCount + TotalFileCount);
  1349. // If, update the text on the billboard for the progress bar.
  1350. if (Params->SetupPage->OcManager->Callbacks.BillBoardSetProgressText)
  1351. {
  1352. Params->SetupPage->OcManager->Callbacks.BillBoardSetProgressText(Text);
  1353. }
  1354. b = FALSE;
  1355. while (! b) {
  1356. DWORD ScanResult;
  1357. LoadString(MyModuleHandle,IDS_FILESCAN,Text,sizeof(Text)/sizeof(TCHAR));
  1358. SetDlgItemText(Params->hdlg,Params->SetupPage->ControlsInfo.ProgressText,Text);
  1359. b = SetupScanFileQueue(Params->SetupPage->FileQueue,
  1360. SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_PRUNE_COPY_QUEUE,
  1361. Params->hdlg,
  1362. NULL,
  1363. NULL,
  1364. &ScanResult);
  1365. //
  1366. // if the scan result is 1, then there isn't anything to commit, the entire
  1367. // file queue has been pruned. So we skip it.
  1368. //
  1369. if (ScanResult != 1) {
  1370. if( IsWindow( Params->hdlg ) ){
  1371. LoadString(MyModuleHandle,IDS_FILEOPS,Text,sizeof(Text)/sizeof(TCHAR));
  1372. SetDlgItemText(Params->SetupPage->hdlg,Params->SetupPage->ControlsInfo.ProgressText,Text);
  1373. }
  1374. if (CheckForQueueCancel(Params->SetupPage)) {
  1375. goto exit;
  1376. }
  1377. //Set the SecondNeedMedia to FALSE as we are starting a commit operation.
  1378. Params->SetupPage->SecondNeedMedia = FALSE;
  1379. b = SetupCommitFileQueue(
  1380. Params->hdlg,
  1381. Params->SetupPage->FileQueue,
  1382. OcManagerQueueCallback1,
  1383. Params->SetupPage
  1384. );
  1385. LastError = GetLastError();
  1386. #ifdef UNICODE
  1387. if (hSfp) {
  1388. SfcClose(hSfp);
  1389. }
  1390. #endif
  1391. }
  1392. if (!b) {
  1393. TRACE(( TEXT("OC:SetupCommitFileQueue failed (LE=%d), last file copied was %s\n"),
  1394. LastError,
  1395. g_LastFileCopied ));
  1396. pOcHelperReportExternalError(
  1397. OcManager,
  1398. 0, // defaults to Master Inf file
  1399. 0,
  1400. MSG_OC_CANT_COMMIT_QUEUE,
  1401. ERRFLG_OCM_MESSAGE,
  1402. LastError
  1403. );
  1404. if ( LastError == ERROR_CANCELLED ||
  1405. LastError == ERROR_CONTROL_ID_NOT_FOUND ||
  1406. LastError == ERROR_OPERATION_ABORTED) {
  1407. //
  1408. // User canceled from a SetupAPI provided Dialog
  1409. // when CallBack Returns FILEOP_ABORT LastError reports
  1410. // ERROR_CONTROL_ID_NOT_FOUND if User aborts in SetupApi
  1411. // find File Dialog you get ERROR_CANCELLED
  1412. //
  1413. if ( AllowCancel &&
  1414. (OcManager->SetupData.OperationFlags & SETUPOP_STANDALONE)) {
  1415. _LogError(
  1416. OcManager,
  1417. OcErrLevError|MB_ICONEXCLAMATION|MB_OK,
  1418. MSG_OC_USER_CANCELED,
  1419. LastError
  1420. );
  1421. }
  1422. //
  1423. // this will force the cancel of setup
  1424. //
  1425. LastError = IDCANCEL;
  1426. } else {
  1427. //
  1428. // Warn the user that it might be hazzardous to continue after copy error
  1429. //
  1430. LastError = _LogError(
  1431. OcManager,
  1432. OcErrLevError|MB_ICONEXCLAMATION|MB_OKCANCEL|MB_DEFBUTTON2,
  1433. MSG_OC_CANT_COMMIT_QUEUE,
  1434. LastError
  1435. );
  1436. }
  1437. //
  1438. // Abort the setup if the user pressed Cancel or
  1439. // Batch mode log the error and cancel out of setup
  1440. //
  1441. if ( LastError == IDCANCEL
  1442. || OcManager->SetupData.OperationFlags & SETUPOP_BATCH) {
  1443. PostMessage(Params->hdlg,WMX_SETUP,OCSETUPSTATE_COPYABORT,0);
  1444. goto exit;
  1445. } else if ( LastError == IDOK ) {
  1446. b = TRUE;
  1447. }
  1448. }
  1449. }
  1450. //
  1451. // put a message in the log so we know we completed all file operations
  1452. //
  1453. _LogError(OcManager,
  1454. OcErrLevInfo,
  1455. MSG_OC_LOG_QUEUE_COMPLETE
  1456. );
  1457. //
  1458. // Tell the UI that we are done with the file operations
  1459. //
  1460. PostMessage(Params->hdlg,WMX_SETUP,OCSETUPSTATE_COPYDONE,0);
  1461. #ifdef UNICODE
  1462. if (Params->SetupPage->OcManager->Callbacks.SetupPerfData)
  1463. Params->SetupPage->OcManager->Callbacks.SetupPerfData(TEXT(__FILE__),__LINE__,L"END_SECTION",LogText);
  1464. #endif
  1465. //
  1466. // Call components to let them do post-commit processing.
  1467. //
  1468. LoadString(MyModuleHandle,IDS_CONFIGURING,Text,sizeof(Text)/sizeof(TCHAR));
  1469. SetDlgItemText(Params->hdlg,Params->SetupPage->ControlsInfo.ProgressText,Text);
  1470. #ifdef UNICODE
  1471. // If, update the text on the billboard for the progress bar.
  1472. if (Params->SetupPage->OcManager->Callbacks.BillBoardSetProgressText)
  1473. {
  1474. Params->SetupPage->OcManager->Callbacks.BillBoardSetProgressText(Text);
  1475. }
  1476. if (Params->SetupPage->OcManager->Callbacks.SetupPerfData)
  1477. Params->SetupPage->OcManager->Callbacks.SetupPerfData(TEXT(__FILE__),__LINE__,L"BEGIN_SECTION",Text);
  1478. #endif
  1479. Params->SetupPage->OcManager->ProgressTextWindow = GetDlgItem(
  1480. Params->hdlg,
  1481. Params->SetupPage->ControlsInfo.ProgressText
  1482. );
  1483. if (CheckForQueueCancel(Params->SetupPage)) {
  1484. goto exit;
  1485. }
  1486. pOcPreOrPostCommitProcessing(Params->SetupPage,FALSE);
  1487. if (CheckForQueueCancel(Params->SetupPage)) {
  1488. goto exit;
  1489. }
  1490. Params->SetupPage->OcManager->ProgressTextWindow = NULL;
  1491. PostMessage(Params->hdlg,WMX_SETUP,OCSETUPSTATE_DONE,0);
  1492. #ifdef UNICODE
  1493. if (Params->SetupPage->OcManager->Callbacks.SetupPerfData)
  1494. Params->SetupPage->OcManager->Callbacks.SetupPerfData(TEXT(__FILE__),__LINE__,L"END_SECTION",Text);
  1495. #endif
  1496. exit:
  1497. TRACE(( TEXT("at pOcSetupDoIt exit\n") ));
  1498. pOcFreeOcSetupPage( Params->SetupPage );
  1499. if (Params->Async) {
  1500. pSetupFree(Params);
  1501. }
  1502. return (0);
  1503. }
  1504. VOID
  1505. pOcPreOrPostCommitProcessing(
  1506. IN OUT PSETUP_PAGE SetupPage,
  1507. IN BOOL PreCommit
  1508. )
  1509. /*++
  1510. Routine Description:
  1511. Handle processing and notification to the component dlls before or after
  1512. the file queue is committed. This involves calling interface dlls once
  1513. for each top-level component, and then once for each subcomponent.
  1514. The ordering for the top-level components is the order that the
  1515. components were listed in the master oc inf.
  1516. The ordering for leaf components is generally random within each
  1517. top-level hierarchy, but 'detours' are taken when components are
  1518. needed by other components. This ensures that components are
  1519. called in the correct order to faciliate uninstall-type actions.
  1520. Arguments:
  1521. SetupPage - supplies context data structure.
  1522. PreCommit - TRUE indicates OC_ABOUT_TO_COMMIT_QUEUE is to be called,
  1523. otherwise OC_COMPLETE_INSTALLATION is to be called.
  1524. Return Value:
  1525. None. Errors are logged.
  1526. --*/
  1527. {
  1528. OPTIONAL_COMPONENT Oc,AuxOc;
  1529. unsigned i,child;
  1530. //
  1531. // Call each component at the "top-level" (ie, no subcomponent).
  1532. //
  1533. pOcTopLevelPreOrPostCommitProcessing(SetupPage,PreCommit);
  1534. if (CheckForQueueCancel(SetupPage)) {
  1535. return;
  1536. }
  1537. if (!PreCommit) {
  1538. //
  1539. // Make sure the components are marked as unprocessed.
  1540. //
  1541. MYASSERT(SetupPage->OcManager->ComponentStringTable);
  1542. //
  1543. // if this doesn't exist then something is hosed.
  1544. //
  1545. if (!SetupPage->OcManager->ComponentStringTable) {
  1546. return;
  1547. }
  1548. pSetupStringTableEnum(
  1549. SetupPage->OcManager->ComponentStringTable,
  1550. &Oc,
  1551. sizeof(OPTIONAL_COMPONENT),
  1552. pOcMarkUnprocessedStringCB,
  1553. 0
  1554. );
  1555. }
  1556. //
  1557. // Call component dlls for each child subcomponent.
  1558. //
  1559. for (i=0; i<SetupPage->OcManager->TopLevelOcCount; i++) {
  1560. pSetupStringTableGetExtraData(
  1561. SetupPage->OcManager->ComponentStringTable,
  1562. SetupPage->OcManager->TopLevelOcStringIds[i],
  1563. &Oc,
  1564. sizeof(OPTIONAL_COMPONENT)
  1565. );
  1566. for (child=0; child<SetupPage->OcManager->TopLevelParentOcCount; child++) {
  1567. pOcSetupDoItWorker(
  1568. SetupPage,
  1569. SetupPage->OcManager->TopLevelParentOcStringIds[child],
  1570. SetupPage->OcManager->TopLevelOcStringIds[i],
  1571. PreCommit
  1572. );
  1573. }
  1574. }
  1575. }
  1576. VOID
  1577. pOcTopLevelPreOrPostCommitProcessing(
  1578. IN PSETUP_PAGE SetupPage,
  1579. IN BOOL PreCommit
  1580. )
  1581. /*++
  1582. Routine Description:
  1583. Call the OC_COMPLETE_INSTALLATION or OC_ABOUT_TO_COMMIT_QUEUE
  1584. interface routine once for each top-level component.
  1585. Arguments:
  1586. SetupPage - supplies context structure.
  1587. PreCommit - if 0, then call OC_COMPLETE_INSTALLATION. Otherwise
  1588. call OC_ABOUT_TO_COMMIT_QUEUE.
  1589. Return Value:
  1590. None. Errors are logged.
  1591. --*/
  1592. {
  1593. unsigned i;
  1594. OPTIONAL_COMPONENT Oc;
  1595. UINT Err;
  1596. for (i=0; i<SetupPage->OcManager->TopLevelOcCount; i++) {
  1597. pSetupStringTableGetExtraData(
  1598. SetupPage->OcManager->ComponentStringTable,
  1599. SetupPage->OcManager->TopLevelOcStringIds[i],
  1600. &Oc,
  1601. sizeof(OPTIONAL_COMPONENT)
  1602. );
  1603. SetupPage->CurrentTopLevelComponentIndex = i;
  1604. Err = OcInterfaceCompleteInstallation(
  1605. SetupPage->OcManager,
  1606. SetupPage->OcManager->TopLevelOcStringIds[i],
  1607. NULL,
  1608. PreCommit
  1609. );
  1610. if (Err != NO_ERROR) {
  1611. _LogError(
  1612. SetupPage->OcManager,
  1613. OcErrLevError,
  1614. MSG_OC_COMP_INST_FAIL,
  1615. Oc.Description,
  1616. Err
  1617. );
  1618. pOcHelperReportExternalError(
  1619. SetupPage->OcManager,
  1620. SetupPage->OcManager->TopLevelOcStringIds[i],
  1621. 0,
  1622. MSG_OC_COMP_INST_FAIL,
  1623. ERRFLG_OCM_MESSAGE,
  1624. Oc.Description,
  1625. Err
  1626. );
  1627. }
  1628. }
  1629. }
  1630. VOID
  1631. pOcSetupDoItWorker(
  1632. IN PSETUP_PAGE SetupPage,
  1633. IN LONG StringId,
  1634. IN LONG TopLevelStringId,
  1635. IN BOOL PreCommit
  1636. )
  1637. /*++
  1638. Routine Description:
  1639. Call the OC_COMPLETE_INSTALLATION or OC_ABOUT_TO_COMMIT_QUEUE
  1640. interface routine for each child of a given top-level component.
  1641. Arguments:
  1642. SetupPage - supplies context structure.
  1643. StringId - ID for the child component to be called
  1644. TopLevelStringId - ID for the child's parent
  1645. PreCommit - if 0, then call OC_COMPLETE_INSTALLATION. Otherwise
  1646. call OC_ABOUT_TO_COMMIT_QUEUE.
  1647. Return Value:
  1648. None. Errors are logged.
  1649. --*/
  1650. {
  1651. OPTIONAL_COMPONENT Oc;
  1652. UINT Err;
  1653. LONG Id;
  1654. unsigned i;
  1655. LONG TopLevelIndex;
  1656. UINT SelectionState;
  1657. UINT InstalledState;
  1658. //
  1659. // Figure out the index of the top-level component associated with this
  1660. // subcomponent.
  1661. //
  1662. Id = pOcGetTopLevelComponent(SetupPage->OcManager,StringId);
  1663. TopLevelIndex = -1;
  1664. for (i=0; i<SetupPage->OcManager->TopLevelOcCount; i++) {
  1665. if (SetupPage->OcManager->TopLevelOcStringIds[i] == Id) {
  1666. TopLevelIndex = i;
  1667. break;
  1668. }
  1669. }
  1670. //
  1671. // Fetch extra data for this subcomponent.
  1672. //
  1673. pSetupStringTableGetExtraData(
  1674. SetupPage->OcManager->ComponentStringTable,
  1675. StringId,
  1676. &Oc,
  1677. sizeof(OPTIONAL_COMPONENT)
  1678. );
  1679. if (Oc.FirstChildStringId == -1) {
  1680. //
  1681. // Leaf subcomponent.
  1682. //
  1683. // In the precommit case, check the subcomponents this subcomponent
  1684. // is needed by; if there are any, process them first.
  1685. //
  1686. // In the postcommit case, check the subcomponents this subcomponent
  1687. // needs; if there are any, process them first.
  1688. //
  1689. if (PreCommit) {
  1690. for (i=0; i<Oc.NeededByCount; i++) {
  1691. pOcSetupDoItWorker(
  1692. SetupPage,
  1693. Oc.NeededByStringIds[i],
  1694. pOcGetTopLevelComponent(SetupPage->OcManager,Oc.NeededByStringIds[i]),
  1695. TRUE
  1696. );
  1697. }
  1698. } else {
  1699. for (i=0; i<Oc.NeedsCount; i++) {
  1700. if (Oc.NeedsStringIds[i] != StringId) {
  1701. pOcSetupDoItWorker(
  1702. SetupPage,
  1703. Oc.NeedsStringIds[i],
  1704. pOcGetTopLevelComponent(SetupPage->OcManager,Oc.NeedsStringIds[i]),
  1705. FALSE
  1706. );
  1707. }
  1708. }
  1709. }
  1710. //
  1711. // Fetch extra data for this subcomponent again as it might have
  1712. // changed in the recursive call we just made.
  1713. //
  1714. pSetupStringTableGetExtraData(
  1715. SetupPage->OcManager->ComponentStringTable,
  1716. StringId,
  1717. &Oc,
  1718. sizeof(OPTIONAL_COMPONENT)
  1719. );
  1720. //
  1721. // If not processed already, process now.
  1722. //
  1723. if (!(Oc.InternalFlags & OCFLAG_PROCESSED)) {
  1724. Oc.InternalFlags |= OCFLAG_PROCESSED;
  1725. pSetupStringTableSetExtraData(
  1726. SetupPage->OcManager->ComponentStringTable,
  1727. StringId,
  1728. &Oc,
  1729. sizeof(OPTIONAL_COMPONENT)
  1730. );
  1731. SetupPage->CurrentTopLevelComponentIndex = TopLevelIndex;
  1732. //
  1733. // Set current install state to not installed, pending successful
  1734. // outcome of the installation routine.
  1735. //
  1736. if (!PreCommit) {
  1737. SelectionState = Oc.SelectionState;
  1738. Oc.SelectionState = SELSTATE_NO;
  1739. pOcSetOneInstallState(SetupPage->OcManager,StringId);
  1740. }
  1741. Err = OcInterfaceCompleteInstallation(
  1742. SetupPage->OcManager,
  1743. pOcGetTopLevelComponent(SetupPage->OcManager,StringId),
  1744. pSetupStringTableStringFromId(SetupPage->OcManager->ComponentStringTable,StringId),
  1745. PreCommit
  1746. );
  1747. // Ignore error and ask the component
  1748. // for the actual installation state.
  1749. if (!PreCommit) {
  1750. Oc.SelectionState = (Err) ? Oc.OriginalSelectionState : SelectionState;
  1751. InstalledState = OcInterfaceQueryState(
  1752. SetupPage->OcManager,
  1753. pOcGetTopLevelComponent(SetupPage->OcManager,StringId),
  1754. pSetupStringTableStringFromId(SetupPage->OcManager->ComponentStringTable,StringId),
  1755. OCSELSTATETYPE_FINAL
  1756. );
  1757. switch (InstalledState) {
  1758. case SubcompOn:
  1759. SelectionState = SELSTATE_YES;
  1760. break;
  1761. case SubcompOff:
  1762. SelectionState = SELSTATE_NO;
  1763. break;
  1764. default:
  1765. SelectionState = Oc.SelectionState;
  1766. break;
  1767. }
  1768. Oc.SelectionState = SelectionState;
  1769. pSetupStringTableSetExtraData(
  1770. SetupPage->OcManager->ComponentStringTable,
  1771. StringId,
  1772. &Oc,
  1773. sizeof(OPTIONAL_COMPONENT)
  1774. );
  1775. pOcSetOneInstallState(SetupPage->OcManager,StringId);
  1776. }
  1777. }
  1778. } else {
  1779. //
  1780. // Parent component. Spin through the children.
  1781. //
  1782. for (Id = Oc.FirstChildStringId; Id != -1; Id = Oc.NextSiblingStringId) {
  1783. pOcSetupDoItWorker(SetupPage,Id,TopLevelStringId,PreCommit);
  1784. pSetupStringTableGetExtraData(
  1785. SetupPage->OcManager->ComponentStringTable,
  1786. Id,
  1787. &Oc,
  1788. sizeof(OPTIONAL_COMPONENT)
  1789. );
  1790. }
  1791. }
  1792. }
  1793. BOOL
  1794. pOcMarkUnprocessedStringCB(
  1795. IN PVOID StringTable,
  1796. IN LONG StringId,
  1797. IN PCTSTR String,
  1798. IN POPTIONAL_COMPONENT Oc,
  1799. IN UINT OcSize,
  1800. IN LPARAM Unused
  1801. )
  1802. /*++
  1803. Routine Description:
  1804. String table callback routine. Clears the OCFLAG_PROCESSED flag in
  1805. the OPTIONAL_COMPONENT structure that is passed to it.
  1806. Arguments:
  1807. String string table callback arguments.
  1808. Return Value:
  1809. Always returns TRUE to continue enumeration.
  1810. --*/
  1811. {
  1812. Oc->InternalFlags &= ~OCFLAG_PROCESSED;
  1813. pSetupStringTableSetExtraData(StringTable,StringId,Oc,OcSize);
  1814. return (TRUE);
  1815. }
  1816. VOID
  1817. _pOcExternalProgressIndicator(
  1818. IN PSETUP_PAGE SetupPage,
  1819. IN BOOL ExternalIndicator,
  1820. IN HWND hdlg
  1821. )
  1822. {
  1823. POC_MANAGER OcManager;
  1824. HWND Animation;
  1825. OcManager = SetupPage->OcManager;
  1826. EnableWindow(
  1827. GetDlgItem(hdlg,SetupPage->ControlsInfo.ProgressBar),
  1828. !ExternalIndicator
  1829. );
  1830. if (SetupPage->ForceExternalProgressIndicator) {
  1831. ShowWindow(
  1832. GetDlgItem(hdlg,SetupPage->ControlsInfo.ProgressBar),
  1833. ExternalIndicator ? SW_HIDE : SW_SHOW
  1834. );
  1835. ShowWindow(
  1836. GetDlgItem(hdlg,SetupPage->ControlsInfo.ProgressLabel),
  1837. ExternalIndicator ? SW_HIDE : SW_SHOW
  1838. );
  1839. }
  1840. Animation = GetDlgItem(hdlg,SetupPage->ControlsInfo.AnimationControl);
  1841. sapiAssert( Animation != NULL );
  1842. if (!ExternalIndicator) {
  1843. Animate_Stop(Animation);
  1844. Animate_Close(Animation);
  1845. }
  1846. EnableWindow(Animation,ExternalIndicator);
  1847. ShowWindow(Animation,ExternalIndicator ? SW_SHOW : SW_HIDE);
  1848. if (ExternalIndicator) {
  1849. Animate_Open(Animation,MAKEINTRESOURCE(SetupPage->ControlsInfo.AnimationResource));
  1850. Animate_Play(Animation,0,-1,-1);
  1851. }
  1852. }
  1853. VOID
  1854. pOcExternalProgressIndicator(
  1855. IN PHELPER_CONTEXT OcManagerContext,
  1856. IN BOOL ExternalIndicator
  1857. )
  1858. {
  1859. POC_MANAGER OcManager;
  1860. HWND hdlg;
  1861. PSETUP_PAGE SetupPage;
  1862. OcManager = OcManagerContext->OcManager;
  1863. if (OcManager->ProgressTextWindow
  1864. && (hdlg = GetParent(OcManager->ProgressTextWindow))
  1865. && (SetupPage = (PSETUP_PAGE)GetWindowLongPtr(hdlg,DWLP_USER))
  1866. && !SetupPage->ForceExternalProgressIndicator) {
  1867. _pOcExternalProgressIndicator(SetupPage,ExternalIndicator,hdlg);
  1868. }
  1869. }