📄 msgqueue.c
字号:
{
CurrentEntry = RemoveHeadList(&MessageQueue->TimerListHead);
CurrentTimer = CONTAINING_RECORD(CurrentEntry, TIMER_ENTRY, ListEntry);
ExFreeToPagedLookasideList(&TimerLookasideList, CurrentTimer);
}
/* notify senders of dispatching messages. This needs to be cleaned up if e.g.
ExitThread() was called in a SendMessage() umode callback */
while (!IsListEmpty(&MessageQueue->LocalDispatchingMessagesHead))
{
CurrentEntry = RemoveHeadList(&MessageQueue->LocalDispatchingMessagesHead);
CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
ListEntry);
/* remove the message from the dispatching list */
if(CurrentSentMessage->DispatchingListEntry.Flink != NULL)
{
RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
}
DPRINT("Notify the sender, the thread has been terminated while dispatching a message!\n");
/* wake the sender's thread */
if (CurrentSentMessage->CompletionEvent != NULL)
{
KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
}
/* dereference our and the sender's message queue */
IntDereferenceMessageQueue(MessageQueue);
IntDereferenceMessageQueue(CurrentSentMessage->SenderQueue);
/* free the message */
ExFreePool(CurrentSentMessage);
}
/* tell other threads not to bother returning any info to us */
while (! IsListEmpty(&MessageQueue->DispatchingMessagesHead))
{
CurrentEntry = RemoveHeadList(&MessageQueue->DispatchingMessagesHead);
CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
DispatchingListEntry);
CurrentSentMessage->CompletionEvent = NULL;
CurrentSentMessage->Result = NULL;
/* do NOT dereference our message queue as it might get attempted to be
locked later */
}
}
PUSER_MESSAGE_QUEUE FASTCALL
MsqCreateMessageQueue(struct _ETHREAD *Thread)
{
PUSER_MESSAGE_QUEUE MessageQueue;
MessageQueue = (PUSER_MESSAGE_QUEUE)ExAllocatePoolWithTag(PagedPool,
sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO),
TAG_MSGQ);
if (!MessageQueue)
{
return NULL;
}
RtlZeroMemory(MessageQueue, sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO));
/* hold at least one reference until it'll be destroyed */
IntReferenceMessageQueue(MessageQueue);
/* initialize the queue */
if (!MsqInitializeMessageQueue(Thread, MessageQueue))
{
IntDereferenceMessageQueue(MessageQueue);
return NULL;
}
return MessageQueue;
}
VOID FASTCALL
MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
{
PDESKTOP_OBJECT desk;
/* remove the message queue from any desktops */
if ((desk = (PDESKTOP_OBJECT)InterlockedExchange((LONG*)&MessageQueue->Desktop, 0)))
{
InterlockedExchange((LONG*)&desk->ActiveMessageQueue, 0);
IntDereferenceMessageQueue(MessageQueue);
}
/* clean it up */
MsqCleanupMessageQueue(MessageQueue);
/* decrease the reference counter, if it hits zero, the queue will be freed */
IntDereferenceMessageQueue(MessageQueue);
}
PHOOKTABLE FASTCALL
MsqGetHooks(PUSER_MESSAGE_QUEUE Queue)
{
return Queue->Hooks;
}
VOID FASTCALL
MsqSetHooks(PUSER_MESSAGE_QUEUE Queue, PHOOKTABLE Hooks)
{
Queue->Hooks = Hooks;
}
LPARAM FASTCALL
MsqSetMessageExtraInfo(LPARAM lParam)
{
LPARAM Ret;
PUSER_MESSAGE_QUEUE MessageQueue;
MessageQueue = PsGetCurrentThreadWin32Thread()->MessageQueue;
if(!MessageQueue)
{
return 0;
}
Ret = MessageQueue->ExtraInfo;
MessageQueue->ExtraInfo = lParam;
return Ret;
}
LPARAM FASTCALL
MsqGetMessageExtraInfo(VOID)
{
PUSER_MESSAGE_QUEUE MessageQueue;
MessageQueue = PsGetCurrentThreadWin32Thread()->MessageQueue;
if(!MessageQueue)
{
return 0;
}
return MessageQueue->ExtraInfo;
}
HWND FASTCALL
MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue, ULONG Type, HWND hWnd)
{
HWND Prev;
switch(Type)
{
case MSQ_STATE_CAPTURE:
Prev = MessageQueue->CaptureWindow;
MessageQueue->CaptureWindow = hWnd;
return Prev;
case MSQ_STATE_ACTIVE:
Prev = MessageQueue->ActiveWindow;
MessageQueue->ActiveWindow = hWnd;
return Prev;
case MSQ_STATE_FOCUS:
Prev = MessageQueue->FocusWindow;
MessageQueue->FocusWindow = hWnd;
return Prev;
case MSQ_STATE_MENUOWNER:
Prev = MessageQueue->MenuOwner;
MessageQueue->MenuOwner = hWnd;
return Prev;
case MSQ_STATE_MOVESIZE:
Prev = MessageQueue->MoveSize;
MessageQueue->MoveSize = hWnd;
return Prev;
case MSQ_STATE_CARET:
ASSERT(MessageQueue->CaretInfo);
Prev = MessageQueue->CaretInfo->hWnd;
MessageQueue->CaretInfo->hWnd = hWnd;
return Prev;
}
return NULL;
}
#ifndef NDEBUG
static VOID FASTCALL
DumpTimerList(PUSER_MESSAGE_QUEUE MessageQueue)
{
PLIST_ENTRY Current;
PTIMER_ENTRY Timer;
Current = MessageQueue->TimerListHead.Flink;
if (Current == &MessageQueue->TimerListHead)
{
DPRINT("timer list is empty for queue %p\n", MessageQueue);
}
while (Current != &MessageQueue->TimerListHead)
{
Timer = CONTAINING_RECORD(Current, TIMER_ENTRY, ListEntry);
DPRINT("queue %p timer %p expiry %I64d wnd %x id %p period %u timerproc %p msg %u\n",
MessageQueue, Timer, Timer->ExpiryTime.QuadPart, Timer->Wnd, Timer->IDEvent,
Timer->Period, Timer->TimerFunc, Timer->Msg);
Current = Current->Flink;
}
}
#endif /* ! defined(NDEBUG) */
/* Must have the message queue locked while calling this */
static VOID FASTCALL
InsertTimer(PUSER_MESSAGE_QUEUE MessageQueue, PTIMER_ENTRY NewTimer)
{
PLIST_ENTRY Current;
Current = MessageQueue->TimerListHead.Flink;
while (Current != &MessageQueue->TimerListHead)
{
if (NewTimer->ExpiryTime.QuadPart <
CONTAINING_RECORD(Current, TIMER_ENTRY, ListEntry)->ExpiryTime.QuadPart)
{
break;
}
Current = Current->Flink;
}
InsertTailList(Current, &NewTimer->ListEntry);
}
/* Must have the message queue locked while calling this */
static PTIMER_ENTRY FASTCALL
RemoveTimer(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd, UINT_PTR IDEvent, UINT Msg)
{
PTIMER_ENTRY Timer;
PLIST_ENTRY EnumEntry;
/* Remove timer if already in the queue */
EnumEntry = MessageQueue->TimerListHead.Flink;
while (EnumEntry != &MessageQueue->TimerListHead)
{
Timer = CONTAINING_RECORD(EnumEntry, TIMER_ENTRY, ListEntry);
EnumEntry = EnumEntry->Flink;
if (Timer->Wnd == Wnd &&
Timer->IDEvent == IDEvent &&
Timer->Msg == Msg)
{
RemoveEntryList(&Timer->ListEntry);
return Timer;
}
}
return NULL;
}
BOOLEAN FASTCALL
MsqSetTimer(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd,
UINT_PTR IDEvent, UINT Period, TIMERPROC TimerFunc,
UINT Msg)
{
PTIMER_ENTRY Timer;
LARGE_INTEGER CurrentTime;
DPRINT("MsqSetTimer queue %p wnd %x id %p period %u timerproc %p msg %d\n",
MessageQueue, Wnd, IDEvent, Period, TimerFunc, Msg);
Timer = RemoveTimer(MessageQueue, Wnd, IDEvent, Msg);
if (NULL == Timer)
{
Timer = ExAllocateFromPagedLookasideList(&TimerLookasideList);
if (NULL == Timer)
{
DPRINT1("Failed to allocate timer entry\n");
return FALSE;
}
DPRINT("Allocated new timer entry %p\n", Timer);
Timer->Wnd = Wnd;
Timer->IDEvent = IDEvent;
Timer->Msg = Msg;
}
else
{
DPRINT("Updating existing timer entry %p\n", Timer);
}
KeQuerySystemTime(&CurrentTime);
Timer->ExpiryTime.QuadPart = CurrentTime.QuadPart +
(ULONGLONG) Period * (ULONGLONG) 10000;
Timer->Period = Period;
Timer->TimerFunc = TimerFunc;
DPRINT("Insert timer now %I64d expiry %I64d\n", CurrentTime.QuadPart,
Timer->ExpiryTime.QuadPart);
InsertTimer(MessageQueue, Timer);
#ifndef NDEBUG
DumpTimerList(MessageQueue);
#endif /* ! defined(NDEBUG) */
return TRUE;
}
BOOLEAN FASTCALL
MsqKillTimer(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd,
UINT_PTR IDEvent, UINT Msg)
{
PTIMER_ENTRY Timer;
DPRINT("MsqKillTimer queue %p wnd %x id %p msg %d\n",
MessageQueue, Wnd, IDEvent, Msg);
Timer = RemoveTimer(MessageQueue, Wnd, IDEvent, Msg);
if (NULL == Timer)
{
DPRINT("Failed to remove timer from list, not found\n");
}
else
{
ExFreeToPagedLookasideList(&TimerLookasideList, Timer);
}
#ifndef NDEBUG
DumpTimerList(MessageQueue);
#endif /* ! defined(NDEBUG) */
return NULL != Timer;
}
BOOLEAN FASTCALL
MsqGetTimerMessage(PUSER_MESSAGE_QUEUE MessageQueue,
HWND WndFilter, UINT MsgFilterMin, UINT MsgFilterMax,
MSG *Msg, BOOLEAN Restart)
{
PTIMER_ENTRY Timer;
LARGE_INTEGER CurrentTime;
LARGE_INTEGER LargeTickCount;
PLIST_ENTRY EnumEntry;
BOOLEAN GotMessage;
DPRINT("MsqGetTimerMessage queue %p msg %p restart %s\n",
MessageQueue, Msg, Restart ? "TRUE" : "FALSE");
KeQuerySystemTime(&CurrentTime);
DPRINT("Current time %I64d\n", CurrentTime.QuadPart);
EnumEntry = MessageQueue->TimerListHead.Flink;
GotMessage = FALSE;
while (EnumEntry != &MessageQueue->TimerListHead)
{
Timer = CONTAINING_RECORD(MessageQueue->TimerListHead.Flink,
TIMER_ENTRY, ListEntry);
DPRINT("Checking timer %p wnd %x expiry %I64d\n", Timer, Timer->Wnd,
Timer->ExpiryTime.QuadPart);
EnumEntry = EnumEntry->Flink;
if ((NULL == WndFilter || Timer->Wnd == WndFilter) &&
((MsgFilterMin == 0 && MsgFilterMax == 0) ||
(MsgFilterMin <= Timer->Msg &&
Timer->Msg <= MsgFilterMax)))
{
if (Timer->ExpiryTime.QuadPart <= CurrentTime.QuadPart)
{
DPRINT("Timer is expired\n");
GotMessage = TRUE;
break;
}
else
{
DPRINT("No need to check later timers\n");
break;
}
}
else
{
DPRINT("timer %p (wnd %x msg %d) failed filter wnd %x msgmin %d msgmax %d\n",
Timer, Timer->Wnd, Timer->Msg, WndFilter, MsgFilterMin, MsgFilterMax);
}
}
if (! GotMessage)
{
DPRINT("No timer pending\n");
return FALSE;
}
Msg->hwnd = Timer->Wnd;
Msg->message = Timer->Msg;
Msg->wParam = (WPARAM) Timer->IDEvent;
Msg->lParam = (LPARAM) Timer->TimerFunc;
KeQueryTickCount(&LargeTickCount);
Msg->time = MsqCalculateMessageTime(&LargeTickCount);
IntGetCursorLocation(PsGetCurrentThreadWin32Thread()->Desktop->WindowStation,
&Msg->pt);
if (Restart)
{
RemoveEntryList(&Timer->ListEntry);
Timer->ExpiryTime.QuadPart = CurrentTime.QuadPart +
(ULONGLONG) Timer->Period * (ULONGLONG) 10000;
DPRINT("Restarting timer %p expires %I64d\n", Timer, Timer->ExpiryTime.QuadPart);
InsertTimer(MessageQueue, Timer);
#ifndef NDEBUG
DumpTimerList(MessageQueue);
#endif /* ! defined(NDEBUG) */
}
DPRINT("Created message wnd %x msg %d wParam %u lParam %u\n", Msg->hwnd, Msg->message,
Msg->wParam, Msg->lParam);
return TRUE;
}
VOID FASTCALL
MsqRemoveTimersWindow(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd)
{
PTIMER_ENTRY Timer;
PLIST_ENTRY EnumEntry;
DPRINT("MsqRemoveTimersWindow queue %p wnd %x\n", MessageQueue, Wnd);
EnumEntry = MessageQueue->TimerListHead.Flink;
while (EnumEntry != &MessageQueue->TimerListHead)
{
Timer = CONTAINING_RECORD(EnumEntry, TIMER_ENTRY, ListEntry);
EnumEntry = EnumEntry->Flink;
if (Timer->Wnd == Wnd)
{
DPRINT("Removing timer %p because its window is going away\n", Timer);
RemoveEntryList(&Timer->ListEntry);
ExFreeToPagedLookasideList(&TimerLookasideList, Timer);
}
}
#ifndef NDEBUG
DumpTimerList(MessageQueue);
#endif /* ! defined(NDEBUG) */
}
BOOLEAN FASTCALL
MsqGetFirstTimerExpiry(PUSER_MESSAGE_QUEUE MessageQueue,
HWND WndFilter, UINT MsgFilterMin, UINT MsgFilterMax,
PLARGE_INTEGER FirstTimerExpiry)
{
PTIMER_ENTRY Timer;
PLIST_ENTRY EnumEntry;
DPRINT("MsqGetFirstTimerExpiry queue %p wndfilter %x msgfiltermin %d msgfiltermax %d expiry %p\n",
MessageQueue, WndFilter, MsgFilterMin, MsgFilterMax, FirstTimerExpiry);
EnumEntry = MessageQueue->TimerListHead.Flink;
while (EnumEntry != &MessageQueue->TimerListHead)
{
Timer = CONTAINING_RECORD(MessageQueue->TimerListHead.Flink,
TIMER_ENTRY, ListEntry);
EnumEntry = EnumEntry->Flink;
if ((NULL == WndFilter || Timer->Wnd == WndFilter) &&
((MsgFilterMin == 0 && MsgFilterMax == 0) ||
(MsgFilterMin <= Timer->Msg &&
Timer->Msg <= MsgFilterMax)))
{
*FirstTimerExpiry = Timer->ExpiryTime;
DPRINT("First timer expires %I64d\n", Timer->ExpiryTime);
return TRUE;
}
}
return FALSE;
}
/* EOF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -