mirror of https://github.com/lianthony/NT4.0
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.
1248 lines
31 KiB
1248 lines
31 KiB
/****************************** 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);
|
|
}
|