/****************************** Module Header ******************************\
* Module Name: timeout.c
*
* Copyright (c) 1991, Microsoft Corporation
*
* Support routines to implement dialog input timeouts
*
* History:
* 12-05-91 Davidc Created.
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
//
// Define private notification message sent to dialogs on an interrupt
//
#define WM_DLG_INTERRUPT (WM_USER+600)
//
// Define value returned by a message box or dialog box when interrupted
// This value must be interpreted using the InterrruptType variable
//
#define DLG_INTERRUPT 0 // Must be 0 so we can return it from message boxes
//
// Define the maximum number of nested dialogs we can handle
//
#define MAX_NESTED_TIMEOUTS 5
#define TIMEOUT_DEFAULT 120
//
// Globals - these will need to put in an instance data structure
// when we have multiple logon threads
//
//
// Define array used to store window handles who ask for timeout service.
// This array is used as a push down stack to suppport nested timeouts
//
HWND hwndArray[MAX_NESTED_TIMEOUTS];
TIMEOUT TimeoutArray[MAX_NESTED_TIMEOUTS];
PGLOBALS GlobalsArray[MAX_NESTED_TIMEOUTS];
LONG NestedIndex = 0;
//
// Variable that stores the required return code for the top dialog.
// This is only used if we force a dialog to return DLG_INTERRUPT.
// We have to use this mechanism because message boxes will not allow
// you to return any random value. DLG_INTERRUPT is 0 which message
// boxes let through.
//
int TopDialogReturnCode = DLG_INTERRUPT;
HWND hwndMessageOwner = NULL;// Store the owner of the message box
// we want to find
LPTSTR TimeoutTitle = NULL; // Stores the title of the message box we
// are going to timeout on.
BOOL InputHooksInstalled = FALSE;
BOOL TimeoutOccurred = FALSE;
BOOL DialogActive = FALSE;
//
// Variables that support the input timeout
//
int TimerID = 0;
HHOOK hhkMouse;
HHOOK hhkKeyboard;
//
// Internal Prototypes
//
BOOL PushMessageTimeout(HWND hwndOwner, TIMEOUT TimeDelay, LPTSTR Title, PGLOBALS pGlobals);
BOOL PopMessageTimeout(VOID);
BOOL PushTimeout(HWND hwnd, TIMEOUT TimeDelay, PGLOBALS pGlobals);
BOOL PopTimeout(VOID);
BOOL StartTopTimeout(VOID);
HWND GetTopTimeout(PTIMEOUT pTimeDelay);
BOOL SetTopTimeout(HWND hwnd);
BOOL SetTimeout(TIMEOUT TimeDelay);
BOOL CheckTimeout(HWND hwnd);
BOOL SetInputHooks(VOID);
BOOL ReleaseInputHooks(VOID);
LRESULT WINAPI MouseHookfn(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT WINAPI KeyboardHookfn(int nCode, WPARAM wParam, LPARAM lParam);
BOOL StartTimer(TIMEOUT TimeDelay);
WORD WINAPI Timerfn(HWND hwnd, WORD Message, int IDEvent, DWORD dwTime);
BOOL StopTimer(VOID);
BOOL FindMessageBox(VOID);
BOOL WINAPI FindEnumfn(HWND, LPARAM);
TIMEOUT InheritTimeout(TIMEOUT TimeDelay);
BOOL HandleScreenSaverTimeout(HWND hwndTop, TIMEOUT Timeout);
BOOL HandleUserLogoff(PGLOBALS pGlobals, HWND hwndTop, TIMEOUT Timeout, LONG Flags);
/***************************************************************************\
* ForwardMessage
*
* Sends a message to the window on top of the timeout stack
*
* 12-05-91 Davidc Created.
\***************************************************************************/
#if 0
LONG
ForwardMessage(
PGLOBALS pGlobals,
UINT Message,
WPARAM wParam,
LPARAM lParam
)
{
TIMEOUT Timeout;
HWND hwndTop = GetTopTimeout(&Timeout);
// If there is nothing on the stack, dump the message
if (hwndTop == NULL) {
DebugLog((DEB_ERROR, "No-one on the stack to forward message to !"));
ASSERT(FALSE);
return(0);
}
switch (Message) {
case WM_SAS:
SendMessage(hwndTop, Message, wParam, lParam);
break;
case WM_INPUT_TIMEOUT:
// Check the timeout condition still exists and exit the dialog
if (CheckTimeout(hwndTop)) {
EndTopDialog(hwndTop, DLG_INPUT_TIMEOUT);
}
break;
case WM_SCREEN_SAVER_TIMEOUT:
//
// Ignore if the current user doesn't have an enabled screen-saver.
// The timeout notification may have been in the message queue when
// we changed user - the new user may not have a screen-saver.
//
if (ScreenSaverEnabled(pGlobals)) {
HandleScreenSaverTimeout(hwndTop, Timeout);
}
break;
case WM_USER_LOGOFF:
HandleUserLogoff(pGlobals, hwndTop, Timeout, lParam);
break;
default:
DebugLog((DEB_ERROR, "Unexpected message supplied to ForwardMessage"));
ASSERT(FALSE);
break;
}
return(0);
}
/***************************************************************************\
* HandleScreenSaverTimeout
*
* Deal with a screen-saver timeout notification from windows.
*
* If the topmost window has a timeout, the screen-saver timeout simply
* interrupts the dialog and causes it to return DLG_SCREEN_SAVER_TIMEOUT.
*
* If the topmost window has no timeout, the window stack is searched from
* the top for the first window to have the TIMEOUT_SS_NOTIFY bit set.
* This window is then sent a WM_SCREEN_SAVER_TIMEOUT message.
* This allows a non-timeout window to take responsibility for starting
* the screen-saver from any-non timeout windows above it.
*
* Returns TRUE
*
* 12-05-91 Davidc Created.
\***************************************************************************/
BOOL
HandleScreenSaverTimeout(
HWND hwndTop,
TIMEOUT Timeout
)
{
HWND hwndNotify;
LONG Index;
//
// If top top window has a timeout, it should be interrupted
//
if (TIMEOUT_VALUE(Timeout) != TIMEOUT_NONE) {
EndTopDialog(hwndTop, DLG_SCREEN_SAVER_TIMEOUT);
return(TRUE); // We're done
}
//
// The top window has no timeout, search for window with notify bit set
//
for (Index = NestedIndex - 1; Index >= 0; Index --) {
if (TIMEOUT_NOTIFY(TimeoutArray[Index])) {
// Found a window with the notify bit set
break;
}
}
// Q.A.
ASSERTMSG("Notify window not found on timeout stack", Index >= 0);
ASSERTMSG("Found notify window with a non-zero timeout !!",
TIMEOUT_VALUE(TimeoutArray[Index]) == TIMEOUT_NONE);
hwndNotify = hwndArray[Index];
ASSERTMSG("Found notify window with a NULL hwnd !!", hwndNotify != NULL);
//
// Forward the message to the notify window
//
SendMessage(hwndNotify, WM_SCREEN_SAVER_TIMEOUT, 0, 0);
return(TRUE); // We've dealt with it
}
#endif
/***************************************************************************\
* MapResultCode
*
* Maps the DLG_INTERRUPT message to the appropriate return code stored
* in TopDialogReturnCode
*
* 03-17-92 Davidc Created.
\***************************************************************************/
int
MapResultCode(
int Result,
int TopDialogReturnCode
)
{
if (Result == DLG_INTERRUPT) {
ASSERT(TopDialogReturnCode != DLG_INTERRUPT);
Result = TopDialogReturnCode;
#if DBG
//
// Reset the stored return code so we can detect if an interrupt is
// generated without the code being set correctly.
//
TopDialogReturnCode = DLG_INTERRUPT;
#endif
}
if (Result == -1) {
DebugLog((DEB_ERROR, "Failed to create dialog or message box"));
}
return(Result);
}
/***************************************************************************\
* ProcessDialogTimeout
*
* Called as first part of dialog routine that wants to timeout after
* there is no input for a specified time. Simply sets up the hwnd on top
* of our stack.
*
* 12-05-91 Davidc Created.
\***************************************************************************/
VOID ProcessDialogTimeout(
HWND hwnd,
UINT Message,
DWORD wParam,
LONG lParam)
{
switch (Message) {
case WM_INITDIALOG:
if (!SetTopTimeout(hwnd)) {
DebugLog((DEB_ERROR, "ProcessDialogTimeout failed to set the hwnd on top of the timeout stack"));
}
}
DBG_UNREFERENCED_PARAMETER(Message);
DBG_UNREFERENCED_PARAMETER(wParam);
DBG_UNREFERENCED_PARAMETER(lParam);
}
/***************************************************************************\
* PushDialogTimeout
*
* Sets up an input timeout for the dialog box that is just about to be created
*
* Returns TRUE on success, FALSE on failure
*
* 12-05-91 Davidc Created.
\***************************************************************************/
BOOL PushDialogTimeout(
TIMEOUT TimeDelay,
PGLOBALS pGlobals)
{
TimeDelay = InheritTimeout(TimeDelay);
// Push the timeout with a NULL hwnd (to be filled in later)
PushTimeout(NULL, TimeDelay, pGlobals);
return(TRUE);
}
/***************************************************************************\
* PushMessageTimeout
*
* Sets up an input timeout for the message box that is just about to be created
*
* Returns TRUE on success, FALSE on failure
*
* 12-05-91 Davidc Created.
\***************************************************************************/
BOOL PushMessageTimeout(
HWND hwndOwner,
TIMEOUT TimeDelay,
LPTSTR Title,
PGLOBALS pGlobals)
{
TimeDelay = InheritTimeout(TimeDelay);
// Check the last message box has been dealt with
ASSERTMSG("Last timeout message box not identified yet !", TimeoutTitle == NULL);
// Push the timeout with a NULL hwnd (to be filled in later)
PushTimeout(NULL, TimeDelay, pGlobals);
// Store the message box title so that when we need to operate on the
// message box, we can go and search for it by title.
TimeoutTitle = Title;
hwndMessageOwner = hwndOwner;
DialogActive = TRUE;
return(TRUE);
}
/***************************************************************************\
* PopMessageTimeout
*
* Pops the top timeout from the stack and reenables the timeout for the
* next guy on the stack
*
* Returns TRUE on success, FALSE on failure
*
* 12-05-91 Davidc Created.
\***************************************************************************/
BOOL PopMessageTimeout(VOID)
{
PopTimeout();
// Reset our global in case we never went off to search for the
// message box 'cos we never had to
TimeoutTitle = NULL;
DialogActive = FALSE;
return(TRUE);
}
/***************************************************************************\
* FindMessageBox
*
* Searches for the message box that our globals tell us we're looking for.
*
* Returns TRUE if found, otherwise FALSE
*
* 12-05-91 Davidc Created.
\***************************************************************************/
BOOL FindMessageBox(VOID)
{
BOOL Found;
Found = !EnumTaskWindows(GetCurrentThreadId(), FindEnumfn, 0);
if (!Found) {
DebugLog((DEB_ERROR, "Message box window <%s> not found !!!", TimeoutTitle));
}
return(Found);
}
/***************************************************************************\
* FindEnumfn
*
* Enumeration function used by FindMessageBox()
*
* Returns FALSE if message box is found, otherwise TRUE
*
* 12-05-91 Davidc Created.
\***************************************************************************/
BOOL WINAPI
FindEnumfn(
HWND hwnd,
LPARAM lParam)
{
TCHAR Title[MAX_STRING_BYTES];
// See if this hwnd is the one
GetWindowText(hwnd, Title, sizeof(Title));
if (lstrcmp(Title, TimeoutTitle) == 0) {
// Found it
if (!SetTopTimeout(hwnd)) {
DebugLog((DEB_ERROR, "failed to set top timeout for message box !!"));
}
// Reset our global
TimeoutTitle = NULL;
return(FALSE); // Stop enumeration
}
return(TRUE); // Continue enumeration
DBG_UNREFERENCED_PARAMETER(lParam);
}
/***************************************************************************\
* InheritTimeout
*
* Converts a timedelay value that is potentially TIMEOUT_CURRENT to
* an independent timedelay value.
*
* 12-05-91 Davidc Created.
\***************************************************************************/
TIMEOUT InheritTimeout(
TIMEOUT TimeDelay
)
{
TIMEOUT ResultantTimeDelay;
if (TIMEOUT_VALUE(TimeDelay) == TIMEOUT_CURRENT) {
//
// Inherit timedelay from previous window
//
HWND hwndTop = GetTopTimeout(&ResultantTimeDelay);
if (!hwndTop)
{
DebugLog((DEB_WARN, "Tried to use TIMEOUT_CURRENT with no current timeout\n"));
ResultantTimeDelay = TIMEOUT_DEFAULT;
}
// Don't inherit the TIMEOUT_SS_NOTIFY bit
ResultantTimeDelay &= TIMEOUT_VALUE_MASK;
// Set the notify bit to match the one passed in
ResultantTimeDelay |= TIMEOUT_NOTIFY(TimeDelay);
} else {
//
// No inheritance
//
ResultantTimeDelay = TimeDelay;
}
return(ResultantTimeDelay);
}
/***************************************************************************\
* PushTimeout
*
* Internal routine to push the timeout information onto a stack
*
* Returns TRUE on success, FALSE on failure
*
* 12-05-91 Davidc Created.
\***************************************************************************/
BOOL PushTimeout(
HWND hwnd,
TIMEOUT TimeDelay,
PGLOBALS pGlobals)
{
// Check we don't have an outstanding unidentified message box
ASSERTMSG("Last timeout message box not identified yet !", TimeoutTitle == NULL);
if (NestedIndex < MAX_NESTED_TIMEOUTS) {
#if DBG
// Check we never push a TIMEOUT_NONE dialog when there's
// a timeout window already on the stack.
// This would be unusual.
if (TIMEOUT_VALUE(TimeDelay) == TIMEOUT_NONE) {
if (NestedIndex > 0) {
if (TIMEOUT_VALUE(TimeoutArray[NestedIndex-1]) != TIMEOUT_NONE) {
ASSERTMSG("Non-timeout window pushed on top of timeout window !!!", FALSE);
}
}
}
#endif
hwndArray[NestedIndex] = hwnd;
GlobalsArray[NestedIndex] = pGlobals;
TimeoutArray[NestedIndex++] = TimeDelay;
StartTopTimeout();
return(TRUE);
} else {
DebugLog((DEB_ERROR, "PushTimeout - Out of input timeout slots !!"));
return(FALSE);
}
}
/***************************************************************************\
* PopTimeout
*
* Pops the top timeout from the stack and reenables the timeout for the
* next guy on the stack
*
* Returns TRUE on success, FALSE on failure
*
* 12-05-91 Davidc Created.
\***************************************************************************/
BOOL PopTimeout(VOID)
{
if (NestedIndex <= 0) {
DebugLog((DEB_ERROR, "PopTimeout called with an empty timeout stack !!"));
return(FALSE);
}
NestedIndex --;
// This call will disable timeouts on an empty stack
StartTopTimeout();
return(TRUE);
}
/***************************************************************************\
* StartTopTimeout
*
* Starts (or restarts) the timeout on the top of the stack.
* If the stack is empty, timeouts are disabled.
*
* Returns TRUE on success, FALSE on failure
*
* 12-05-91 Davidc Created.
\***************************************************************************/
BOOL StartTopTimeout(VOID)
{
TIMEOUT TimeDelay;
if (NestedIndex > 0) {
TimeDelay = TimeoutArray[NestedIndex - 1];
DebugLog((DEB_TRACE_TIMEOUT, "Enabling timeout after %d seconds\n", TIMEOUT_VALUE(TimeDelay)));
} else {
DebugLog((DEB_TRACE_TIMEOUT, "Disabling timeouts\n"));
TimeDelay = TIMEOUT_NONE; // Disable timeouts
}
SetTimeout(TIMEOUT_VALUE(TimeDelay));
return(TRUE);
}
/***************************************************************************\
* GetTopTimeout
*
* Returns the timeout on the top of the stack.
*
* Returns top hwnd and time-delay or NULL on failure
*
* 12-05-91 Davidc Created.
\***************************************************************************/
HWND GetTopTimeout(
PTIMEOUT pTimeDelay)
{
HWND hwndTop = NULL;
TIMEOUT TimeDelay = 0;
if (TimeoutTitle != NULL) {
// Go search for message box before getting the top hwnd
FindMessageBox();
}
if (NestedIndex > 0) {
hwndTop = hwndArray[NestedIndex - 1];
TimeDelay = TimeoutArray[NestedIndex - 1];
}
if (pTimeDelay != NULL) {
*pTimeDelay = TimeDelay;
}
return(hwndTop);
}
//+---------------------------------------------------------------------------
//
// Function: TimeoutUpdateTopTimeout
//
// Synopsis: Updates the current timeout, returns FALSE if no window
// active, TRUE if it was updated.
//
// Arguments: [Timeout] --
//
// History: 3-05-96 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
TimeoutUpdateTopTimeout(
DWORD Timeout)
{
if ( DialogActive )
{
if ( TimeoutTitle != NULL )
{
FindMessageBox();
}
if ( NestedIndex > 0 )
{
TimeoutArray[ NestedIndex - 1 ] = Timeout;
return( TRUE );
}
}
return( FALSE );
}
/***************************************************************************\
* SetTopTimeout
*
* Sets the hwnd on top of the timeout stack to the one specified.
* The top timeout value is left unchanged.
*
* Checks if the existing hwnd is NULL, if not this call fails.
*
* Returns TRUE on success, FALSE on failure.
*
* 12-05-91 Davidc Created.
\***************************************************************************/
BOOL SetTopTimeout(
HWND hwnd)
{
if (NestedIndex <= 0) {
DebugLog((DEB_ERROR, "SetTopTimeout : Tried to set the top hwnd on an empty stack !!"));
return(FALSE);
}
if (hwndArray[NestedIndex - 1] != NULL) {
DebugLog((DEB_ERROR, "SetTopTimeout : hwnd at top of stack is not NULL !!"));
return(FALSE);
}
hwndArray[NestedIndex - 1] = hwnd;
return(TRUE);
}
/***************************************************************************\
* SetTimeout
*
* Sets an input timeout for the specified window using the specified delay.
*
* If TimeDelay = 0, no timeout is enabled for this window.
*
* Returns TRUE on success, FALSE on failure
*
* 12-05-91 Davidc Created.
\***************************************************************************/
BOOL SetTimeout(
TIMEOUT TimeDelay)
{
if (TimeDelay != 0) {
if (!InputHooksInstalled) {
SetInputHooks();
}
StartTimer(TimeDelay);
} else {
if (InputHooksInstalled) {
ReleaseInputHooks();
}
StopTimer();
}
return (TRUE);
}
/***************************************************************************\
* CheckTimeout
*
* Returns TRUE if a timeout is still occurring for this window, otherwise FALSE
*
* 12-05-91 Davidc Created.
\***************************************************************************/
BOOL CheckTimeout(
HWND hwnd)
{
if (GetTopTimeout(NULL) != hwnd) {
return(FALSE);
}
return (TimeoutOccurred);
}
/***************************************************************************\
* StartTimer
*
* Starts (or restarts) the input timer with the specified delay
*
* Returns TRUE on success, FALSE on failure
*
* 12-05-91 Davidc Created.
\***************************************************************************/
BOOL StartTimer(
TIMEOUT TimeDelay)
{
StopTimer();
TimerID = SetTimer(NULL, TimerID, TimeDelay * 1000, (TIMERPROC)Timerfn);
return(TimerID != 0);
}
/***************************************************************************\
* StopTimer
*
* Stops the input timer and resets the timeout flag
*
* Returns TRUE on success, FALSE on failure
*
* 12-05-91 Davidc Created.
\***************************************************************************/
BOOL StopTimer(VOID)
{
if (TimerID != 0) {
KillTimer(NULL, TimerID);
TimerID = 0;
}
TimeoutOccurred = FALSE;
return(TRUE);
}
/***************************************************************************\
* Timerfn
*
* Called when the timer goes off.
*
* 12-05-91 Davidc Created.
\***************************************************************************/
WORD WINAPI Timerfn(
HWND hwnd,
WORD Message,
int IDEvent,
DWORD dwTime)
{
// Set the timeout flag and stop any more timeouts
TimeoutOccurred = TRUE;
KillTimer(NULL, TimerID);
TimerID = 0;
if (GetTopTimeout(NULL) == NULL) {
DebugLog((DEB_ERROR, "Input timer went off, but top timeout has NULL hwnd"));
}
// Send a message to the window who owns the timeout
// ForwardMessage(NULL, WM_INPUT_TIMEOUT, FALSE, 0);
DebugLog((DEB_TRACE_TIMEOUT, "Input timer went off, sending TIMEOUT\n"));
if (DialogActive)
{
EndTopDialog(NULL, WLX_DLG_INPUT_TIMEOUT);
}
else
SASRouter(GlobalsArray[NestedIndex - 1], WLX_SAS_TYPE_TIMEOUT);
return(0);
DBG_UNREFERENCED_PARAMETER(hwnd);
DBG_UNREFERENCED_PARAMETER(Message);
DBG_UNREFERENCED_PARAMETER(IDEvent);
DBG_UNREFERENCED_PARAMETER(dwTime);
}
/***************************************************************************\
* SetInputHooks
*
* Installs input hooks
*
* Returns TRUE on success, FALSE on failure
*
* 12-05-91 Davidc Created.
\***************************************************************************/
BOOL SetInputHooks(VOID)
{
InputHooksInstalled = TRUE;
hhkMouse = SetWindowsHook(WH_MOUSE, MouseHookfn);
hhkKeyboard = SetWindowsHook(WH_KEYBOARD, KeyboardHookfn);
return(TRUE);
}
/***************************************************************************\
* ReleaseInputHooks
*
* Uninstalls input hooks
*
* Returns TRUE on success, FALSE on failure
*
* 12-05-91 Davidc Created.
\***************************************************************************/
BOOL ReleaseInputHooks(VOID)
{
UnhookWindowsHook(WH_MOUSE, MouseHookfn);
UnhookWindowsHook(WH_KEYBOARD, KeyboardHookfn);
InputHooksInstalled = FALSE;
return(TRUE);
}
/***************************************************************************\
* MouseHookfn
*
* Called when there is mouse input for this app
*
* 12-05-91 Davidc Created.
\***************************************************************************/
LRESULT WINAPI
MouseHookfn(
int nCode,
WPARAM wParam,
LPARAM lParam
)
{
if (nCode >= 0) {
if (!TimeoutOccurred) {
StartTopTimeout();
}
}
return(DefHookProc(nCode, wParam, lParam, &hhkMouse));
}
/***************************************************************************\
* KeyboardHookfn
*
* Called when there is keyboard input for this app
*
* 12-05-91 Davidc Created.
\***************************************************************************/
LRESULT WINAPI
KeyboardHookfn(
int nCode,
WPARAM wParam,
LPARAM lParam
)
{
if (nCode >= 0) {
if (!TimeoutOccurred) {
StartTopTimeout();
}
}
return(DefHookProc(nCode, wParam, lParam, &hhkKeyboard));
}
/***************************************************************************\
* TimeoutMessageBox
*
* Same as a normal message box, but times out if there is no user input
* for the specified number of seconds
* For convenience, this api takes string resource ids rather than string
* pointers as input. The resources are loaded from the .exe module
*
* 12-05-91 Davidc Created.
\***************************************************************************/
int TimeoutMessageBoxEx(
PGLOBALS pGlobals,
HWND hwnd,
UINT IdText,
UINT IdCaption,
UINT wType,
TIMEOUT Timeout)
{
TCHAR CaptionBuffer[MAX_STRING_BYTES];
PTCHAR Caption = CaptionBuffer;
TCHAR Text[MAX_STRING_BYTES];
LoadString(NULL, IdText, Text, MAX_STRING_LENGTH);
if (IdCaption != 0) {
LoadString(NULL, IdCaption, Caption, MAX_STRING_LENGTH);
} else {
Caption = NULL;
}
return TimeoutMessageBoxlpstr(pGlobals, hwnd, Text, Caption, wType, Timeout);
}
/***************************************************************************\
* TimeoutMessageBoxlpstr
*
* Same as a normal message box, but times out if there is no user input
* for the specified number of seconds
*
* 12-05-91 Davidc Created.
\***************************************************************************/
int TimeoutMessageBoxlpstr(
PGLOBALS pGlobals,
HWND hwnd,
LPTSTR Text,
LPTSTR Caption,
UINT wType,
TIMEOUT Timeout)
{
int Result;
int DlgResult;
#if DBG
//
// Reset the return code so if we forget to set if before returning
// an interrupt MapResultCode will detect it.
// Also this allows us to check the interrupt type is not overwritten
// by a second interrupt before we clear it.
//
TopDialogReturnCode = DLG_INTERRUPT;
#endif
// Set up input timeout
PushMessageTimeout(hwnd, Timeout, Caption, pGlobals);
Result = MessageBox(hwnd, Text, Caption, wType);
// Re-enable previous timeout
PopMessageTimeout();
DlgResult = MapResultCode(Result, TopDialogReturnCode);
#if DBG
//
// Reset the stored return code so we can detect if an interrupt is
// generated without the code being set.
//
TopDialogReturnCode = DLG_INTERRUPT;
#endif
return(DlgResult);
}
/***************************************************************************\
* TimeoutDialogBoxParam
*
* Same as a normal dialog box, but times out if there is no user input
* for the specified number of seconds
*
* 12-05-91 Davidc Created.
\***************************************************************************/
int
TimeoutDialogBoxParam(
PGLOBALS pGlobals,
HANDLE hInstance,
LPTSTR lpTemplateName,
HWND hwndParent,
DLGPROC lpDialogFunc,
LONG dwInitParam,
TIMEOUT Timeout)
{
int Result;
MSG msg;
#if DBG
//
// Reset the return code so if we forget to set if before returning
// an interrupt MapResultCode will detect it.
// Also this allows us to check the interrupt type is not overwritten
// by a second interrupt before we clear it.
//
TopDialogReturnCode = DLG_INTERRUPT;
#endif
while (TRUE) {
PushDialogTimeout(Timeout, pGlobals);
Result = DialogBoxParam(hInstance,
lpTemplateName,
hwndParent,
lpDialogFunc,
dwInitParam
);
#if DBG
if (Result < 0)
{
if ((DWORD) lpTemplateName > 0x00010000)
{
DebugLog((DEB_WARN, "DialogBoxParam(%#x, %ws, %#x, %#x, %#x) failed, error %d\n",
hInstance, lpTemplateName, hwndParent, lpDialogFunc,
dwInitParam, GetLastError() ));
}
else
{
DebugLog((DEB_WARN, "DialogBoxParam(%#x, %#x, %#x, %#x, %#x) failed, error %d\n",
hInstance, lpTemplateName, hwndParent, lpDialogFunc,
dwInitParam, GetLastError() ));
}
}
#endif
// Re-enable previous timeout
PopTimeout();
//
// If the dialog returned due to WM_QUIT, eat the message
// and do the dialog again.
//
if (!PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE)) {
break;
}
}
return(Result);
}
/***************************************************************************\
* TimeoutDialogBoxIndirectParam
*
* Same as a normal dialog box, but times out if there is no user input
* for the specified number of seconds
*
* 05-15-92 Davidc Created.
\***************************************************************************/
int
TimeoutDialogBoxIndirectParam(
PGLOBALS pGlobals,
HANDLE hInstance,
LPDLGTEMPLATE Template,
HWND hwndParent,
DLGPROC lpDialogFunc,
LONG dwInitParam,
TIMEOUT Timeout)
{
int Result;
MSG msg;
while (TRUE) {
PushDialogTimeout(Timeout, pGlobals);
Result = DialogBoxIndirectParam(hInstance,
Template,
hwndParent,
lpDialogFunc,
dwInitParam
);
// Re-enable previous timeout
PopTimeout();
//
// If the dialog returned due to WM_QUIT, eat the message
// and do the dialog again.
//
if (!PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE)) {
break;
}
}
return(Result);
}
/***************************************************************************\
* EndTopDialog
*
* Interrupts the dialog on top of the timeout stack and causes it to return
* the code specified.
*
* The passed hwnd is that of the caller. This is not used other than as
* a debugging aid.
*
* The dlgresult passed must be one of the interrupt types.
*
* Returns TRUE on success, FALSE on failure.
*
* 12-05-91 Davidc Created.
\***************************************************************************/
BOOL EndTopDialog(
HWND hwnd,
int DlgResult
)
{
HWND hwndTop = GetTopTimeout(NULL);
if (hwndTop == NULL) {
DebugLog((DEB_ERROR, "EndTopDialog called with no dialogs on the stack!"));
ASSERT(FALSE);
return(FALSE);
}
#ifdef WINLOGON_TEST
if (hwndTop != hwnd) {
DebugLog((DEB_ERROR, "Ending top dialog from lower-level dialog!"));
}
#endif
//
// Check the value has not already been set
//
ASSERT(TopDialogReturnCode == DLG_INTERRUPT);
TopDialogReturnCode = DlgResult;
return (EndDialog(hwndTop, DLG_INTERRUPT));
}
BOOL
KillMessageBox( DWORD SasCode )
{
DWORD EndCode;
//
// This will kill any outstanding message boxes due to an incoming
// SAS event. This is used by SendSasToTopWindow when it is forwarding
// along an GINA specific SAS. This kills pending message boxes so that
// the dialog regains control.
//
if (DialogActive)
{
switch ( SasCode )
{
case WLX_SAS_TYPE_TIMEOUT:
EndCode = WLX_DLG_INPUT_TIMEOUT ;
break;
case WLX_SAS_TYPE_SCRNSVR_TIMEOUT:
EndCode = WLX_DLG_SCREEN_SAVER_TIMEOUT ;
break;
default:
EndCode = WLX_DLG_SAS;
break;
}
EndTopDialog(NULL, EndCode);
return(TRUE);
}
return(FALSE);
}