📄 msgqueue.c
字号:
PUSER_MESSAGE* Message)
{
KIRQL OldIrql;
POINT ScreenPoint;
BOOL Accept, Freed;
PLIST_ENTRY CurrentEntry;
PWINDOW_OBJECT DesktopWindow = NULL;
PVOID WaitObjects[2];
NTSTATUS WaitStatus;
DECLARE_RETURN(BOOL);
USER_REFERENCE_ENTRY Ref;
WaitObjects[1] = MessageQueue->NewMessages;
WaitObjects[0] = &HardwareMessageQueueLock;
do
{
UserLeaveCo();
WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
UserMode, FALSE, NULL, NULL);
UserEnterCo();
while (co_MsqDispatchOneSentMessage(MessageQueue))
{
;
}
}
while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 != WaitStatus);
DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
if (DesktopWindow) UserRefObjectCo(DesktopWindow, &Ref);//can DesktopWindow be NULL?
/* Process messages in the message queue itself. */
IntLockHardwareMessageQueue(MessageQueue);
CurrentEntry = MessageQueue->HardwareMessagesListHead.Flink;
while (CurrentEntry != &MessageQueue->HardwareMessagesListHead)
{
PUSER_MESSAGE Current =
CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
CurrentEntry = CurrentEntry->Flink;
if (Current->Msg.message >= WM_MOUSEFIRST &&
Current->Msg.message <= WM_MOUSELAST)
{
Accept = co_MsqTranslateMouseMessage(MessageQueue, hWnd, FilterLow, FilterHigh,
Current, Remove, &Freed,
DesktopWindow, &ScreenPoint, FALSE);
if (Accept)
{
if (Remove)
{
RemoveEntryList(&Current->ListEntry);
}
IntUnLockHardwareMessageQueue(MessageQueue);
IntUnLockSystemHardwareMessageQueueLock(FALSE);
*Message = Current;
RETURN(TRUE);
}
}
}
IntUnLockHardwareMessageQueue(MessageQueue);
/* Now try the global queue. */
/* Transfer all messages from the DPC accessible queue to the main queue. */
IntLockSystemMessageQueue(OldIrql);
while (SystemMessageQueueCount > 0)
{
PUSER_MESSAGE UserMsg;
MSG Msg;
BOOL ProcessMessage;
ASSERT(SystemMessageQueueHead < SYSTEM_MESSAGE_QUEUE_SIZE);
Msg = SystemMessageQueue[SystemMessageQueueHead];
SystemMessageQueueHead =
(SystemMessageQueueHead + 1) % SYSTEM_MESSAGE_QUEUE_SIZE;
SystemMessageQueueCount--;
IntUnLockSystemMessageQueue(OldIrql);
if (WM_MOUSEFIRST <= Msg.message && Msg.message <= WM_MOUSELAST)
{
MSLLHOOKSTRUCT MouseHookData;
MouseHookData.pt.x = LOWORD(Msg.lParam);
MouseHookData.pt.y = HIWORD(Msg.lParam);
switch(Msg.message)
{
case WM_MOUSEWHEEL:
MouseHookData.mouseData = MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg.wParam));
break;
case WM_XBUTTONDOWN:
case WM_XBUTTONUP:
case WM_XBUTTONDBLCLK:
case WM_NCXBUTTONDOWN:
case WM_NCXBUTTONUP:
case WM_NCXBUTTONDBLCLK:
MouseHookData.mouseData = MAKELONG(0, HIWORD(Msg.wParam));
break;
default:
MouseHookData.mouseData = 0;
break;
}
MouseHookData.flags = 0;
MouseHookData.time = Msg.time;
MouseHookData.dwExtraInfo = 0;
ProcessMessage = (0 == co_HOOK_CallHooks(WH_MOUSE_LL, HC_ACTION,
Msg.message, (LPARAM) &MouseHookData));
}
else
{
ProcessMessage = TRUE;
}
if (ProcessMessage)
{
UserMsg = ExAllocateFromPagedLookasideList(&MessageLookasideList);
/* What to do if out of memory? For now we just panic a bit in debug */
ASSERT(UserMsg);
UserMsg->FreeLParam = FALSE;
UserMsg->Msg = Msg;
InsertTailList(&HardwareMessageQueueHead, &UserMsg->ListEntry);
}
IntLockSystemMessageQueue(OldIrql);
}
HardwareMessageQueueStamp++;
IntUnLockSystemMessageQueue(OldIrql);
/* Process messages in the queue until we find one to return. */
CurrentEntry = HardwareMessageQueueHead.Flink;
while (CurrentEntry != &HardwareMessageQueueHead)
{
PUSER_MESSAGE Current =
CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
CurrentEntry = CurrentEntry->Flink;
RemoveEntryList(&Current->ListEntry);
HardwareMessageQueueStamp++;
if (Current->Msg.message >= WM_MOUSEFIRST &&
Current->Msg.message <= WM_MOUSELAST)
{
const ULONG ActiveStamp = HardwareMessageQueueStamp;
/* Translate the message. */
Accept = co_MsqTranslateMouseMessage(MessageQueue, hWnd, FilterLow, FilterHigh,
Current, Remove, &Freed,
DesktopWindow, &ScreenPoint, TRUE);
if (Accept)
{
/* Check for no more messages in the system queue. */
IntLockSystemMessageQueue(OldIrql);
if (SystemMessageQueueCount == 0 &&
IsListEmpty(&HardwareMessageQueueHead))
{
KeClearEvent(&HardwareMessageEvent);
}
IntUnLockSystemMessageQueue(OldIrql);
/*
If we aren't removing the message then add it to the private
queue.
*/
if (!Remove)
{
IntLockHardwareMessageQueue(MessageQueue);
if(Current->Msg.message == WM_MOUSEMOVE)
{
if(MessageQueue->MouseMoveMsg)
{
RemoveEntryList(&MessageQueue->MouseMoveMsg->ListEntry);
ExFreePool(MessageQueue->MouseMoveMsg);
}
MessageQueue->MouseMoveMsg = Current;
}
InsertTailList(&MessageQueue->HardwareMessagesListHead,
&Current->ListEntry);
IntUnLockHardwareMessageQueue(MessageQueue);
}
IntUnLockSystemHardwareMessageQueueLock(FALSE);
*Message = Current;
RETURN(TRUE);
}
/* If the contents of the queue changed then restart processing. */
if (HardwareMessageQueueStamp != ActiveStamp)
{
CurrentEntry = HardwareMessageQueueHead.Flink;
continue;
}
}
}
/* Check if the system message queue is now empty. */
IntLockSystemMessageQueue(OldIrql);
if (SystemMessageQueueCount == 0 && IsListEmpty(&HardwareMessageQueueHead))
{
KeClearEvent(&HardwareMessageEvent);
}
IntUnLockSystemMessageQueue(OldIrql);
IntUnLockSystemHardwareMessageQueueLock(FALSE);
RETURN(FALSE);
CLEANUP:
if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
END_CLEANUP;
}
VOID FASTCALL
co_MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
PUSER_MESSAGE_QUEUE FocusMessageQueue;
MSG Msg;
LARGE_INTEGER LargeTickCount;
KBDLLHOOKSTRUCT KbdHookData;
DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
uMsg, wParam, lParam);
Msg.hwnd = 0;
Msg.message = uMsg;
Msg.wParam = wParam;
Msg.lParam = lParam;
KeQueryTickCount(&LargeTickCount);
Msg.time = MsqCalculateMessageTime(&LargeTickCount);
/* We can't get the Msg.pt point here since we don't know thread
(and thus the window station) the message will end up in yet. */
KbdHookData.vkCode = Msg.wParam;
KbdHookData.scanCode = (Msg.lParam >> 16) & 0xff;
KbdHookData.flags = (0 == (Msg.lParam & 0x01000000) ? 0 : LLKHF_EXTENDED) |
(0 == (Msg.lParam & 0x20000000) ? 0 : LLKHF_ALTDOWN) |
(0 == (Msg.lParam & 0x80000000) ? 0 : LLKHF_UP);
KbdHookData.time = Msg.time;
KbdHookData.dwExtraInfo = 0;
if (co_HOOK_CallHooks(WH_KEYBOARD_LL, HC_ACTION, Msg.message, (LPARAM) &KbdHookData))
{
DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
Msg.message, Msg.wParam, Msg.lParam);
return;
}
FocusMessageQueue = IntGetFocusMessageQueue();
if (FocusMessageQueue == NULL)
{
DPRINT("No focus message queue\n");
return;
}
if (FocusMessageQueue->FocusWindow != (HWND)0)
{
Msg.hwnd = FocusMessageQueue->FocusWindow;
DPRINT("Msg.hwnd = %x\n", Msg.hwnd);
IntGetCursorLocation(FocusMessageQueue->Desktop->WindowStation,
&Msg.pt);
MsqPostMessage(FocusMessageQueue, &Msg, FALSE, QS_KEY);
}
else
{
DPRINT("Invalid focus window handle\n");
}
}
VOID FASTCALL
MsqPostHotKeyMessage(PVOID Thread, HWND hWnd, WPARAM wParam, LPARAM lParam)
{
PWINDOW_OBJECT Window;
PW32THREAD Win32Thread;
PWINSTATION_OBJECT WinSta;
MSG Mesg;
LARGE_INTEGER LargeTickCount;
NTSTATUS Status;
Status = ObReferenceObjectByPointer (Thread,
THREAD_ALL_ACCESS,
PsThreadType,
KernelMode);
if (!NT_SUCCESS(Status))
return;
Win32Thread = ((PETHREAD)Thread)->Tcb.Win32Thread;
if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
{
ObDereferenceObject ((PETHREAD)Thread);
return;
}
WinSta = Win32Thread->Desktop->WindowStation;
Window = IntGetWindowObject(hWnd);
if (!Window)
{
ObDereferenceObject ((PETHREAD)Thread);
return;
}
Mesg.hwnd = hWnd;
Mesg.message = WM_HOTKEY;
Mesg.wParam = wParam;
Mesg.lParam = lParam;
KeQueryTickCount(&LargeTickCount);
Mesg.time = MsqCalculateMessageTime(&LargeTickCount);
IntGetCursorLocation(WinSta, &Mesg.pt);
MsqPostMessage(Window->MessageQueue, &Mesg, FALSE, QS_HOTKEY);
ObmDereferenceObject(Window);
ObDereferenceObject (Thread);
// InsertHeadList(&pThread->MessageQueue->PostedMessagesListHead,
// &Message->ListEntry);
// KeSetEvent(pThread->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
}
PUSER_MESSAGE FASTCALL
MsqCreateMessage(LPMSG Msg, BOOLEAN FreeLParam)
{
PUSER_MESSAGE Message;
Message = ExAllocateFromPagedLookasideList(&MessageLookasideList);
if (!Message)
{
return NULL;
}
Message->FreeLParam = FreeLParam;
RtlMoveMemory(&Message->Msg, Msg, sizeof(MSG));
return Message;
}
VOID FASTCALL
MsqDestroyMessage(PUSER_MESSAGE Message)
{
ExFreeToPagedLookasideList(&MessageLookasideList, Message);
}
VOID FASTCALL
co_MsqDispatchSentNotifyMessages(PUSER_MESSAGE_QUEUE MessageQueue)
{
PLIST_ENTRY ListEntry;
PUSER_SENT_MESSAGE_NOTIFY Message;
while (!IsListEmpty(&MessageQueue->SentMessagesListHead))
{
ListEntry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
Message = CONTAINING_RECORD(ListEntry, USER_SENT_MESSAGE_NOTIFY,
ListEntry);
co_IntCallSentMessageCallback(Message->CompletionCallback,
Message->hWnd,
Message->Msg,
Message->CompletionCallbackContext,
Message->Result);
}
}
BOOLEAN FASTCALL
MsqPeekSentMessages(PUSER_MESSAGE_QUEUE MessageQueue)
{
return(!IsListEmpty(&MessageQueue->SentMessagesListHead));
}
BOOLEAN FASTCALL
co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
{
PUSER_SENT_MESSAGE Message;
PLIST_ENTRY Entry;
LRESULT Result;
BOOL SenderReturned;
PUSER_SENT_MESSAGE_NOTIFY NotifyMessage;
if (IsListEmpty(&MessageQueue->SentMessagesListHead))
{
return(FALSE);
}
/* remove it from the list of pending messages */
Entry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
/* insert it to the list of messages that are currently dispatched by this
message queue */
InsertTailList(&MessageQueue->LocalDispatchingMessagesHead,
&Message->ListEntry);
if (Message->HookMessage)
{
Result = co_HOOK_CallHooks(Message->Msg.message,
(INT) Message->Msg.hwnd,
Message->Msg.wParam,
Message->Msg.lParam);
}
else
{
/* Call the window procedure. */
Result = co_IntSendMessage(Message->Msg.hwnd,
Message->Msg.message,
Message->Msg.wParam,
Message->Msg.lParam);
}
/* remove the message from the local dispatching list, because it doesn't need
to be cleaned up on thread termination anymore */
RemoveEntryList(&Message->ListEntry);
/* remove the message from the dispatching list, so lock the sender's message queue */
SenderReturned = (Message->DispatchingListEntry.Flink == NULL);
if(!SenderReturned)
{
/* only remove it from the dispatching list if not already removed by a timeout */
RemoveEntryList(&Message->DispatchingListEntry);
}
/* still keep the sender's message queue locked, so the sender can't exit the
MsqSendMessage() function (if timed out) */
/* Let the sender know the result. */
if (Message->Result != NULL)
{
*Message->Result = Result;
}
/* Notify the sender. */
if (Message->CompletionEvent != NULL)
{
KeSetEvent(Message->CompletionEvent, IO_NO_INCREMENT, FALSE);
}
/* Notify the sender if they specified a callback. */
if (!SenderReturned && Message->CompletionCallback != NULL)
{
if(!(NotifyMessage = ExAllocatePoolWithTag(NonPagedPool,
sizeof(USER_SENT_MESSAGE_NOTIFY), TAG_USRMSG)))
{
DPRINT1("MsqDispatchOneSentMessage(): Not enough memory to create a callback notify message\n");
goto Notified;
}
NotifyMessage->CompletionCallback =
Message->CompletionCallback;
NotifyMessage->CompletionCallbackContext =
Message->CompletionCallbackContext;
NotifyMessage->Result = Result;
NotifyMessage->hWnd = Message->Msg.hwnd;
NotifyMessage->Msg = Message->Msg.message;
MsqSendNotifyMessage(Message->SenderQueue, NotifyMessage);
}
Notified:
/* dereference both sender and our queue */
IntDereferenceMessageQueue(MessageQueue);
IntDereferenceMessageQueue(Message->SenderQueue);
/* free the message */
ExFreePool(Message);
return(TRUE);
}
VOID STDCALL
MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
{
PUSER_SENT_MESSAGE SentMessage;
PUSER_MESSAGE PostedMessage;
PUSER_MESSAGE_QUEUE MessageQueue;
PLIST_ENTRY CurrentEntry, ListHead;
PWINDOW_OBJECT Window = pWindow;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -