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.

698 lines
20 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. billbrd.c
  5. Abstract:
  6. Routines for displaying Windows that are static in nature.
  7. Author:
  8. Ted Miller (tedm) 8-Jun-1995
  9. Revision History:
  10. --*/
  11. #include "setupp.h"
  12. #pragma hdrstop
  13. //
  14. // Define structure we pass around to describe a billboard.
  15. //
  16. typedef struct _BILLBOARD_PARAMS {
  17. UINT MessageId;
  18. va_list *arglist;
  19. HWND Owner;
  20. DWORD NotifyThreadId;
  21. } BILLBOARD_PARAMS, *PBILLBOARD_PARAMS;
  22. //
  23. // Custom window messages
  24. //
  25. #define WMX_BILLBOARD_DISPLAYED (WM_USER+243)
  26. #define WMX_BILLBOARD_TERMINATE (WM_USER+244)
  27. #define ID_REBOOT_TIMER 10
  28. //
  29. // Import the entry point used to check whether setup is executing within an
  30. // ASR context.
  31. //
  32. extern BOOL
  33. AsrIsEnabled( VOID );
  34. INT_PTR
  35. BillboardDlgProc(
  36. IN HWND hdlg,
  37. IN UINT msg,
  38. IN WPARAM wParam,
  39. IN LPARAM lParam
  40. )
  41. {
  42. static BOOL Initializing;
  43. HWND Animation = GetDlgItem(hdlg,IDA_SETUPINIT);
  44. static HANDLE hBitmap;
  45. static HCURSOR hCursor;
  46. switch(msg) {
  47. case WM_INITDIALOG:
  48. {
  49. PBILLBOARD_PARAMS BillParams;
  50. PWSTR p;
  51. BOOL b;
  52. BillParams = (PBILLBOARD_PARAMS)lParam;
  53. if(BillParams->MessageId == MSG_INITIALIZING) {
  54. Initializing = TRUE;
  55. b = TRUE;
  56. hCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
  57. ShowCursor( TRUE );
  58. Animate_Open(Animation,MAKEINTRESOURCE(IDA_SETUPINIT));
  59. hBitmap = LoadBitmap (MyModuleHandle, MAKEINTRESOURCE(IDB_INIT_WORKSTATION));
  60. SendDlgItemMessage(hdlg,IDC_BITMAP,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)hBitmap);
  61. } else {
  62. Initializing = FALSE;
  63. if(p = RetrieveAndFormatMessageV(SETUPLOG_USE_MESSAGEID,
  64. BillParams->MessageId,BillParams->arglist)) {
  65. b = SetDlgItemText(hdlg,IDT_STATIC_1,p);
  66. MyFree(p);
  67. } else {
  68. b = FALSE;
  69. }
  70. }
  71. if(b) {
  72. //
  73. // Center the billboard relative to the window that owns it.
  74. //
  75. // if we have the BB window, do the positioning on that.
  76. // MainWindowHandle point to that window
  77. //
  78. if (GetBBhwnd())
  79. CenterWindowRelativeToWindow(hdlg, MainWindowHandle, FALSE);
  80. else
  81. pSetupCenterWindowRelativeToParent(hdlg);
  82. //
  83. // Post ourselves a message that we won't get until we've been
  84. // actually displayed on the screen. Then when we process that message,
  85. // we inform the thread that created us that we're up. Note that
  86. // once that notification has been made, the BillParams we're using
  87. // now will go away since they are stored in local vars (see
  88. // DisplayBillboard()).
  89. //
  90. PostMessage(hdlg,WMX_BILLBOARD_DISPLAYED,0,(LPARAM)BillParams->NotifyThreadId);
  91. //
  92. // Tell Windows not to process this message.
  93. //
  94. return(FALSE);
  95. } else {
  96. //
  97. // We won't post the message, but returning -1 will get the
  98. // caller of DialogBox to post it for us.
  99. //
  100. EndDialog(hdlg,-1);
  101. }
  102. }
  103. break;
  104. case WMX_BILLBOARD_DISPLAYED:
  105. if(Initializing) {
  106. Animate_Play(Animation,0,-1,-1);
  107. }
  108. PostThreadMessage(
  109. (DWORD)lParam,
  110. WMX_BILLBOARD_DISPLAYED,
  111. TRUE,
  112. (LPARAM)hdlg
  113. );
  114. break;
  115. case WMX_BILLBOARD_TERMINATE:
  116. if(Initializing) {
  117. SetCursor( hCursor );
  118. ShowCursor( FALSE );
  119. Animate_Stop(Animation);
  120. Animate_Close(Animation);
  121. DeleteObject(hBitmap);
  122. }
  123. EndDialog(hdlg,0);
  124. break;
  125. default:
  126. return(FALSE);
  127. }
  128. return(TRUE);
  129. }
  130. DWORD
  131. BillboardThread(
  132. IN PVOID ThreadParam
  133. )
  134. {
  135. PBILLBOARD_PARAMS BillboardParams;
  136. INT_PTR i;
  137. BillboardParams = ThreadParam;
  138. //
  139. // For the "initializing" case, we use a different dialog.
  140. //
  141. if( AsrIsEnabled() ) {
  142. i = DialogBoxParam(
  143. MyModuleHandle,
  144. (BillboardParams->MessageId == MSG_INITIALIZING) ?
  145. MAKEINTRESOURCE(IDD_SETUPINIT_ASR) :
  146. MAKEINTRESOURCE(IDD_BILLBOARD1),
  147. BillboardParams->Owner,
  148. BillboardDlgProc,
  149. (LPARAM)BillboardParams
  150. );
  151. } else {
  152. i = DialogBoxParam(
  153. MyModuleHandle,
  154. (BillboardParams->MessageId == MSG_INITIALIZING) ?
  155. MAKEINTRESOURCE(IDD_SETUPINIT) :
  156. MAKEINTRESOURCE(IDD_BILLBOARD1),
  157. BillboardParams->Owner,
  158. BillboardDlgProc,
  159. (LPARAM)BillboardParams
  160. );
  161. }
  162. //
  163. // If the dialog box call failed, we have to tell the
  164. // main thread about it here. Otherwise the dialog proc
  165. // tells the main thread.
  166. //
  167. if(i == -1) {
  168. PostThreadMessage(
  169. BillboardParams->NotifyThreadId,
  170. WMX_BILLBOARD_DISPLAYED,
  171. FALSE,
  172. (LPARAM)NULL
  173. );
  174. }
  175. return(0);
  176. }
  177. HWND
  178. DisplayBillboard(
  179. IN HWND Owner,
  180. IN UINT MessageId,
  181. ...
  182. )
  183. {
  184. HANDLE ThreadHandle;
  185. DWORD ThreadId;
  186. BILLBOARD_PARAMS ThreadParams;
  187. va_list arglist;
  188. HWND hwnd;
  189. MSG msg;
  190. hwnd = NULL;
  191. // If we have a billboard, we should not need this. dialog.
  192. if (GetBBhwnd() == NULL)
  193. {
  194. va_start(arglist,MessageId);
  195. //
  196. // The billboard will exist in a separate thread so it will
  197. // always be responsive.
  198. //
  199. ThreadParams.MessageId = MessageId;
  200. ThreadParams.arglist = &arglist;
  201. ThreadParams.Owner = Owner;
  202. ThreadParams.NotifyThreadId = GetCurrentThreadId();
  203. ThreadHandle = CreateThread(
  204. NULL,
  205. 0,
  206. BillboardThread,
  207. &ThreadParams,
  208. 0,
  209. &ThreadId
  210. );
  211. if(ThreadHandle) {
  212. //
  213. // Wait for the billboard to tell us its window handle
  214. // or that it failed to display the billboard dialog.
  215. //
  216. do {
  217. GetMessage(&msg,NULL,0,0);
  218. if(msg.message == WMX_BILLBOARD_DISPLAYED) {
  219. if(msg.wParam) {
  220. hwnd = (HWND)msg.lParam;
  221. Sleep(1500); // let the user see it even on fast machines
  222. }
  223. } else {
  224. DispatchMessage(&msg);
  225. }
  226. } while(msg.message != WMX_BILLBOARD_DISPLAYED);
  227. CloseHandle(ThreadHandle);
  228. }
  229. va_end(arglist);
  230. }
  231. else
  232. {
  233. // Start BB text
  234. StartStopBB(TRUE);
  235. }
  236. return(hwnd);
  237. }
  238. VOID
  239. KillBillboard(
  240. IN HWND BillboardWindowHandle
  241. )
  242. {
  243. if(BillboardWindowHandle && IsWindow(BillboardWindowHandle)) {
  244. PostMessage(BillboardWindowHandle,WMX_BILLBOARD_TERMINATE,0,0);
  245. }
  246. }
  247. INT_PTR
  248. DoneDlgProc(
  249. IN HWND hdlg,
  250. IN UINT msg,
  251. IN WPARAM wParam,
  252. IN LPARAM lParam
  253. )
  254. {
  255. PWSTR p;
  256. static UINT Countdown;
  257. switch(msg) {
  258. case WM_INITDIALOG:
  259. // if we have the BB window, do the positioning on that. MainWindowHandle point to that window
  260. if (GetBBhwnd())
  261. CenterWindowRelativeToWindow(hdlg, MainWindowHandle, FALSE);
  262. else
  263. pSetupCenterWindowRelativeToParent(hdlg);
  264. SendDlgItemMessage(
  265. hdlg,
  266. IDOK,
  267. BM_SETIMAGE,
  268. 0,
  269. (LPARAM)LoadBitmap(MyModuleHandle,MAKEINTRESOURCE(IDB_REBOOT))
  270. );
  271. if(p = RetrieveAndFormatMessage(NULL,(UINT)lParam)) {
  272. SetDlgItemText(hdlg,IDT_STATIC_1,p);
  273. MyFree(p);
  274. }
  275. Countdown = 15 * 10;
  276. SendDlgItemMessage(hdlg,IDC_PROGRESS1,PBM_SETRANGE,0,MAKELONG(0,Countdown));
  277. SendDlgItemMessage(hdlg,IDC_PROGRESS1,PBM_SETSTEP,1,0);
  278. SendDlgItemMessage(hdlg,IDC_PROGRESS1,PBM_SETPOS,0,0);
  279. SetTimer(hdlg,ID_REBOOT_TIMER,100,NULL);
  280. SetFocus(GetDlgItem(hdlg,IDOK));
  281. return(FALSE);
  282. case WM_TIMER:
  283. Countdown--;
  284. if(Countdown) {
  285. SendDlgItemMessage(hdlg,IDC_PROGRESS1,PBM_STEPIT,0,0);
  286. } else {
  287. KillTimer(hdlg,ID_REBOOT_TIMER);
  288. DeleteObject((HGDIOBJ)SendDlgItemMessage(hdlg,IDOK,BM_GETIMAGE,0,0));
  289. EndDialog(hdlg,0);
  290. }
  291. break;
  292. case WM_COMMAND:
  293. if((HIWORD(wParam) == BN_CLICKED) && (LOWORD(wParam) == IDOK)) {
  294. KillTimer(hdlg,ID_REBOOT_TIMER);
  295. DeleteObject((HGDIOBJ)SendDlgItemMessage(hdlg,IDOK,BM_GETIMAGE,0,0));
  296. EndDialog(hdlg,0);
  297. } else {
  298. return(FALSE);
  299. }
  300. break;
  301. default:
  302. return(FALSE);
  303. }
  304. return(TRUE);
  305. }
  306. typedef BOOL (CALLBACK *STOPBILLBOARD)();
  307. typedef BOOL (CALLBACK *STARTBILLBOARD)();
  308. typedef BOOL (WINAPI* SETTIMEESTIMATE)(LPCTSTR szText);
  309. typedef BOOL (WINAPI* SETPROGRESSTEXT)(LPCTSTR szText);
  310. typedef BOOL (WINAPI* SETINFOTEXT)(LPCTSTR szText);
  311. typedef LRESULT (WINAPI* PROGRESSGAUGEMSG)(UINT msg, WPARAM wparam, LPARAM lparam);
  312. typedef BOOL (WINAPI* SHOWPROGRESSGAUGEWINDOW)(UINT uiShow);
  313. BOOL BB_ShowProgressGaugeWnd(UINT nCmdShow)
  314. {
  315. static SHOWPROGRESSGAUGEWINDOW fpShowGauge = NULL;
  316. BOOL bRet = FALSE;
  317. if (fpShowGauge == NULL)
  318. {
  319. if (hinstBB)
  320. {
  321. fpShowGauge = (SHOWPROGRESSGAUGEWINDOW )GetProcAddress(hinstBB, "ShowProgressGaugeWindow");
  322. }
  323. }
  324. if (fpShowGauge != NULL)
  325. {
  326. bRet = fpShowGauge(nCmdShow);
  327. }
  328. return bRet;
  329. }
  330. LRESULT BB_ProgressGaugeMsg(UINT msg, WPARAM wparam, LPARAM lparam)
  331. {
  332. static PROGRESSGAUGEMSG fpProgressGaugeMsg = NULL;
  333. LRESULT lresult = 0;
  334. if (fpProgressGaugeMsg == NULL)
  335. {
  336. if (hinstBB)
  337. {
  338. fpProgressGaugeMsg = (PROGRESSGAUGEMSG )GetProcAddress(hinstBB, "ProgressGaugeMsg");
  339. }
  340. }
  341. if (fpProgressGaugeMsg != NULL)
  342. {
  343. lresult = fpProgressGaugeMsg(msg, wparam, lparam);
  344. }
  345. return lresult;
  346. }
  347. void BB_SetProgressText(LPCTSTR szText)
  348. {
  349. static SETPROGRESSTEXT fpSetProgressText = NULL;
  350. if (fpSetProgressText == NULL)
  351. {
  352. if (hinstBB)
  353. {
  354. fpSetProgressText = (SETPROGRESSTEXT )GetProcAddress(hinstBB, "SetProgressText");
  355. }
  356. }
  357. if (fpSetProgressText != NULL)
  358. {
  359. fpSetProgressText(szText);
  360. }
  361. }
  362. void BB_SetInfoText(LPTSTR szText)
  363. {
  364. static SETINFOTEXT fpSetInfoText = NULL;
  365. if (fpSetInfoText == NULL)
  366. {
  367. if (hinstBB)
  368. {
  369. fpSetInfoText = (SETINFOTEXT )GetProcAddress(hinstBB, "SetInfoText");
  370. }
  371. }
  372. if (fpSetInfoText != NULL)
  373. {
  374. fpSetInfoText(szText);
  375. }
  376. }
  377. void BB_SetTimeEstimateText(LPTSTR szText)
  378. {
  379. static SETTIMEESTIMATE fpSetTimeEstimate = NULL;
  380. if (fpSetTimeEstimate == NULL)
  381. {
  382. if (hinstBB)
  383. {
  384. fpSetTimeEstimate = (SETTIMEESTIMATE)GetProcAddress(hinstBB, "SetTimeEstimate");
  385. }
  386. }
  387. if (fpSetTimeEstimate != NULL)
  388. {
  389. fpSetTimeEstimate(szText);
  390. }
  391. }
  392. BOOL StartStopBB(BOOL bStart)
  393. {
  394. static STARTBILLBOARD fpStart = NULL;
  395. static STOPBILLBOARD fpStop = NULL;
  396. BOOL bRet = FALSE;
  397. if ((fpStart == NULL) || (fpStop == NULL))
  398. {
  399. if (hinstBB)
  400. {
  401. fpStop = (STARTBILLBOARD )GetProcAddress(hinstBB, "StopBillBoard");
  402. fpStart = (STOPBILLBOARD )GetProcAddress(hinstBB, "StartBillBoard");
  403. }
  404. }
  405. if ((fpStart != NULL) && (fpStop != NULL))
  406. {
  407. if (bStart)
  408. bRet = fpStart();
  409. else
  410. bRet = fpStop();
  411. }
  412. return bRet;
  413. }
  414. LRESULT ProgressGaugeMsgWrapper(UINT msg, WPARAM wparam, LPARAM lparam)
  415. {
  416. static DWORD MsecPerProcessTick;
  417. static DWORD PreviousRemainingTime = 0;
  418. static DWORD RemainungTimeMsecInThisPhase = 0;
  419. static int iCurrentPos = 0;
  420. static int iMaxPosition = 0;
  421. static int iStepSize = 0;
  422. static UINT PreviousPhase = Phase_Unknown;
  423. static BOOL IgnoreSetRange = FALSE;
  424. static BOOL IgnoreSetPos = FALSE;
  425. DWORD dwDeltaTicks = 0;
  426. switch (msg)
  427. {
  428. case WMX_PROGRESSTICKS:
  429. // If we get a WMX_PROGRESSTICKS before a PBM_SETRANGE, ignore the set range
  430. // This should be use if the progress bar only takes up x% of the whole bar.
  431. // In this case the phase sends PBM_SETRANGE and a PBM_SETPOS to setup the
  432. // progress values for it's part of the gauge.
  433. IgnoreSetRange = TRUE;
  434. if (PreviousPhase != CurrentPhase)
  435. {
  436. PreviousPhase = CurrentPhase;
  437. iCurrentPos = 0;
  438. iMaxPosition = (int)wparam;
  439. iStepSize = 10;
  440. MsecPerProcessTick = ((SetupPhase[CurrentPhase].Time*1000)/(iMaxPosition - iCurrentPos) )+ 1;
  441. RemainungTimeMsecInThisPhase = (SetupPhase[CurrentPhase].Time * 1000);
  442. PreviousRemainingTime = RemainungTimeMsecInThisPhase;
  443. }
  444. else
  445. {
  446. // what to do if the same phase send more then one set range.
  447. // don't change the remaining time, only recal the msecperprogresstick
  448. //
  449. iCurrentPos = 0;
  450. iMaxPosition = (int)wparam;
  451. iStepSize = 10;
  452. MsecPerProcessTick = (RemainungTimeMsecInThisPhase /(iMaxPosition - iCurrentPos) )+ 1;
  453. }
  454. break;
  455. case PBM_SETPOS:
  456. {
  457. UINT uiCurrentPos;
  458. if (!IgnoreSetPos)
  459. {
  460. int iDeltaPos = 0;
  461. // Find out where the current position of the gasgauge is.
  462. // The difference is the #ticks we use to reduce the time estimate
  463. uiCurrentPos = (UINT)BB_ProgressGaugeMsg(PBM_GETPOS, 0, 0);
  464. // See if there is a difference in the current position and the one
  465. // we think we are in.
  466. // Only if the new position is greater then the current one
  467. // calc the difference and substract from remaining time.
  468. if ((UINT)wparam > uiCurrentPos)
  469. {
  470. iDeltaPos = (UINT)wparam - uiCurrentPos;
  471. iCurrentPos += iDeltaPos;
  472. // Only substract if more time left
  473. if ((iDeltaPos * MsecPerProcessTick) < RemainungTimeMsecInThisPhase)
  474. {
  475. RemainungTimeMsecInThisPhase -= (iDeltaPos * MsecPerProcessTick);
  476. }
  477. else
  478. {
  479. RemainungTimeMsecInThisPhase = 0;
  480. }
  481. UpdateTimeString(RemainungTimeMsecInThisPhase, &PreviousRemainingTime);
  482. }
  483. }
  484. IgnoreSetPos = FALSE;
  485. }
  486. break;
  487. case PBM_SETRANGE:
  488. case PBM_SETRANGE32:
  489. // did the phase not send the private message above
  490. if (!IgnoreSetRange)
  491. {
  492. // Are we not in the same phase?
  493. if (PreviousPhase != CurrentPhase)
  494. {
  495. PreviousPhase = CurrentPhase;
  496. // Get the new start and max position
  497. if (msg == PBM_SETRANGE32)
  498. {
  499. iCurrentPos = (int)wparam;
  500. iMaxPosition = (int)lparam;
  501. }
  502. else
  503. {
  504. iCurrentPos = LOWORD(lparam);
  505. iMaxPosition = HIWORD(lparam);
  506. }
  507. iStepSize = 10;
  508. // Calc the msec per tick and msec in this phase
  509. MsecPerProcessTick = ((SetupPhase[CurrentPhase].Time*1000)/(iMaxPosition - iCurrentPos) )+ 1;
  510. RemainungTimeMsecInThisPhase = (SetupPhase[CurrentPhase].Time * 1000);
  511. PreviousRemainingTime = RemainungTimeMsecInThisPhase;
  512. }
  513. else
  514. {
  515. // the same phase send more then one set range.
  516. // 1. don't change the remaining time, only recal the msecperprogresstick
  517. // 2. Ignore the next PBM_SETPOS message.
  518. //
  519. // Get the new start and max position
  520. if (msg == PBM_SETRANGE32)
  521. {
  522. iCurrentPos = (int)wparam;
  523. iMaxPosition = (int)lparam;
  524. }
  525. else
  526. {
  527. iCurrentPos = LOWORD(lparam);
  528. iMaxPosition = HIWORD(lparam);
  529. }
  530. iStepSize = 10;
  531. MsecPerProcessTick = (RemainungTimeMsecInThisPhase /(iMaxPosition - iCurrentPos) )+ 1;
  532. IgnoreSetPos = TRUE;
  533. }
  534. }
  535. else
  536. {
  537. // If we ignored the setrange, also ignore the first set pos.
  538. IgnoreSetPos = TRUE;
  539. }
  540. IgnoreSetRange = FALSE;
  541. break;
  542. case PBM_DELTAPOS:
  543. {
  544. int iDeltaPos = 0;
  545. // wparam has the # of ticks to move the gas gauge
  546. // make sure we don't over shoot the max posistion
  547. if ((iCurrentPos + (int)wparam) > iMaxPosition)
  548. {
  549. iDeltaPos = (iMaxPosition - iCurrentPos);
  550. }
  551. else
  552. {
  553. iDeltaPos = (int)wparam;
  554. }
  555. iCurrentPos += iDeltaPos;
  556. if ((iDeltaPos * MsecPerProcessTick) < RemainungTimeMsecInThisPhase)
  557. {
  558. RemainungTimeMsecInThisPhase -= (iDeltaPos * MsecPerProcessTick);
  559. }
  560. else
  561. {
  562. RemainungTimeMsecInThisPhase = 0;
  563. }
  564. UpdateTimeString(RemainungTimeMsecInThisPhase, &PreviousRemainingTime);
  565. }
  566. break;
  567. case PBM_STEPIT:
  568. {
  569. int iDeltaPos = 0;
  570. // make sure we don't over shoot the max posistion
  571. if ((iCurrentPos + iStepSize) > iMaxPosition)
  572. {
  573. iDeltaPos = (iMaxPosition - iCurrentPos);
  574. }
  575. else
  576. {
  577. iDeltaPos = iStepSize;
  578. }
  579. iCurrentPos += iDeltaPos;
  580. if ((iDeltaPos * MsecPerProcessTick) < RemainungTimeMsecInThisPhase)
  581. {
  582. RemainungTimeMsecInThisPhase -= (iDeltaPos * MsecPerProcessTick);
  583. }
  584. else
  585. {
  586. RemainungTimeMsecInThisPhase = 0;
  587. }
  588. UpdateTimeString(RemainungTimeMsecInThisPhase, &PreviousRemainingTime);
  589. }
  590. break;
  591. case PBM_SETSTEP:
  592. iStepSize = (int)wparam;
  593. break;
  594. }
  595. return BB_ProgressGaugeMsg(msg, wparam, lparam);
  596. }
  597. void UpdateTimeString(DWORD RemainungTimeMsecInThisPhase,
  598. DWORD *PreviousRemainingTime)
  599. {
  600. // If the previous displayed time is 1 minute old, update the time remaining.
  601. if ((*PreviousRemainingTime >= 60000) && ((*PreviousRemainingTime - 60000) > RemainungTimeMsecInThisPhase))
  602. {
  603. // Substract one minute.
  604. RemainingTime -= 60;
  605. *PreviousRemainingTime = RemainungTimeMsecInThisPhase;
  606. SetRemainingTime(RemainingTime);
  607. }
  608. }