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/nt…
==============================================================================
--- 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/nt…
==============================================================================
--- 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/nt…
==============================================================================
--- 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/nt…
==============================================================================
--- 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);