windows-nt/Source/XPSP1/NT/base/ntsetup/syssetup/billbrd.c
2020-09-26 16:20:57 +08:00

699 lines
20 KiB
C

/*++
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);
}
}