/*++ Copyright (c) 1995 Microsoft Corporation Module Name: billbrd.c Abstract: Routines for displaying Windows that are static in nature. Author: Ted Miller (tedm) 8-Jun-1995 Revision History: --*/ #include "setupp.h" #pragma hdrstop // // Define structure we pass around to describe a billboard. // typedef struct _BILLBOARD_PARAMS { UINT MessageId; va_list *arglist; HWND Owner; DWORD NotifyThreadId; } BILLBOARD_PARAMS, *PBILLBOARD_PARAMS; // // Custom window messages // #define WMX_BILLBOARD_DISPLAYED (WM_USER+243) #define WMX_BILLBOARD_TERMINATE (WM_USER+244) #define ID_REBOOT_TIMER 10 // // Import the entry point used to check whether setup is executing within an // ASR context. // extern BOOL AsrIsEnabled( VOID ); INT_PTR BillboardDlgProc( IN HWND hdlg, IN UINT msg, IN WPARAM wParam, IN LPARAM lParam ) { static BOOL Initializing; HWND Animation = GetDlgItem(hdlg,IDA_SETUPINIT); static HANDLE hBitmap; static HCURSOR hCursor; switch(msg) { case WM_INITDIALOG: { PBILLBOARD_PARAMS BillParams; PWSTR p; BOOL b; BillParams = (PBILLBOARD_PARAMS)lParam; if(BillParams->MessageId == MSG_INITIALIZING) { Initializing = TRUE; b = TRUE; hCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) ); ShowCursor( TRUE ); Animate_Open(Animation,MAKEINTRESOURCE(IDA_SETUPINIT)); hBitmap = LoadBitmap (MyModuleHandle, MAKEINTRESOURCE(IDB_INIT_WORKSTATION)); SendDlgItemMessage(hdlg,IDC_BITMAP,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)hBitmap); } else { Initializing = FALSE; if(p = RetrieveAndFormatMessageV(SETUPLOG_USE_MESSAGEID, BillParams->MessageId,BillParams->arglist)) { b = SetDlgItemText(hdlg,IDT_STATIC_1,p); MyFree(p); } else { b = FALSE; } } if(b) { // // Center the billboard relative to the window that owns it. // // if we have the BB window, do the positioning on that. // MainWindowHandle point to that window // if (GetBBhwnd()) CenterWindowRelativeToWindow(hdlg, MainWindowHandle, FALSE); else pSetupCenterWindowRelativeToParent(hdlg); // // Post ourselves a message that we won't get until we've been // actually displayed on the screen. Then when we process that message, // we inform the thread that created us that we're up. Note that // once that notification has been made, the BillParams we're using // now will go away since they are stored in local vars (see // DisplayBillboard()). // PostMessage(hdlg,WMX_BILLBOARD_DISPLAYED,0,(LPARAM)BillParams->NotifyThreadId); // // Tell Windows not to process this message. // return(FALSE); } else { // // We won't post the message, but returning -1 will get the // caller of DialogBox to post it for us. // EndDialog(hdlg,-1); } } break; case WMX_BILLBOARD_DISPLAYED: if(Initializing) { Animate_Play(Animation,0,-1,-1); } PostThreadMessage( (DWORD)lParam, WMX_BILLBOARD_DISPLAYED, TRUE, (LPARAM)hdlg ); break; case WMX_BILLBOARD_TERMINATE: if(Initializing) { SetCursor( hCursor ); ShowCursor( FALSE ); Animate_Stop(Animation); Animate_Close(Animation); DeleteObject(hBitmap); } EndDialog(hdlg,0); break; default: return(FALSE); } return(TRUE); } DWORD BillboardThread( IN PVOID ThreadParam ) { PBILLBOARD_PARAMS BillboardParams; INT_PTR i; BillboardParams = ThreadParam; // // For the "initializing" case, we use a different dialog. // if( AsrIsEnabled() ) { i = DialogBoxParam( MyModuleHandle, (BillboardParams->MessageId == MSG_INITIALIZING) ? MAKEINTRESOURCE(IDD_SETUPINIT_ASR) : MAKEINTRESOURCE(IDD_BILLBOARD1), BillboardParams->Owner, BillboardDlgProc, (LPARAM)BillboardParams ); } else { i = DialogBoxParam( MyModuleHandle, (BillboardParams->MessageId == MSG_INITIALIZING) ? MAKEINTRESOURCE(IDD_SETUPINIT) : MAKEINTRESOURCE(IDD_BILLBOARD1), BillboardParams->Owner, BillboardDlgProc, (LPARAM)BillboardParams ); } // // If the dialog box call failed, we have to tell the // main thread about it here. Otherwise the dialog proc // tells the main thread. // if(i == -1) { PostThreadMessage( BillboardParams->NotifyThreadId, WMX_BILLBOARD_DISPLAYED, FALSE, (LPARAM)NULL ); } return(0); } HWND DisplayBillboard( IN HWND Owner, IN UINT MessageId, ... ) { HANDLE ThreadHandle; DWORD ThreadId; BILLBOARD_PARAMS ThreadParams; va_list arglist; HWND hwnd; MSG msg; hwnd = NULL; // If we have a billboard, we should not need this. dialog. if (GetBBhwnd() == NULL) { va_start(arglist,MessageId); // // The billboard will exist in a separate thread so it will // always be responsive. // ThreadParams.MessageId = MessageId; ThreadParams.arglist = &arglist; ThreadParams.Owner = Owner; ThreadParams.NotifyThreadId = GetCurrentThreadId(); ThreadHandle = CreateThread( NULL, 0, BillboardThread, &ThreadParams, 0, &ThreadId ); if(ThreadHandle) { // // Wait for the billboard to tell us its window handle // or that it failed to display the billboard dialog. // do { GetMessage(&msg,NULL,0,0); if(msg.message == WMX_BILLBOARD_DISPLAYED) { if(msg.wParam) { hwnd = (HWND)msg.lParam; Sleep(1500); // let the user see it even on fast machines } } else { DispatchMessage(&msg); } } while(msg.message != WMX_BILLBOARD_DISPLAYED); CloseHandle(ThreadHandle); } va_end(arglist); } else { // Start BB text StartStopBB(TRUE); } return(hwnd); } VOID KillBillboard( IN HWND BillboardWindowHandle ) { if(BillboardWindowHandle && IsWindow(BillboardWindowHandle)) { PostMessage(BillboardWindowHandle,WMX_BILLBOARD_TERMINATE,0,0); } } INT_PTR DoneDlgProc( IN HWND hdlg, IN UINT msg, IN WPARAM wParam, IN LPARAM lParam ) { PWSTR p; static UINT Countdown; switch(msg) { case WM_INITDIALOG: // if we have the BB window, do the positioning on that. MainWindowHandle point to that window if (GetBBhwnd()) CenterWindowRelativeToWindow(hdlg, MainWindowHandle, FALSE); else pSetupCenterWindowRelativeToParent(hdlg); SendDlgItemMessage( hdlg, IDOK, BM_SETIMAGE, 0, (LPARAM)LoadBitmap(MyModuleHandle,MAKEINTRESOURCE(IDB_REBOOT)) ); if(p = RetrieveAndFormatMessage(NULL,(UINT)lParam)) { SetDlgItemText(hdlg,IDT_STATIC_1,p); MyFree(p); } Countdown = 15 * 10; SendDlgItemMessage(hdlg,IDC_PROGRESS1,PBM_SETRANGE,0,MAKELONG(0,Countdown)); SendDlgItemMessage(hdlg,IDC_PROGRESS1,PBM_SETSTEP,1,0); SendDlgItemMessage(hdlg,IDC_PROGRESS1,PBM_SETPOS,0,0); SetTimer(hdlg,ID_REBOOT_TIMER,100,NULL); SetFocus(GetDlgItem(hdlg,IDOK)); return(FALSE); case WM_TIMER: Countdown--; if(Countdown) { SendDlgItemMessage(hdlg,IDC_PROGRESS1,PBM_STEPIT,0,0); } else { KillTimer(hdlg,ID_REBOOT_TIMER); DeleteObject((HGDIOBJ)SendDlgItemMessage(hdlg,IDOK,BM_GETIMAGE,0,0)); EndDialog(hdlg,0); } break; case WM_COMMAND: if((HIWORD(wParam) == BN_CLICKED) && (LOWORD(wParam) == IDOK)) { KillTimer(hdlg,ID_REBOOT_TIMER); DeleteObject((HGDIOBJ)SendDlgItemMessage(hdlg,IDOK,BM_GETIMAGE,0,0)); EndDialog(hdlg,0); } else { return(FALSE); } break; default: return(FALSE); } return(TRUE); } typedef BOOL (CALLBACK *STOPBILLBOARD)(); typedef BOOL (CALLBACK *STARTBILLBOARD)(); typedef BOOL (WINAPI* SETTIMEESTIMATE)(LPCTSTR szText); typedef BOOL (WINAPI* SETPROGRESSTEXT)(LPCTSTR szText); typedef BOOL (WINAPI* SETINFOTEXT)(LPCTSTR szText); typedef LRESULT (WINAPI* PROGRESSGAUGEMSG)(UINT msg, WPARAM wparam, LPARAM lparam); typedef BOOL (WINAPI* SHOWPROGRESSGAUGEWINDOW)(UINT uiShow); BOOL BB_ShowProgressGaugeWnd(UINT nCmdShow) { static SHOWPROGRESSGAUGEWINDOW fpShowGauge = NULL; BOOL bRet = FALSE; if (fpShowGauge == NULL) { if (hinstBB) { fpShowGauge = (SHOWPROGRESSGAUGEWINDOW )GetProcAddress(hinstBB, "ShowProgressGaugeWindow"); } } if (fpShowGauge != NULL) { bRet = fpShowGauge(nCmdShow); } return bRet; } LRESULT BB_ProgressGaugeMsg(UINT msg, WPARAM wparam, LPARAM lparam) { static PROGRESSGAUGEMSG fpProgressGaugeMsg = NULL; LRESULT lresult = 0; if (fpProgressGaugeMsg == NULL) { if (hinstBB) { fpProgressGaugeMsg = (PROGRESSGAUGEMSG )GetProcAddress(hinstBB, "ProgressGaugeMsg"); } } if (fpProgressGaugeMsg != NULL) { lresult = fpProgressGaugeMsg(msg, wparam, lparam); } return lresult; } void BB_SetProgressText(LPCTSTR szText) { static SETPROGRESSTEXT fpSetProgressText = NULL; if (fpSetProgressText == NULL) { if (hinstBB) { fpSetProgressText = (SETPROGRESSTEXT )GetProcAddress(hinstBB, "SetProgressText"); } } if (fpSetProgressText != NULL) { fpSetProgressText(szText); } } void BB_SetInfoText(LPTSTR szText) { static SETINFOTEXT fpSetInfoText = NULL; if (fpSetInfoText == NULL) { if (hinstBB) { fpSetInfoText = (SETINFOTEXT )GetProcAddress(hinstBB, "SetInfoText"); } } if (fpSetInfoText != NULL) { fpSetInfoText(szText); } } void BB_SetTimeEstimateText(LPTSTR szText) { static SETTIMEESTIMATE fpSetTimeEstimate = NULL; if (fpSetTimeEstimate == NULL) { if (hinstBB) { fpSetTimeEstimate = (SETTIMEESTIMATE)GetProcAddress(hinstBB, "SetTimeEstimate"); } } if (fpSetTimeEstimate != NULL) { fpSetTimeEstimate(szText); } } BOOL StartStopBB(BOOL bStart) { static STARTBILLBOARD fpStart = NULL; static STOPBILLBOARD fpStop = NULL; BOOL bRet = FALSE; if ((fpStart == NULL) || (fpStop == NULL)) { if (hinstBB) { fpStop = (STARTBILLBOARD )GetProcAddress(hinstBB, "StopBillBoard"); fpStart = (STOPBILLBOARD )GetProcAddress(hinstBB, "StartBillBoard"); } } if ((fpStart != NULL) && (fpStop != NULL)) { if (bStart) bRet = fpStart(); else bRet = fpStop(); } return bRet; } LRESULT ProgressGaugeMsgWrapper(UINT msg, WPARAM wparam, LPARAM lparam) { static DWORD MsecPerProcessTick; static DWORD PreviousRemainingTime = 0; static DWORD RemainungTimeMsecInThisPhase = 0; static int iCurrentPos = 0; static int iMaxPosition = 0; static int iStepSize = 0; static UINT PreviousPhase = Phase_Unknown; static BOOL IgnoreSetRange = FALSE; static BOOL IgnoreSetPos = FALSE; DWORD dwDeltaTicks = 0; switch (msg) { case WMX_PROGRESSTICKS: // If we get a WMX_PROGRESSTICKS before a PBM_SETRANGE, ignore the set range // This should be use if the progress bar only takes up x% of the whole bar. // In this case the phase sends PBM_SETRANGE and a PBM_SETPOS to setup the // progress values for it's part of the gauge. IgnoreSetRange = TRUE; if (PreviousPhase != CurrentPhase) { PreviousPhase = CurrentPhase; iCurrentPos = 0; iMaxPosition = (int)wparam; iStepSize = 10; MsecPerProcessTick = ((SetupPhase[CurrentPhase].Time*1000)/(iMaxPosition - iCurrentPos) )+ 1; RemainungTimeMsecInThisPhase = (SetupPhase[CurrentPhase].Time * 1000); PreviousRemainingTime = RemainungTimeMsecInThisPhase; } else { // what to do if the same phase send more then one set range. // don't change the remaining time, only recal the msecperprogresstick // iCurrentPos = 0; iMaxPosition = (int)wparam; iStepSize = 10; MsecPerProcessTick = (RemainungTimeMsecInThisPhase /(iMaxPosition - iCurrentPos) )+ 1; } break; case PBM_SETPOS: { UINT uiCurrentPos; if (!IgnoreSetPos) { int iDeltaPos = 0; // Find out where the current position of the gasgauge is. // The difference is the #ticks we use to reduce the time estimate uiCurrentPos = (UINT)BB_ProgressGaugeMsg(PBM_GETPOS, 0, 0); // See if there is a difference in the current position and the one // we think we are in. // Only if the new position is greater then the current one // calc the difference and substract from remaining time. if ((UINT)wparam > uiCurrentPos) { iDeltaPos = (UINT)wparam - uiCurrentPos; iCurrentPos += iDeltaPos; // Only substract if more time left if ((iDeltaPos * MsecPerProcessTick) < RemainungTimeMsecInThisPhase) { RemainungTimeMsecInThisPhase -= (iDeltaPos * MsecPerProcessTick); } else { RemainungTimeMsecInThisPhase = 0; } UpdateTimeString(RemainungTimeMsecInThisPhase, &PreviousRemainingTime); } } IgnoreSetPos = FALSE; } break; case PBM_SETRANGE: case PBM_SETRANGE32: // did the phase not send the private message above if (!IgnoreSetRange) { // Are we not in the same phase? if (PreviousPhase != CurrentPhase) { PreviousPhase = CurrentPhase; // Get the new start and max position if (msg == PBM_SETRANGE32) { iCurrentPos = (int)wparam; iMaxPosition = (int)lparam; } else { iCurrentPos = LOWORD(lparam); iMaxPosition = HIWORD(lparam); } iStepSize = 10; // Calc the msec per tick and msec in this phase MsecPerProcessTick = ((SetupPhase[CurrentPhase].Time*1000)/(iMaxPosition - iCurrentPos) )+ 1; RemainungTimeMsecInThisPhase = (SetupPhase[CurrentPhase].Time * 1000); PreviousRemainingTime = RemainungTimeMsecInThisPhase; } else { // the same phase send more then one set range. // 1. don't change the remaining time, only recal the msecperprogresstick // 2. Ignore the next PBM_SETPOS message. // // Get the new start and max position if (msg == PBM_SETRANGE32) { iCurrentPos = (int)wparam; iMaxPosition = (int)lparam; } else { iCurrentPos = LOWORD(lparam); iMaxPosition = HIWORD(lparam); } iStepSize = 10; MsecPerProcessTick = (RemainungTimeMsecInThisPhase /(iMaxPosition - iCurrentPos) )+ 1; IgnoreSetPos = TRUE; } } else { // If we ignored the setrange, also ignore the first set pos. IgnoreSetPos = TRUE; } IgnoreSetRange = FALSE; break; case PBM_DELTAPOS: { int iDeltaPos = 0; // wparam has the # of ticks to move the gas gauge // make sure we don't over shoot the max posistion if ((iCurrentPos + (int)wparam) > iMaxPosition) { iDeltaPos = (iMaxPosition - iCurrentPos); } else { iDeltaPos = (int)wparam; } iCurrentPos += iDeltaPos; if ((iDeltaPos * MsecPerProcessTick) < RemainungTimeMsecInThisPhase) { RemainungTimeMsecInThisPhase -= (iDeltaPos * MsecPerProcessTick); } else { RemainungTimeMsecInThisPhase = 0; } UpdateTimeString(RemainungTimeMsecInThisPhase, &PreviousRemainingTime); } break; case PBM_STEPIT: { int iDeltaPos = 0; // make sure we don't over shoot the max posistion if ((iCurrentPos + iStepSize) > iMaxPosition) { iDeltaPos = (iMaxPosition - iCurrentPos); } else { iDeltaPos = iStepSize; } iCurrentPos += iDeltaPos; if ((iDeltaPos * MsecPerProcessTick) < RemainungTimeMsecInThisPhase) { RemainungTimeMsecInThisPhase -= (iDeltaPos * MsecPerProcessTick); } else { RemainungTimeMsecInThisPhase = 0; } UpdateTimeString(RemainungTimeMsecInThisPhase, &PreviousRemainingTime); } break; case PBM_SETSTEP: iStepSize = (int)wparam; break; } return BB_ProgressGaugeMsg(msg, wparam, lparam); } void UpdateTimeString(DWORD RemainungTimeMsecInThisPhase, DWORD *PreviousRemainingTime) { // If the previous displayed time is 1 minute old, update the time remaining. if ((*PreviousRemainingTime >= 60000) && ((*PreviousRemainingTime - 60000) > RemainungTimeMsecInThisPhase)) { // Substract one minute. RemainingTime -= 60; *PreviousRemainingTime = RemainungTimeMsecInThisPhase; SetRemainingTime(RemainingTime); } }