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

500 lines
13 KiB
C

#include "precomp.h"
#pragma hdrstop
extern HWND hWndShell;
/*
** Pointer to top of Dialog Stack DBCB (dialog box context block).
*/
PDBCB GLOBAL(pdbcbTop) = NULL;
/*
** Purpose:
** To allocate enough storage to hold one DBCB (dialog box context block).
** Arguments:
** None.
** Returns:
** A Non-NULL pointer to a block of memory the size of one DBCB if
** allocation succeeds, NULL otherwise.
**
****************************************************************************/
PDBCB APIENTRY PdbcbAlloc()
{
PDBCB pdbcb;
if ((pdbcb = (PDBCB)SAlloc(sizeof(DBCB))) != (PDBCB)NULL)
{
pdbcb->szDlgName = (SZ)NULL;
pdbcb->hDlg = (HDLG)NULL;
pdbcb->lpprocDlg = (WNDPROC)NULL;
pdbcb->lpprocEventHandler = (PFNEVENT)NULL;
pdbcb->hDlgFocus = (HDLG)NULL;
pdbcb->szHelp = (SZ)NULL;
pdbcb->hDlgHelp = (HDLG)NULL;
pdbcb->lpprocHelp = (WNDPROC)NULL;
pdbcb->pdbcbNext = (PDBCB)NULL;
pdbcb->fActive = fFalse;
}
return(pdbcb);
}
/*
** Purpose:
** To free the storage occupied by one DBCB (dialog box context block).
** Arguments:
** pdbcb: A pointer to the DBCB.
** Returns:
** fFalse if the pdbcb is NULL or the operation fails, fTrue if the
** operation succeeds.
**
*****************************************************************************/
BOOL APIENTRY FFreeDbcb(pdbcb)
PDBCB pdbcb;
{
PreCondition(pdbcb != NULL, fFalse);
SFree(pdbcb);
return(fTrue);
}
/*
** Purpose:
** To push a dialog onto the dialog stack.
** Arguments:
** hinst: Handle to instance of the APP (i.e. the shell).
** szDlgName: Name of the dialog (e.g. GetDestPath, PrinterSelection).
** szDlgTemplate: Name of dialog template.
** hwndParent: Handle to the dialogs parent window (i.e. the shell).
** lpprocDlg: Procedure-instance address for the dialog procedure.
** lParam: 32-bit initialization value that will be passed to the
** dialog procedure when the dialog box is created.
** Currently unused by our general dialog procedures.
** lpprocEH: Procedure-instance address for the dialog event handler.
** szHelp: Name of Help dialog template associated with this dialog.
** lpprocHelp: Procedure-instance address for the help dlg procedure.
** Returns:
** A window handle to the dialog if the Push succeeds, NULL if it fails
** (i.e. if unable to allocate storage for the DBCB or the dialog creation
** fails.
**
****************************************************************************/
HDLG APIENTRY HdlgPushDbcb(hinst, szDlgName, szDlgTemplate,
hwndParent, lpprocDlg, lParam, lpprocEH, szHelp, lpprocHelp)
HANDLE hinst;
SZ szDlgName;
SZ szDlgTemplate;
HWND hwndParent;
WNDPROC lpprocDlg;
DWORD lParam;
PFNEVENT lpprocEH;
SZ szHelp;
WNDPROC lpprocHelp;
{
PDBCB pdbcb;
Unused(szHelp);
Unused(lpprocHelp);
AssertDataSeg();
ChkArg(hinst != NULL, 1, NULL);
ChkArg(szDlgTemplate != NULL, 2, NULL);
ChkArg(hwndParent != NULL, 4, NULL);
ChkArg(lpprocDlg != NULL, 5, NULL);
while ((pdbcb = PdbcbAlloc()) == NULL)
if (!FHandleOOM(hwndParent))
return(NULL);
if (szDlgName != NULL)
while ((pdbcb->szDlgName = SzDupl(szDlgName)) == (SZ)NULL)
if (!FHandleOOM(hwndParent))
return(NULL);
pdbcb->lpprocDlg = lpprocDlg;
pdbcb->lpprocEventHandler = lpprocEH;
pdbcb->pdbcbNext = GLOBAL(pdbcbTop);
if ((pdbcb->hDlg = HdlgCreateFillAndShowDialog(hinst, szDlgTemplate,
hwndParent, lpprocDlg, lParam)) != NULL)
{
//
// Disable the main app window
//
EnableWindow( hWndShell, fFalse );
FFlashParentWindow( fFalse ) ;
//
// If there is a dialog on the stack disable it too
//
if (GLOBAL(pdbcbTop) != NULL) {
FDisableDialog(GLOBAL(pdbcbTop)->hDlg);
}
GLOBAL(pdbcbTop) = pdbcb;
//
// Set this window as the active window
//
//SetActiveWindow( pdbcb->hDlg );
SetForegroundWindow(pdbcb->hDlg);
}
return(pdbcb->hDlg);
}
/*
** Purpose:
** To pop a dialog from the dialog stack and free the storage occupied by
** the DBCB(dialog box context block).
** Arguments:
** None.
** Returns:
** fFalse if the stack is empty, fTrue otherwise.
**
****************************************************************************/
BOOL APIENTRY FPopDbcb()
{
PDBCB pdbcbTemp = GLOBAL(pdbcbTop);
AssertDataSeg();
// changed so that we no longer fail if there's nothing to pop (lonnym)
// PreCondition(GLOBAL(pdbcbTop) != NULL, fFalse);
if(GLOBAL(pdbcbTop) == NULL) {
return(fTrue);
}
//
// Enable the shell window till we have another dialog active
//
EnableWindow( hWndShell, fTrue );
//
// If the dialog stack is empty, flash the parent app's window
// if there is one.
//
if ( GLOBAL(pdbcbTop)->pdbcbNext == NULL )
{
FFlashParentWindow( fTrue ) ;
}
EvalAssert(FCloseDialog(GLOBAL(pdbcbTop)->hDlg));
if (GLOBAL(pdbcbTop)->szDlgName != NULL) {
SFree(GLOBAL(pdbcbTop)->szDlgName);
}
GLOBAL(pdbcbTop) = GLOBAL(pdbcbTop)->pdbcbNext;
EvalAssert(FFreeDbcb(GLOBAL(pdbcbTemp)));
return(fTrue);
}
/*
** Purpose:
** To pop N dialogs from the dialog stack and free the storage associated
** with the N DBCB's (dialog box context blocks).
** Arguments:
** n: The non-negative number of dialogs to be popped from the stack.
** Returns:
** fTrue if n == 0 or the n'th Pops succeeds, fFalse otherwise.
**
****************************************************************************/
BOOL APIENTRY FPopNDbcb(cDlgs)
INT cDlgs;
{
AssertDataSeg();
ChkArg(cDlgs >= 0, 1, fFalse);
if (cDlgs == 0)
return(fTrue);
while(--cDlgs != 0)
EvalAssert(FPopDbcb());
return(FPopDbcb());
}
/*
** Purpose:
** To preprocess messages sent to the main app window (i.e. the shell) that
** have special significance to the UI component. This function must be
** inserted in the message loop in the app's WinMain. The message should
** be passed to TranslateMessage or DispatchMessage if and only if
** FUiLibFilter returns fTrue.
** Arguments:
** pmsg: points to a MSG data structure that contains the message to be
** checked.
** Returns:
** fTrue if the message should also be passed to TranslateMessage and
** DispatchMessage, and fFalse otherwise.
**
****************************************************************************/
BOOL APIENTRY FUiLibFilter(pmsg)
MSG * pmsg;
{
HDLG hDlg;
HDLG hDlgHelp;
AssertDataSeg();
switch(pmsg->message)
{
// case WM_SETFOCUS:
// if(GLOBAL(pdbcbTop) != NULL)
// SetFocus(GLOBAL(pdbcbTop)->hDlg);
// break;
// case WM_KEYDOWN:
// if (pmsg->wParam == VK_TAB && GetKeyState(VK_CONTROL) < 0)
// {
// EvalAssert(FToggleDlgActivation());
// return(fFalse);
// }
// break;
case WM_SYSCOMMAND:
if (pmsg->wParam == SC_CLOSE && GLOBAL(pdbcbTop) != NULL)
{
// if (GLOBAL(pdbcbTop)->hDlgHelp != NULL)
// SendMessage(GLOBAL(pdbcbTop)->hDlgHelp, WM_SYSCOMMAND, SC_CLOSE,
// pmsg->lParam);
// else
SendMessage(GLOBAL(pdbcbTop)->hDlg, WM_SYSCOMMAND, SC_CLOSE,
pmsg->lParam);
return(fFalse);
}
break;
}
if (pdbcbTop == NULL)
hDlg = hDlgHelp = NULL;
else
{
hDlg = GLOBAL(pdbcbTop)->hDlg;
hDlgHelp = NULL;
// hDlgHelp = GLOBAL(pdbcbTop)->hDlgHelp;
}
return(((hDlg == 0 || !IsDialogMessage(hDlg, pmsg)) &&
(hDlgHelp == 0 || !IsDialogMessage(hDlgHelp, pmsg))));
}
/*
** Purpose:
** To activate and enable the dialog on the top of the stack. This is
** used after the dialog stack has been popped to resume the previously
** inactive dialog.
** Arguments:
** None.
** Returns:
** fFalse if the stack is empty, fTrue otherwise.
**
****************************************************************************/
BOOL APIENTRY FResumeStackTop()
{
AssertDataSeg();
PreCondition(GLOBAL(pdbcbTop) != NULL, fFalse);
EnableWindow( hWndShell, fFalse );
FFlashParentWindow( fFalse );
FEnableDialog(GLOBAL(pdbcbTop)->hDlg); /* do not EvalAssert */
SetActiveWindow(GLOBAL(pdbcbTop)->hDlg);
// EvalAssert(FActivateStackTop());
return(fTrue);
}
/*
** Purpose:
** To get the name of the dialog on the top of the dialog stack.
** Arguments:
** None.
** Returns:
** NULL if the stack is empty, the sz that is the name of the top-of-stack
** dialog otherwise.
**
*****************************************************************************/
SZ APIENTRY SzStackTopName()
{
AssertDataSeg();
if (GLOBAL(pdbcbTop) == NULL)
return(NULL);
else
return(GLOBAL(pdbcbTop)->szDlgName);
}
/*
** Purpose:
** Called by the main app (i.e. the shell) to handle the events that can
** occur while executing the top-of-stack dialog. The events can
** optionally be preprocessed by a specific event handler for the dialog.
** The standard events (continue, back, help, exit) can be handled
** directly.
** Arguments:
** hInst: Handle to instance of the APP (i.e. the shell).
** hwndShell: Handle to the main app window (i.e. the shell).
** wMsg: UI-Lib defined messages indicating what event occurred.
** wParam: the wParam associated with the message wMsg.
** lParam: the lParam associated with the message wMsg.
** Notes:
** This processes button events by getting the associated value for
** $(ButtonPressed) from the Symbol Table (set by the standard dialogs)
** and, if that value equals IDC_C, IDC_B, or IDC_X, setting the
** value associated with the symbol $(DLGEVENT) to either "CONTINUE",
** "BACK", or "EXIT" respectively.
** Returns:
** fTrue if the event was handled, fFalse otherwise or if the stack is
** empty.
**
*****************************************************************************/
BOOL APIENTRY FGenericEventHandler(HANDLE hInst, HWND hwndShell,
UINT wMsg, WPARAM wParam, LPARAM lParam)
{
PFNEVENT pfnEvent;
EHRC ehrc = ehrcNotHandled;
AssertDataSeg();
PreCondition(GLOBAL(pdbcbTop) != NULL, fFalse);
if (GLOBAL(pdbcbTop)->lpprocEventHandler != NULL)
{
pfnEvent = (PFNEVENT)GLOBAL(pdbcbTop)->lpprocEventHandler;
ehrc = (*pfnEvent)(hInst, hwndShell, wMsg, wParam, lParam);
}
if (ehrc == ehrcNotHandled)
{
SZ szEvent;
ehrc = ehrcPostInterp;
EvalAssert((szEvent= SzFindSymbolValueInSymTab("ButtonPressed"))!=NULL);
switch (atoi(szEvent))
{
case IDC_C:
szEvent = "CONTINUE";
break;
case IDCANCEL:
case IDC_B:
szEvent = "BACK";
break;
case IDC_H:
szEvent = "HELP";
break;
case IDC_X:
szEvent = "EXIT";
break;
case IDC_M:
szEvent = "FREEBUTTON1";
break;
case IDC_O:
szEvent = "FREEBUTTON2";
break;
case IDC_BTN0:
case IDC_BTN1: case IDC_BTN2: case IDC_BTN3:
case IDC_BTN4: case IDC_BTN5: case IDC_BTN6:
case IDC_BTN7: case IDC_BTN8: case IDC_BTN9:
{
SZ butns[10] = {"DLGBUTTON0",
"DLGBUTTON1", "DLGBUTTON2", "DLGBUTTON3",
"DLGBUTTON4", "DLGBUTTON5", "DLGBUTTON6",
"DLGBUTTON7", "DLGBUTTON8", "DLGBUTTON9",
};
szEvent = butns[atoi(szEvent) - IDC_BTN0];
}
break;
default:
szEvent = (SZ)NULL;
ehrc = ehrcError;
break;
}
if (szEvent != (SZ)NULL)
{
while (!FAddSymbolValueToSymTab("DLGEVENT", szEvent))
if (!FHandleOOM(hwndShell))
ehrc = ehrcError;
}
}
if (ehrc == ehrcPostInterp)
PostMessage(hwndShell, (WORD)STF_SHL_INTERP, 0, 0L);
return(ehrc != ehrcError);
}
/*
** Purpose:
** To check if the stack is empty.
** Arguments:
** None.
** Returns:
** fTrue if the stack is empty, fFalse otherwise.
**
*****************************************************************************/
BOOL APIENTRY FStackEmpty()
{
AssertDataSeg();
return(!GLOBAL(pdbcbTop));
}
/*
** Purpose:
** To get the handle of the dialog on the top of the stack.
** Arguments:
** None.
** Returns:
** The handle to the dialog on the top of the stack, or NULL if the
** stack is empty.
**
*****************************************************************************/
HDLG APIENTRY HdlgStackTop()
{
AssertDataSeg();
if (GLOBAL(pdbcbTop) == (PDBCB)NULL)
return((HDLG)NULL);
return((GLOBAL(pdbcbTop))->hDlg);
}