mirror of
https://github.com/reactos/reactos.git
synced 2025-07-28 02:11:54 +00:00
[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. svn path=/trunk/; revision=51255
This commit is contained in:
parent
9990b69447
commit
771f834c43
4 changed files with 155 additions and 66 deletions
|
@ -115,15 +115,19 @@ IntCallLowLevelEvent( PEVENTHOOK pEH,
|
|||
|
||||
/* 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);
|
||||
|
|
|
@ -88,15 +88,19 @@ IntCallLowLevelHook( PHOOK Hook,
|
|||
|
||||
/* 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);
|
||||
|
|
|
@ -1261,11 +1261,15 @@ co_IntSendMessageTimeoutSingle( HWND hWnd,
|
|||
|
||||
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 @@ co_IntSendMessageNoWait(HWND hWnd,
|
|||
LPARAM lParam)
|
||||
{
|
||||
ULONG_PTR Result = 0;
|
||||
/* Piggyback off CallBack */
|
||||
co_IntSendMessageWithCallBack(hWnd,
|
||||
Msg,
|
||||
wParam,
|
||||
|
@ -1372,12 +1377,12 @@ co_IntSendMessageNoWait(HWND hWnd,
|
|||
*/
|
||||
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 @@ co_IntSendMessageWithCallBack( HWND hWnd,
|
|||
}
|
||||
|
||||
/* 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 @@ co_IntSendMessageWithCallBack( HWND hWnd,
|
|||
*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 @@ co_IntSendMessageWithCallBack( HWND hWnd,
|
|||
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;
|
||||
MsqWakeQueue(Window->head.pti->MessageQueue, QS_SENDMESSAGE, FALSE);
|
||||
|
||||
if (CompletionCallback)
|
||||
InsertTailList(&Win32Thread->MessageQueue->DispatchingMessagesHead, &Message->DispatchingListEntry);
|
||||
InsertTailList(&Window->head.pti->MessageQueue->SentMessagesListHead, &Message->ListEntry);
|
||||
MsqWakeQueue(Window->head.pti->MessageQueue, QS_SENDMESSAGE, FALSE);
|
||||
IntDereferenceMessageQueue(Window->head.pti->MessageQueue);
|
||||
|
||||
RETURN(TRUE);
|
||||
|
@ -2112,7 +2129,7 @@ NtUserMessageCall( HWND hWnd,
|
|||
{
|
||||
co_IntSendMessageTimeout( HWND_BROADCAST,
|
||||
Msg,
|
||||
wParam,
|
||||
wParam,
|
||||
lParam,
|
||||
SMTO_NORMAL,
|
||||
2000,
|
||||
|
|
|
@ -423,7 +423,7 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
|
|||
PLIST_ENTRY Entry;
|
||||
LRESULT Result;
|
||||
PTHREADINFO pti;
|
||||
|
||||
|
||||
if (IsListEmpty(&MessageQueue->SentMessagesListHead))
|
||||
{
|
||||
return(FALSE);
|
||||
|
@ -466,6 +466,18 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
|
|||
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 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
|
|||
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 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
|
|||
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 @@ MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
|
|||
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 @@ MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
|
|||
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 @@ MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
|
|||
}
|
||||
|
||||
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,49 +656,87 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
|
|||
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;
|
||||
Message->HookMessage = HookMessage;
|
||||
Message->HasPackedLParam = FALSE;
|
||||
|
||||
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 = 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);
|
||||
|
@ -687,6 +744,13 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
|
|||
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! */
|
||||
|
||||
if(Block)
|
||||
|
@ -854,7 +918,7 @@ MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue, ULONG ExitCode)
|
|||
* 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 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
|
|||
|
||||
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 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
|
|||
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 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
|
|||
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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue