first attempt to implement SendMessageTimeout()

svn path=/trunk/; revision=8643
This commit is contained in:
Thomas Bluemel 2004-03-11 14:47:44 +00:00
parent 241b66d3bd
commit 1988a7b8ea
8 changed files with 292 additions and 52 deletions

View file

@ -473,6 +473,7 @@ NtUserScrollWindowEx 8
NtUserSendInput 3
NtUserSendMessage 5
NtUserSendMessageCallback 6
NtUserSendMessageTimeout 8
NtUserSendNotifyMessage 4
NtUserSetActiveWindow 1
NtUserSetCapture 1

View file

@ -2084,6 +2084,13 @@ extern "C" {
/* InitializeSecurityDescriptor */
#define SECURITY_DESCRIPTOR_REVISION (1)
/* InSendMessageEx */
#define ISMEX_NOSEND (0)
#define ISMEX_SEND (1)
#define ISMEX_NOTIFY (2)
#define ISMEX_CALLBACK (4)
#define ISMEX_REPLIED (8)
/* JournalPlaybackProc, KeyboardProc */
#define HC_GETNEXT (1)
#define HC_SKIP (2)

View file

@ -570,6 +570,8 @@ extern "C" {
#define ERROR_PAGEFILE_QUOTA 1454L
#define ERROR_COMMITMENT_LIMIT 1455L
#define ERROR_MENU_ITEM_NOT_FOUND 1456L
#define ERROR_TIMEOUT 1460L
#define ERROR_INVALID_MONITOR_HANDLE 1461L
#define ERROR_EVENTLOG_FILE_CORRUPT 1500L
#define ERROR_EVENTLOG_CANT_START 1501L
#define ERROR_LOG_FILE_FULL 1502L

View file

@ -783,10 +783,12 @@ NtUserGetThreadDesktop(
DWORD dwThreadId,
DWORD Unknown1);
#define THREADSTATE_FOCUSWINDOW (1)
#define THREADSTATE_INSENDMESSAGE (2)
DWORD
STDCALL
NtUserGetThreadState(
DWORD Unknown0);
DWORD Routine);
DWORD
STDCALL
@ -1167,6 +1169,16 @@ NtUserSendMessageCallback(
SENDASYNCPROC lpCallBack,
ULONG_PTR dwData);
LRESULT STDCALL
NtUserSendMessageTimeout(HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam,
UINT uFlags,
UINT uTimeout,
ULONG_PTR *uResult,
PNTUSERSENDMESSAGEINFO Info);
BOOL
STDCALL
NtUserSendNotifyMessage(

View file

@ -1,4 +1,4 @@
/* $Id: message.c,v 1.35 2004/01/28 20:54:30 gvg Exp $
/* $Id: message.c,v 1.36 2004/03/11 14:47:43 weiden Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS user32.dll
@ -54,6 +54,8 @@ BOOL
STDCALL
InSendMessage(VOID)
{
/* return(NtUserGetThreadState(THREADSTATE_INSENDMESSAGE) != ISMEX_NOSEND); */
UNIMPLEMENTED;
return FALSE;
}
@ -66,6 +68,7 @@ STDCALL
InSendMessageEx(
LPVOID lpReserved)
{
/* return NtUserGetThreadState(THREADSTATE_INSENDMESSAGE); */
UNIMPLEMENTED;
return 0;
}
@ -834,8 +837,64 @@ SendMessageTimeoutA(
UINT uTimeout,
PDWORD_PTR lpdwResult)
{
UNIMPLEMENTED;
return (LRESULT)0;
MSG AnsiMsg;
MSG UcMsg;
LRESULT Result;
NTUSERSENDMESSAGEINFO Info;
AnsiMsg.hwnd = hWnd;
AnsiMsg.message = Msg;
AnsiMsg.wParam = wParam;
AnsiMsg.lParam = lParam;
if (! MsgiAnsiToUnicodeMessage(&UcMsg, &AnsiMsg))
{
return FALSE;
}
Info.Ansi = TRUE;
Result = NtUserSendMessageTimeout(UcMsg.hwnd, UcMsg.message,
UcMsg.wParam, UcMsg.lParam,
fuFlags, uTimeout, (ULONG_PTR*)lpdwResult, &Info);
if(!Result)
{
return FALSE;
}
if (! Info.HandledByKernel)
{
/* We need to send the message ourselves */
if (Info.Ansi)
{
/* Ansi message and Ansi window proc, that's easy. Clean up
the Unicode message though */
MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
Result = IntCallWindowProcA(Info.Ansi, Info.Proc, hWnd, Msg, wParam, lParam);
}
else
{
/* Unicode winproc. Although we started out with an Ansi message we
already converted it to Unicode for the kernel call. Reuse that
message to avoid another conversion */
Result = IntCallWindowProcW(Info.Ansi, Info.Proc, UcMsg.hwnd,
UcMsg.message, UcMsg.wParam, UcMsg.lParam);
if (! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result))
{
return FALSE;
}
}
if(lpdwResult)
*lpdwResult = Result;
Result = TRUE;
}
else
{
/* Message sent by kernel. Convert back to Ansi */
if (! MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result))
{
return FALSE;
}
}
return Result;
}
@ -853,8 +912,22 @@ SendMessageTimeoutW(
UINT uTimeout,
PDWORD_PTR lpdwResult)
{
UNIMPLEMENTED;
return (LRESULT)0;
NTUSERSENDMESSAGEINFO Info;
LRESULT Result;
Info.Ansi = FALSE;
Result = NtUserSendMessageTimeout(hWnd, Msg, wParam, lParam, fuFlags, uTimeout,
lpdwResult, &Info);
if (! Info.HandledByKernel)
{
/* We need to send the message ourselves */
Result = IntCallWindowProcW(Info.Ansi, Info.Proc, hWnd, Msg, wParam, lParam);
if(lpdwResult)
*lpdwResult = Result;
return TRUE;
}
return Result;
}

View file

@ -6,6 +6,8 @@
#include "caret.h"
#include "hook.h"
#define MSQ_HUNG 5000
typedef struct _USER_MESSAGE
{
LIST_ENTRY ListEntry;
@ -59,8 +61,8 @@ typedef struct _USER_MESSAGE_QUEUE
ULONG QuitExitCode;
/* Set if there are new messages in any of the queues. */
KEVENT NewMessages;
/* FIXME: Unknown. */
ULONG QueueStatus;
/* Last time PeekMessage() was called. */
ULONG LastMsgRead;
/* Current window with focus (ie. receives keyboard input) for this queue. */
HWND FocusWindow;
/* True if a window needs painting. */
@ -94,9 +96,12 @@ typedef struct _USER_MESSAGE_QUEUE
} USER_MESSAGE_QUEUE, *PUSER_MESSAGE_QUEUE;
LRESULT FASTCALL
BOOL FASTCALL
MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue);
NTSTATUS FASTCALL
MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam);
HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam,
UINT uTimeout, BOOL Block, ULONG_PTR *uResult);
VOID FASTCALL
MsqInitializeMessage(PUSER_MESSAGE Message,
LPMSG Msg);
@ -147,6 +152,14 @@ IntSendMessage(HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam);
LRESULT STDCALL
IntSendMessageTimeout(HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam,
UINT uFlags,
UINT uTimeout,
ULONG_PTR *uResult);
LRESULT FASTCALL
IntDispatchMessage(MSG* Msg);
BOOL FASTCALL

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: message.c,v 1.52 2004/02/24 13:27:03 weiden Exp $
/* $Id: message.c,v 1.53 2004/03/11 14:47:44 weiden Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
@ -47,6 +47,13 @@
#define NDEBUG
#include <debug.h>
typedef struct
{
UINT uFlags;
UINT uTimeout;
ULONG_PTR uResult;
} DOSENDMESSAGE, *PDOSENDMESSAGE;
/* FUNCTIONS *****************************************************************/
NTSTATUS FASTCALL
@ -235,6 +242,7 @@ IntPeekMessage(LPMSG Msg,
UINT MsgFilterMax,
UINT RemoveMsg)
{
LARGE_INTEGER LargeTickCount;
PUSER_MESSAGE_QUEUE ThreadQueue;
BOOLEAN Present;
PUSER_MESSAGE Message;
@ -244,6 +252,9 @@ IntPeekMessage(LPMSG Msg,
article on GetMessage() */
ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
KeQueryTickCount(&LargeTickCount);
ThreadQueue->LastMsgRead = LargeTickCount.u.LowPart;
/* Inspect RemoveMsg flags */
/* FIXME: The only flag we process is PM_REMOVE - processing of others must still be implemented */
@ -706,11 +717,29 @@ UnpackParam(LPARAM lParamPacked, UINT Msg, WPARAM wParam, LPARAM lParam)
LRESULT STDCALL
IntSendMessage(HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam)
UINT Msg,
WPARAM wParam,
LPARAM lParam)
{
LRESULT Result = 0;
if(IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
{
return Result;
}
return 0;
}
LRESULT STDCALL
IntSendMessageTimeout(HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam,
UINT uFlags,
UINT uTimeout,
ULONG_PTR *uResult)
{
LRESULT Result;
NTSTATUS Status;
PWINDOW_OBJECT Window;
PMSGMEMORY MsgMemoryEntry;
INT lParamBufferSize;
@ -724,7 +753,7 @@ IntSendMessage(HWND hWnd,
if (!Window)
{
SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
return 0;
return FALSE;
}
Win32Thread = PsGetWin32Thread();
@ -736,7 +765,7 @@ IntSendMessage(HWND hWnd,
{
/* Never send messages to exiting threads */
IntReleaseWindowObject(Window);
return 0;
return FALSE;
}
/* See if this message type is present in the table */
@ -754,7 +783,7 @@ IntSendMessage(HWND hWnd,
{
IntReleaseWindowObject(Window);
DPRINT1("Failed to pack message parameters\n");
return -1;
return FALSE;
}
if (0xFFFF0000 != ((DWORD) Window->WndProcW & 0xFFFF0000))
{
@ -770,17 +799,37 @@ IntSendMessage(HWND hWnd,
{
IntReleaseWindowObject(Window);
DPRINT1("Failed to unpack message parameters\n");
return Result;
if(uResult)
*uResult = Result;
return TRUE;
}
IntReleaseWindowObject(Window);
return Result;
if(uResult)
*uResult = Result;
return TRUE;
}
Result = MsqSendMessage(Window->MessageQueue, hWnd, Msg, wParam, lParam);
if(uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->MessageQueue))
{
IntReleaseWindowObject(Window);
/* FIXME - Set a LastError? */
return FALSE;
}
Status = MsqSendMessage(Window->MessageQueue, hWnd, Msg, wParam, lParam,
(uFlags & SMTO_BLOCK), uTimeout, &Result);
if(Status == STATUS_TIMEOUT)
{
IntReleaseWindowObject(Window);
SetLastWin32Error(ERROR_TIMEOUT);
return FALSE;
}
IntReleaseWindowObject(Window);
return Result;
if(uResult)
*uResult = Result;
return TRUE;
}
static NTSTATUS FASTCALL
@ -878,12 +927,13 @@ CopyMsgToUserMem(MSG *UserModeMsg, MSG *KernelModeMsg)
return STATUS_SUCCESS;
}
LRESULT STDCALL
NtUserSendMessage(HWND Wnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam,
PNTUSERSENDMESSAGEINFO UnsafeInfo)
LRESULT FASTCALL
IntDoSendMessage(HWND Wnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam,
PDOSENDMESSAGE dsm,
PNTUSERSENDMESSAGEINFO UnsafeInfo)
{
LRESULT Result;
NTSTATUS Status;
@ -957,16 +1007,25 @@ NtUserSendMessage(HWND Wnd,
{
MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return -1;
return (dsm ? 0 : -1);
}
Result = IntSendMessage(KernelModeMsg.hwnd, KernelModeMsg.message,
KernelModeMsg.wParam, KernelModeMsg.lParam);
if(!dsm)
{
Result = IntSendMessage(KernelModeMsg.hwnd, KernelModeMsg.message,
KernelModeMsg.wParam, KernelModeMsg.lParam);
}
else
{
Result = IntSendMessageTimeout(KernelModeMsg.hwnd, KernelModeMsg.message,
KernelModeMsg.wParam, KernelModeMsg.lParam,
dsm->uFlags, dsm->uTimeout, &dsm->uResult);
}
Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
if (! NT_SUCCESS(Status))
{
MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return -1;
return(dsm ? 0 : -1);
}
}
@ -979,6 +1038,46 @@ NtUserSendMessage(HWND Wnd,
return Result;
}
LRESULT STDCALL
NtUserSendMessageTimeout(HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam,
UINT uFlags,
UINT uTimeout,
ULONG_PTR *uResult,
PNTUSERSENDMESSAGEINFO UnsafeInfo)
{
DOSENDMESSAGE dsm;
LRESULT Result;
dsm.uFlags = uFlags;
dsm.uTimeout = uTimeout;
Result = IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
if(uResult)
{
NTSTATUS Status;
Status = MmCopyToCaller(uResult, &dsm.uResult, sizeof(ULONG_PTR));
if(!NT_SUCCESS(Status))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return FALSE;
}
}
return Result;
}
LRESULT STDCALL
NtUserSendMessage(HWND Wnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam,
PNTUSERSENDMESSAGEINFO UnsafeInfo)
{
return IntDoSendMessage(Wnd, Msg, wParam, lParam, NULL, UnsafeInfo);
}
BOOL STDCALL
NtUserSendMessageCallback(HWND hWnd,
UINT Msg,

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: msgqueue.c,v 1.74 2004/02/28 00:44:28 weiden Exp $
/* $Id: msgqueue.c,v 1.75 2004/03/11 14:47:44 weiden Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
@ -889,16 +889,17 @@ MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue,
IntUnLockMessageQueue(MessageQueue);
}
LRESULT FASTCALL
NTSTATUS FASTCALL
MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam,
UINT uTimeout, BOOL Block, ULONG_PTR *uResult)
{
PUSER_SENT_MESSAGE Message;
KEVENT CompletionEvent;
PVOID WaitObjects[2];
NTSTATUS WaitStatus;
LRESULT Result;
PUSER_MESSAGE_QUEUE ThreadQueue;
LARGE_INTEGER Timeout;
KeInitializeEvent(&CompletionEvent, NotificationEvent, FALSE);
@ -914,24 +915,44 @@ MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
IntLockMessageQueue(MessageQueue);
InsertTailList(&MessageQueue->SentMessagesListHead, &Message->ListEntry);
KeSetEvent(&MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
IntUnLockMessageQueue(MessageQueue);
KeSetEvent(&MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
Timeout.QuadPart = uTimeout * -10000;
ThreadQueue = PsGetWin32Thread()->MessageQueue;
WaitObjects[1] = &ThreadQueue->NewMessages;
WaitObjects[0] = &CompletionEvent;
do
{
WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
UserMode, TRUE, NULL, NULL);
while (MsqDispatchOneSentMessage(ThreadQueue))
{
;
}
}
while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 != WaitStatus);
return (STATUS_WAIT_0 == WaitStatus ? Result : -1);
if(Block)
{
/* don't process messages sent to the thread */
WaitStatus = KeWaitForSingleObject(&CompletionEvent, UserRequest, UserMode,
FALSE, (uTimeout ? &Timeout : NULL));
}
else
{
PVOID WaitObjects[2];
WaitObjects[0] = &CompletionEvent;
WaitObjects[1] = &ThreadQueue->NewMessages;
do
{
WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
UserMode, FALSE, (uTimeout ? &Timeout : NULL), NULL);
if(WaitStatus == STATUS_TIMEOUT)
{DbgPrint("MsqSendMessage timed out\n");
break;
}
while (MsqDispatchOneSentMessage(ThreadQueue))
{
;
}
}
while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 != WaitStatus);
}
if(WaitStatus != STATUS_TIMEOUT)
*uResult = (STATUS_WAIT_0 == WaitStatus ? Result : -1);
return WaitStatus;
}
VOID FASTCALL
@ -1014,9 +1035,20 @@ MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue)
NULL));
}
BOOL FASTCALL
MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue)
{
LARGE_INTEGER LargeTickCount;
KeQueryTickCount(&LargeTickCount);
return ((LargeTickCount.u.LowPart - MessageQueue->LastMsgRead) > MSQ_HUNG);
}
VOID FASTCALL
MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQueue)
{
LARGE_INTEGER LargeTickCount;
MessageQueue->Thread = Thread;
MessageQueue->CaretInfo = (PTHRDCARETINFO)(MessageQueue + 1);
InitializeListHead(&MessageQueue->PostedMessagesListHead);
@ -1027,7 +1059,8 @@ MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQu
MessageQueue->QuitPosted = FALSE;
MessageQueue->QuitExitCode = 0;
KeInitializeEvent(&MessageQueue->NewMessages, SynchronizationEvent, FALSE);
MessageQueue->QueueStatus = 0;
KeQueryTickCount(&LargeTickCount);
MessageQueue->LastMsgRead = LargeTickCount.u.LowPart;
MessageQueue->FocusWindow = NULL;
MessageQueue->PaintPosted = FALSE;
MessageQueue->PaintCount = 0;