Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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