⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 msgqueue.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 4 页
字号:
   {
      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 + -