Author: mjmartin
Date: Mon Apr 4 21:50:24 2011
New Revision: 51255
URL: http://svn.reactos.org/svn/reactos?rev=51255&view=rev
Log:
[Win32k]
- co_MsqDispatchOneSentMessage: After calling the windows procedure check if
the message was a callback. If so place the message into the calling
MessageQueue. Also check if the current MessageQueue is the calling
MessageQueue in which case dont call the Windows procedure but call the
callback routine. SendMessageCallback is now properly implemented.
- Remove the use of MSQ_SENTNOWAIT and instead use the SenderQueue and
CallBackSenderQueue members to determine if the MessageQueues need to be
dereferenced.
- Modify co_MsqSendMessage to accept more parameters so that it can handle
Notification, Callback and Internal messages. These changes make this function
more complex but removes duplicate code in messages.c and move the handling for
all queued messages in one location.
- co_IntSendMessageWithCallBack: If the callback is for the same Message Queue,
call it vice queuing it.
Insert the message into the MessageQueue before waking the thread to handle the
message. Should fix bug 5580.
Modified:
trunk/reactos/subsystems/win32/win32k/ntuser/event.c
trunk/reactos/subsystems/win32/win32k/ntuser/hook.c
trunk/reactos/subsystems/win32/win32k/ntuser/message.c
trunk/reactos/subsystems/win32/win32k/ntuser/msgqueue.c
Modified: trunk/reactos/subsystems/win32/win32k/ntuser/event.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/ntuser/event.c?rev=51255&r1=51254&r2=51255&view=diff
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/ntuser/event.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/win32/win32k/ntuser/event.c [iso-8859-1] Mon Apr
4 21:50:24 2011
@@ -115,15 +115,19 @@
/* FIXME should get timeout from
* HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
- Status = co_MsqSendMessage( pEH->head.pti->MessageQueue,
+ Status = co_MsqSendMessage(
((PTHREADINFO)PsGetCurrentThreadWin32Thread())->MessageQueue,
+ pEH->head.pti->MessageQueue,
hwnd,
event,
0,
- (LPARAM)pEP,
+ (LPARAM)pEP,
+ FALSE,
+ NULL,
+ 0,
300,
TRUE,
MSQ_ISEVENT,
- &uResult);
+ &uResult);
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(pEP, TAG_HOOK);
Modified: trunk/reactos/subsystems/win32/win32k/ntuser/hook.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/ntuser/hook.c?rev=51255&r1=51254&r2=51255&view=diff
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/ntuser/hook.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/win32/win32k/ntuser/hook.c [iso-8859-1] Mon Apr 4
21:50:24 2011
@@ -88,15 +88,19 @@
/* FIXME should get timeout from
* HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */
- Status = co_MsqSendMessage( pti->MessageQueue,
+ Status = co_MsqSendMessage(
((PTHREADINFO)PsGetCurrentThreadWin32Thread())->MessageQueue,
+ pti->MessageQueue,
IntToPtr(Code), // hWnd
Hook->HookId, // Msg
wParam,
- (LPARAM)pHP,
+ (LPARAM)pHP,
+ FALSE,
+ NULL,
+ 0,
uTimeout,
Block,
MSQ_ISHOOK,
- &uResult);
+ &uResult);
if (!NT_SUCCESS(Status))
{
DPRINT1("Error Hook Call SendMsg. %d Status: 0x%x\n", Hook->HookId,
Status);
Modified: trunk/reactos/subsystems/win32/win32k/ntuser/message.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/ntuser/message.c?rev=51255&r1=51254&r2=51255&view=diff
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/ntuser/message.c [iso-8859-1]
(original)
+++ trunk/reactos/subsystems/win32/win32k/ntuser/message.c [iso-8859-1] Mon Apr
4 21:50:24 2011
@@ -1261,11 +1261,15 @@
do
{
- Status = co_MsqSendMessage( Window->head.pti->MessageQueue,
+ Status =
co_MsqSendMessage(((PTHREADINFO)PsGetCurrentThreadWin32Thread())->MessageQueue,
+ Window->head.pti->MessageQueue,
hWnd,
Msg,
wParam,
lParam,
+ FALSE,
+ NULL,
+ 0,
uTimeout,
(uFlags & SMTO_BLOCK),
MSQ_NORMAL,
@@ -1354,6 +1358,7 @@
LPARAM lParam)
{
ULONG_PTR Result = 0;
+ /* Piggyback off CallBack */
co_IntSendMessageWithCallBack(hWnd,
Msg,
wParam,
@@ -1372,12 +1377,12 @@
*/
LRESULT FASTCALL
co_IntSendMessageWithCallBack( HWND hWnd,
- UINT Msg,
- WPARAM wParam,
- LPARAM lParam,
- SENDASYNCPROC CompletionCallback,
- ULONG_PTR CompletionCallbackContext,
- ULONG_PTR *uResult)
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam,
+ SENDASYNCPROC CompletionCallback,
+ ULONG_PTR CompletionCallbackContext,
+ ULONG_PTR *uResult)
{
ULONG_PTR Result;
PWND Window = NULL;
@@ -1437,7 +1442,7 @@
}
/* If this is not a callback and it can be sent now, then send it. */
- if ((Window->head.pti->MessageQueue == Win32Thread->MessageQueue) &&
(CompletionCallback == NULL))
+ if (Window->head.pti->MessageQueue == Win32Thread->MessageQueue)
{
ObReferenceObject(Win32Thread->pEThread);
Result = (ULONG_PTR)co_IntCallWindowProc( Window->lpfnWndProc,
@@ -1452,11 +1457,20 @@
*uResult = Result;
}
ObDereferenceObject(Win32Thread->pEThread);
+
+ if (CompletionCallback)
+ {
+ co_IntCallSentMessageCallback(CompletionCallback,
+ hWnd,
+ Msg,
+ CompletionCallbackContext,
+ Result);
+ }
}
IntCallWndProcRet( Window, hWnd, Msg, wParam, lParam, (LRESULT *)uResult);
- if ((Window->head.pti->MessageQueue == Win32Thread->MessageQueue) &&
(CompletionCallback == NULL))
+ if (Window->head.pti->MessageQueue == Win32Thread->MessageQueue)
{
if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam,
FALSE)))
{
@@ -1480,18 +1494,21 @@
Message->lResult = 0;
Message->QS_Flags = 0;
Message->SenderQueue = NULL; // mjmartin, you are right! This is null.
- Message->CallBackSenderQueue = Win32Thread->MessageQueue;
-
+ if (CompletionCallback)
+ Message->CallBackSenderQueue = Win32Thread->MessageQueue;
+ else
+ Message->CallBackSenderQueue = NULL;
IntReferenceMessageQueue(Window->head.pti->MessageQueue);
Message->CompletionCallback = CompletionCallback;
Message->CompletionCallbackContext = CompletionCallbackContext;
- Message->HookMessage = MSQ_NORMAL | MSQ_SENTNOWAIT;
- Message->HasPackedLParam = (lParamBufferSize > 0);
+ Message->HookMessage = MSQ_NORMAL;
+ Message->HasPackedLParam = (lParamBufferSize > -1);
Message->QS_Flags = QS_SENDMESSAGE;
+ if (CompletionCallback)
+ InsertTailList(&Win32Thread->MessageQueue->DispatchingMessagesHead,
&Message->DispatchingListEntry);
+ InsertTailList(&Window->head.pti->MessageQueue->SentMessagesListHead,
&Message->ListEntry);
MsqWakeQueue(Window->head.pti->MessageQueue, QS_SENDMESSAGE, FALSE);
-
- InsertTailList(&Window->head.pti->MessageQueue->SentMessagesListHead,
&Message->ListEntry);
IntDereferenceMessageQueue(Window->head.pti->MessageQueue);
RETURN(TRUE);
@@ -2112,7 +2129,7 @@
{
co_IntSendMessageTimeout( HWND_BROADCAST,
Msg,
- wParam,
+ wParam,
lParam,
SMTO_NORMAL,
2000,
Modified: trunk/reactos/subsystems/win32/win32k/ntuser/msgqueue.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/ntuser/msgqueue.c?rev=51255&r1=51254&r2=51255&view=diff
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/ntuser/msgqueue.c [iso-8859-1]
(original)
+++ trunk/reactos/subsystems/win32/win32k/ntuser/msgqueue.c [iso-8859-1] Mon
Apr 4 21:50:24 2011
@@ -423,7 +423,7 @@
PLIST_ENTRY Entry;
LRESULT Result;
PTHREADINFO pti;
-
+
if (IsListEmpty(&MessageQueue->SentMessagesListHead))
{
return(FALSE);
@@ -466,6 +466,18 @@
Message->Msg.wParam,
Message->Msg.lParam);
}
+ else if ((Message->CompletionCallback)
+ && (Message->CallBackSenderQueue == MessageQueue))
+ { /* Call the callback routine */
+ ASSERT(Message->QS_Flags & QS_SMRESULT);
+ co_IntCallSentMessageCallback(Message->CompletionCallback,
+ Message->Msg.hwnd,
+ Message->Msg.message,
+ Message->CompletionCallbackContext,
+ Message->lResult);
+ /* Set callback to NULL to prevent reentry */
+ Message->CompletionCallback = NULL;
+ }
else
{ /* Call the window procedure. */
Result = co_IntSendMessage( Message->Msg.hwnd,
@@ -478,8 +490,23 @@
to be cleaned up on thread termination anymore */
RemoveEntryList(&Message->ListEntry);
- /* remove the message from the dispatching list if needed, so lock the
sender's message queue */
- if (!(Message->HookMessage & MSQ_SENTNOWAIT))
+ if (Message->CompletionCallback)
+ {
+ if (Message->CallBackSenderQueue)
+ {
+ Message->lResult = Result;
+ Message->QS_Flags |= QS_SMRESULT;
+
+ /* queue it in the callers message queue */
+ InsertTailList(&Message->CallBackSenderQueue->SentMessagesListHead,
&Message->ListEntry);
+ MsqWakeQueue(Message->CallBackSenderQueue, QS_SENDMESSAGE, TRUE);
+ IntDereferenceMessageQueue(Message->CallBackSenderQueue);
+ }
+ return (TRUE);
+ }
+
+ /* remove the message from the dispatching list if there is a SenderQueue,
so lock the sender's message queue */
+ if ((Message->SenderQueue) || (Message->CallBackSenderQueue))
{
if (Message->DispatchingListEntry.Flink != NULL)
{
@@ -513,18 +540,8 @@
KeSetEvent(Message->CompletionEvent, IO_NO_INCREMENT, FALSE);
}
- /* Call the callback if the message was sent with SendMessageCallback */
- if (Message->CompletionCallback != NULL)
- {
- co_IntCallSentMessageCallback(Message->CompletionCallback,
- Message->Msg.hwnd,
- Message->Msg.message,
- Message->CompletionCallbackContext,
- Result);
- }
-
- /* Only if it is not a no wait message */
- if (!(Message->HookMessage & MSQ_SENTNOWAIT))
+ /* If SenderQueue then SenderQueue and MessageQueue was referenced,
dereference them here */
+ if (Message->SenderQueue)
{
IntDereferenceMessageQueue(Message->SenderQueue);
IntDereferenceMessageQueue(MessageQueue);
@@ -588,10 +605,11 @@
RemoveEntryList(&SentMessage->ListEntry);
ClearMsgBitsMask(MessageQueue, SentMessage->QS_Flags);
- /* remove the message from the dispatching list if neede */
- if ((!(SentMessage->HookMessage & MSQ_SENTNOWAIT))
+ /* If there was a SenderQueue then remove the message from this
threads dispatching list */
+ if (((SentMessage->SenderQueue) || (SentMessage->CallBackSenderQueue))
&& (SentMessage->DispatchingListEntry.Flink != NULL))
{
+ SentMessage->CallBackSenderQueue = NULL;
RemoveEntryList(&SentMessage->DispatchingListEntry);
}
@@ -607,8 +625,8 @@
ExFreePool((PVOID)SentMessage->Msg.lParam);
}
- /* Only if it is not a no wait message */
- if (!(SentMessage->HookMessage & MSQ_SENTNOWAIT))
+ /* If SenderQueue then SenderQueue and MessageQueue was referenced,
dereference them here */
+ if (SentMessage->SenderQueue)
{
/* dereference our and the sender's message queue */
IntDereferenceMessageQueue(MessageQueue);
@@ -628,8 +646,9 @@
}
NTSTATUS FASTCALL
-co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
- HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam,
+co_MsqSendMessage(PUSER_MESSAGE_QUEUE ThreadQueue, PUSER_MESSAGE_QUEUE
MessageQueue,
+ HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam, BOOL
HasPackedLParam,
+ SENDASYNCPROC CompletionCallback, ULONG_PTR
CompletionCallbackContext,
UINT uTimeout, BOOL Block, INT HookMessage,
ULONG_PTR *uResult)
{
@@ -637,55 +656,100 @@
PUSER_SENT_MESSAGE Message;
KEVENT CompletionEvent;
NTSTATUS WaitStatus;
- PUSER_MESSAGE_QUEUE ThreadQueue;
LARGE_INTEGER Timeout;
PLIST_ENTRY Entry;
+ BOOL WaitForCompletion;
LRESULT Result = 0; //// Result could be trashed. ////
+ /* Notification messages and some internal messages sent from the subsystem
must not block current
+ thread and therefore pass NULL as ThreadQueue. Callbacks also do not
block */
+ WaitForCompletion = ((ThreadQueue) && (!CompletionCallback));
+
if(!(Message = ExAllocatePoolWithTag(PagedPool, sizeof(USER_SENT_MESSAGE),
TAG_USRMSG)))
{
DPRINT1("MsqSendMessage(): Not enough memory to allocate a message");
return STATUS_INSUFFICIENT_RESOURCES;
}
- KeInitializeEvent(&CompletionEvent, NotificationEvent, FALSE);
+ /* Initialize event if calling thread will wait on completion */
+ if (WaitForCompletion)
+ KeInitializeEvent(&CompletionEvent, NotificationEvent, FALSE);
pti = PsGetCurrentThreadWin32Thread();
- ThreadQueue = pti->MessageQueue;
ptirec = MessageQueue->Thread->Tcb.Win32Thread;
ASSERT(ThreadQueue != MessageQueue);
ASSERT(ptirec->pcti); // Send must have a client side to receive it!!!!
Timeout.QuadPart = (LONGLONG) uTimeout * (LONGLONG) -10000;
- /* FIXME - increase reference counter of sender's message queue here */
-
Message->Msg.hwnd = Wnd;
Message->Msg.message = Msg;
Message->Msg.wParam = wParam;
Message->Msg.lParam = lParam;
- Message->CompletionEvent = &CompletionEvent;
- Message->Result = &Result;
Message->lResult = 0;
Message->QS_Flags = 0;
- Message->SenderQueue = ThreadQueue;
- Message->CallBackSenderQueue = NULL;
- IntReferenceMessageQueue(ThreadQueue);
- Message->CompletionCallback = NULL;
- Message->CompletionCallbackContext = 0;
+
+ if (WaitForCompletion)
+ {
+ /* Normal SendMessage that will block until the Windows Procedure
handles the message */
+ Message->SenderQueue = ThreadQueue;
+ Message->CompletionEvent = &CompletionEvent;
+ Message->Result = &Result;
+ }
+ else
+ {
+ /* Either a SendMessageCallback, Notify Message or Internal Message from
Win32k */
+ Message->SenderQueue = NULL;
+ Message->CompletionEvent = NULL;
+ Message->Result = NULL;
+ }
+
+ if (CompletionCallback)
+ {
+ Message->CallBackSenderQueue = ThreadQueue;
+ }
+ else
+ {
+ Message->CallBackSenderQueue = NULL;
+ }
+
+ /* Reference the ThreadQueue if there was one. For normal messages
+ the thread is dereferenced when the messages is processed by windows
procedure.
+ For callbacks it dereferenced once the callback message is processed and
placed back
+ into the sending message queue */
+ if (ThreadQueue != NULL)
+ IntReferenceMessageQueue(ThreadQueue);
+
+ Message->CompletionCallback = CompletionCallback;
+ Message->CompletionCallbackContext = CompletionCallbackContext;
Message->HookMessage = HookMessage;
- Message->HasPackedLParam = FALSE;
-
+ Message->HasPackedLParam = HasPackedLParam;
+
+ if (HasPackedLParam)
+ {
+ ASSERT(Message->SenderQueue == NULL);
+ }
+
IntReferenceMessageQueue(MessageQueue);
- /* add it to the list of pending messages */
- InsertTailList(&ThreadQueue->DispatchingMessagesHead,
&Message->DispatchingListEntry);
+ /* Add it to the list of pending messages if waiting on completion or if
message is callback.
+ This is done for callbacks as if the Sender terminates it will set the
CallBackSenderQueue member to NULL,
+ informing the windows procedure handling the message to discard the
callback procedure */
+ if (ThreadQueue != NULL)
+ InsertTailList(&ThreadQueue->DispatchingMessagesHead,
&Message->DispatchingListEntry);
/* queue it in the destination's message queue */
InsertTailList(&MessageQueue->SentMessagesListHead, &Message->ListEntry);
Message->QS_Flags = QS_SENDMESSAGE;
MsqWakeQueue(MessageQueue, QS_SENDMESSAGE, TRUE);
+
+ /* If not waiting on completion, dereference the MessageQueue and return */
+ if (!WaitForCompletion)
+ {
+ IntDereferenceMessageQueue(MessageQueue);
+ return STATUS_SUCCESS;
+ }
/* we can't access the Message anymore since it could have already been
deleted! */
@@ -854,7 +918,7 @@
* Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
* the window has the WS_EX_NOPARENTNOTIFY style.
*/
-static void MsqSendParentNotify( PWND pwnd, WORD event, WORD idChild, POINT pt
)
+void MsqSendParentNotify( PWND pwnd, WORD event, WORD idChild, POINT pt )
{
PWND pwndDesktop = UserGetWindowObject(IntGetDesktopWindow());
@@ -1466,8 +1530,8 @@
DPRINT("Notify the sender and remove a message from the queue that had
not been dispatched\n");
- /* remove the message from the dispatching list if needed */
- if ((!(CurrentSentMessage->HookMessage & MSQ_SENTNOWAIT))
+ /* remove the message from the dispatching list if there was a
SenderQueue */
+ if (((CurrentSentMessage->SenderQueue) ||
(CurrentSentMessage->CallBackSenderQueue))
&& (CurrentSentMessage->DispatchingListEntry.Flink != NULL))
{
RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
@@ -1485,8 +1549,8 @@
ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
}
- /* Only if it is not a no wait message */
- if (!(CurrentSentMessage->HookMessage & MSQ_SENTNOWAIT))
+ /* If SenderQueue then SenderQueue and MessageQueue was referenced,
dereference them here */
+ if (CurrentSentMessage->SenderQueue)
{
/* dereference our and the sender's message queue */
IntDereferenceMessageQueue(MessageQueue);
@@ -1525,8 +1589,8 @@
ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
}
- /* Only if it is not a no wait message */
- if (!(CurrentSentMessage->HookMessage & MSQ_SENTNOWAIT))
+ /* If SenderQueue then SenderQueue and MessageQueue was referenced,
dereference them here */
+ if (CurrentSentMessage->SenderQueue)
{
/* dereference our and the sender's message queue */
IntDereferenceMessageQueue(MessageQueue);