msgqueue.c
来自「一个类似windows」· C语言 代码 · 共 1,894 行 · 第 1/5 页
C
1,894 行
DPRINT("MsqSendMessage (blocked) timed out\n");
}
while (co_MsqDispatchOneSentMessage(ThreadQueue))
;
}
else
{
PVOID WaitObjects[2];
WaitObjects[0] = &CompletionEvent;
WaitObjects[1] = ThreadQueue->NewMessages;
do
{
UserLeaveCo();
WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
UserMode, FALSE, (uTimeout ? &Timeout : NULL), NULL);
UserEnterCo();
if(WaitStatus == STATUS_TIMEOUT)
{
/* look up if the message has not yet been dispatched, if so
make sure it can't pass a result and it must not set the completion event anymore */
Entry = MessageQueue->SentMessagesListHead.Flink;
while (Entry != &MessageQueue->SentMessagesListHead)
{
if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry)
== Message)
{
/* we can access Message here, it's secure because the message queue is locked
and the message is still hasn't been dispatched */
Message->CompletionEvent = NULL;
Message->Result = NULL;
break;
}
Entry = Entry->Flink;
}
/* remove from the local dispatching list so the other thread knows,
it can't pass a result and it must not set the completion event anymore */
Entry = ThreadQueue->DispatchingMessagesHead.Flink;
while (Entry != &ThreadQueue->DispatchingMessagesHead)
{
if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry)
== Message)
{
/* we can access Message here, it's secure because the sender's message is locked
and the message has definitely not yet been destroyed, otherwise it would
have been removed from this list by the dispatching routine right after
dispatching the message */
Message->CompletionEvent = NULL;
Message->Result = NULL;
RemoveEntryList(&Message->DispatchingListEntry);
Message->DispatchingListEntry.Flink = NULL;
break;
}
Entry = Entry->Flink;
}
DPRINT("MsqSendMessage timed out\n");
break;
}
while (co_MsqDispatchOneSentMessage(ThreadQueue))
;
}
while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 != WaitStatus);
}
if(WaitStatus != STATUS_TIMEOUT)
*uResult = (STATUS_WAIT_0 == WaitStatus ? Result : -1);
return WaitStatus;
}
VOID FASTCALL
MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg, BOOLEAN FreeLParam,
DWORD MessageBits)
{
PUSER_MESSAGE Message;
if(!(Message = MsqCreateMessage(Msg, FreeLParam)))
{
return;
}
InsertTailList(&MessageQueue->PostedMessagesListHead,
&Message->ListEntry);
MessageQueue->QueueBits |= MessageBits;
MessageQueue->ChangedBits |= MessageBits;
if (MessageQueue->WakeMask & MessageBits)
KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
}
VOID FASTCALL
MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue, ULONG ExitCode)
{
MessageQueue->QuitPosted = TRUE;
MessageQueue->QuitExitCode = ExitCode;
MessageQueue->QueueBits |= QS_POSTMESSAGE;
MessageQueue->ChangedBits |= QS_POSTMESSAGE;
if (MessageQueue->WakeMask & QS_POSTMESSAGE)
KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
}
BOOLEAN STDCALL
co_MsqFindMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
IN BOOLEAN Hardware,
IN BOOLEAN Remove,
IN HWND Wnd,
IN UINT MsgFilterLow,
IN UINT MsgFilterHigh,
OUT PUSER_MESSAGE* Message)
{
PLIST_ENTRY CurrentEntry;
PUSER_MESSAGE CurrentMessage;
PLIST_ENTRY ListHead;
if (Hardware)
{
return(co_MsqPeekHardwareMessage(MessageQueue, Wnd,
MsgFilterLow, MsgFilterHigh,
Remove, Message));
}
CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
ListHead = &MessageQueue->PostedMessagesListHead;
while (CurrentEntry != ListHead)
{
CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
ListEntry);
if ((Wnd == 0 || Wnd == CurrentMessage->Msg.hwnd) &&
((MsgFilterLow == 0 && MsgFilterHigh == 0) ||
(MsgFilterLow <= CurrentMessage->Msg.message &&
MsgFilterHigh >= CurrentMessage->Msg.message)))
{
if (Remove)
{
RemoveEntryList(&CurrentMessage->ListEntry);
}
*Message = CurrentMessage;
return(TRUE);
}
CurrentEntry = CurrentEntry->Flink;
}
return(FALSE);
}
NTSTATUS FASTCALL
co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, HWND WndFilter,
UINT MsgFilterMin, UINT MsgFilterMax)
{
PVOID WaitObjects[2] = {MessageQueue->NewMessages, &HardwareMessageEvent};
LARGE_INTEGER TimerExpiry;
PLARGE_INTEGER Timeout;
NTSTATUS ret;
if (MsqGetFirstTimerExpiry(MessageQueue, WndFilter, MsgFilterMin, MsgFilterMax, &TimerExpiry))
{
Timeout = &TimerExpiry;
}
else
{
Timeout = NULL;
}
UserLeaveCo();
ret = KeWaitForMultipleObjects(2,
WaitObjects,
WaitAny,
Executive,
UserMode,
FALSE,
Timeout,
NULL);
UserEnterCo();
return ret;
}
BOOL FASTCALL
MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue)
{
LARGE_INTEGER LargeTickCount;
KeQueryTickCount(&LargeTickCount);
return ((LargeTickCount.u.LowPart - MessageQueue->LastMsgRead) > MSQ_HUNG);
}
BOOLEAN FASTCALL
MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQueue)
{
LARGE_INTEGER LargeTickCount;
NTSTATUS Status;
MessageQueue->Thread = Thread;
MessageQueue->CaretInfo = (PTHRDCARETINFO)(MessageQueue + 1);
InitializeListHead(&MessageQueue->PostedMessagesListHead);
InitializeListHead(&MessageQueue->SentMessagesListHead);
InitializeListHead(&MessageQueue->HardwareMessagesListHead);
InitializeListHead(&MessageQueue->TimerListHead);
InitializeListHead(&MessageQueue->DispatchingMessagesHead);
InitializeListHead(&MessageQueue->LocalDispatchingMessagesHead);
KeInitializeMutex(&MessageQueue->HardwareLock, 0);
MessageQueue->QuitPosted = FALSE;
MessageQueue->QuitExitCode = 0;
KeQueryTickCount(&LargeTickCount);
MessageQueue->LastMsgRead = LargeTickCount.u.LowPart;
MessageQueue->FocusWindow = NULL;
MessageQueue->PaintCount = 0;
MessageQueue->WakeMask = ~0;
MessageQueue->NewMessagesHandle = NULL;
Status = ZwCreateEvent(&MessageQueue->NewMessagesHandle, EVENT_ALL_ACCESS,
NULL, SynchronizationEvent, FALSE);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
Status = ObReferenceObjectByHandle(MessageQueue->NewMessagesHandle, 0,
ExEventObjectType, KernelMode,
(PVOID*)&MessageQueue->NewMessages, NULL);
if (!NT_SUCCESS(Status))
{
ZwClose(MessageQueue->NewMessagesHandle);
MessageQueue->NewMessagesHandle = NULL;
return FALSE;
}
return TRUE;
}
VOID FASTCALL
MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
{
PLIST_ENTRY CurrentEntry;
PUSER_MESSAGE CurrentMessage;
PTIMER_ENTRY CurrentTimer;
PUSER_SENT_MESSAGE CurrentSentMessage;
/* cleanup posted messages */
while (!IsListEmpty(&MessageQueue->PostedMessagesListHead))
{
CurrentEntry = RemoveHeadList(&MessageQueue->PostedMessagesListHead);
CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
ListEntry);
MsqDestroyMessage(CurrentMessage);
}
/* remove the messages that have not yet been dispatched */
while (!IsListEmpty(&MessageQueue->SentMessagesListHead))
{
CurrentEntry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
ListEntry);
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(CurrentSentMessage->DispatchingListEntry.Flink != NULL)
{
RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
}
/* 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);
}
/* cleanup timers */
while (! IsListEmpty(&MessageQueue->TimerListHead))
{
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);
}
/* if this is the primitive message queue, deregister it */
if (MessageQueue == W32kGetPrimitiveMessageQueue())
W32kUnregisterPrimitiveMessageQueue();
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?