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

📄 msgqueue.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 *  ReactOS W32 Subsystem
 *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/* $Id: msgqueue.c 27952 2007-07-28 17:16:51Z weiden $
 *
 * COPYRIGHT:        See COPYING in the top level directory
 * PROJECT:          ReactOS kernel
 * PURPOSE:          Message queues
 * FILE:             subsys/win32k/ntuser/msgqueue.c
 * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
 * REVISION HISTORY:
 *       06-06-2001  CSH  Created
 */

/* INCLUDES ******************************************************************/

#include <w32k.h>

#define NDEBUG
#include <debug.h>

/* GLOBALS *******************************************************************/

#define SYSTEM_MESSAGE_QUEUE_SIZE           (256)

static MSG SystemMessageQueue[SYSTEM_MESSAGE_QUEUE_SIZE];
static ULONG SystemMessageQueueHead = 0;
static ULONG SystemMessageQueueTail = 0;
static ULONG SystemMessageQueueCount = 0;
static KSPIN_LOCK SystemMessageQueueLock;

static ULONG volatile HardwareMessageQueueStamp = 0;
static LIST_ENTRY HardwareMessageQueueHead;
static KMUTANT HardwareMessageQueueLock;

static KEVENT HardwareMessageEvent;

static PAGED_LOOKASIDE_LIST MessageLookasideList;
static PAGED_LOOKASIDE_LIST TimerLookasideList;

#define IntLockSystemMessageQueue(OldIrql) \
  KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql)

#define IntUnLockSystemMessageQueue(OldIrql) \
  KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql)

#define IntUnLockSystemHardwareMessageQueueLock(Wait) \
  KeReleaseMutant(&HardwareMessageQueueLock, IO_NO_INCREMENT, FALSE, Wait)

/* FUNCTIONS *****************************************************************/

HANDLE FASTCALL
IntMsqSetWakeMask(DWORD WakeMask)
{
   PW32THREAD Win32Thread;
   PUSER_MESSAGE_QUEUE MessageQueue;
   HANDLE MessageEventHandle;

   Win32Thread = PsGetCurrentThreadWin32Thread();
   if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
      return 0;

   MessageQueue = Win32Thread->MessageQueue;
   MessageQueue->WakeMask = WakeMask;
   MessageEventHandle = MessageQueue->NewMessagesHandle;

   return MessageEventHandle;
}

BOOL FASTCALL
IntMsqClearWakeMask(VOID)
{
   PW32THREAD Win32Thread;
   PUSER_MESSAGE_QUEUE MessageQueue;

   Win32Thread = PsGetCurrentThreadWin32Thread();
   if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
      return FALSE;

   MessageQueue = Win32Thread->MessageQueue;
   MessageQueue->WakeMask = ~0;

   return TRUE;
}

VOID FASTCALL
MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
{
   Queue->PaintCount++;
   Queue->QueueBits |= QS_PAINT;
   Queue->ChangedBits |= QS_PAINT;
   if (Queue->WakeMask & QS_PAINT)
      KeSetEvent(Queue->NewMessages, IO_NO_INCREMENT, FALSE);
}

VOID FASTCALL
MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
{
   Queue->PaintCount--;
}


NTSTATUS FASTCALL
MsqInitializeImpl(VOID)
{
   /*CurrentFocusMessageQueue = NULL;*/
   InitializeListHead(&HardwareMessageQueueHead);
   KeInitializeEvent(&HardwareMessageEvent, NotificationEvent, 0);
   KeInitializeSpinLock(&SystemMessageQueueLock);
   KeInitializeMutant(&HardwareMessageQueueLock, 0);

   ExInitializePagedLookasideList(&MessageLookasideList,
                                  NULL,
                                  NULL,
                                  0,
                                  sizeof(USER_MESSAGE),
                                  0,
                                  256);
   ExInitializePagedLookasideList(&TimerLookasideList,
                                  NULL,
                                  NULL,
                                  0,
                                  sizeof(TIMER_ENTRY),
                                  0,
                                  64);

   return(STATUS_SUCCESS);
}

VOID FASTCALL
MsqInsertSystemMessage(MSG* Msg)
{
   LARGE_INTEGER LargeTickCount;
   KIRQL OldIrql;
   ULONG Prev;

   IntLockSystemMessageQueue(OldIrql);

   /*
    * Bail out if the queue is full. FIXME: We should handle this case
    * more gracefully.
    */

   if (SystemMessageQueueCount == SYSTEM_MESSAGE_QUEUE_SIZE)
   {
      IntUnLockSystemMessageQueue(OldIrql);
      return;
   }

   KeQueryTickCount(&LargeTickCount);
   Msg->time = MsqCalculateMessageTime(&LargeTickCount);
   
   /*
    * If we got WM_MOUSEMOVE and there are already messages in the
    * system message queue, check if the last message is mouse move
    * and if it is then just overwrite it.
    */

   if (Msg->message == WM_MOUSEMOVE && SystemMessageQueueCount)
   {
      if (SystemMessageQueueTail == 0)
         Prev = SYSTEM_MESSAGE_QUEUE_SIZE - 1;
      else
         Prev = SystemMessageQueueTail - 1;
      if (SystemMessageQueue[Prev].message == WM_MOUSEMOVE)
      {
         SystemMessageQueueTail = Prev;
         SystemMessageQueueCount--;
      }
   }

   /*
    * Actually insert the message into the system message queue.
    */

   SystemMessageQueue[SystemMessageQueueTail] = *Msg;
   SystemMessageQueueTail =
      (SystemMessageQueueTail + 1) % SYSTEM_MESSAGE_QUEUE_SIZE;
   SystemMessageQueueCount++;

   IntUnLockSystemMessageQueue(OldIrql);

   KeSetEvent(&HardwareMessageEvent, IO_NO_INCREMENT, FALSE);
}

BOOL FASTCALL
MsqIsDblClk(LPMSG Msg, BOOL Remove)
{
   PWINSTATION_OBJECT WinStaObject;
   PSYSTEM_CURSORINFO CurInfo;
   LONG dX, dY;
   BOOL Res;

   if (PsGetCurrentThreadWin32Thread()->Desktop == NULL)
   {
      return FALSE;
   }

   WinStaObject = PsGetCurrentThreadWin32Thread()->Desktop->WindowStation;

   CurInfo = IntGetSysCursorInfo(WinStaObject);
   Res = (Msg->hwnd == (HWND)CurInfo->LastClkWnd) &&
         ((Msg->time - CurInfo->LastBtnDown) < CurInfo->DblClickSpeed);
   if(Res)
   {

      dX = CurInfo->LastBtnDownX - Msg->pt.x;
      dY = CurInfo->LastBtnDownY - Msg->pt.y;
      if(dX < 0)
         dX = -dX;
      if(dY < 0)
         dY = -dY;

      Res = (dX <= CurInfo->DblClickWidth) &&
            (dY <= CurInfo->DblClickHeight);

      if(Res)
      {
         if(CurInfo->ButtonsDown)
           Res = (CurInfo->ButtonsDown == Msg->message);
      }
   }

   if(Remove)
   {
      if (Res)
      {
         CurInfo->LastBtnDown = 0;
         CurInfo->LastBtnDownX = Msg->pt.x;
         CurInfo->LastBtnDownY = Msg->pt.y;
         CurInfo->LastClkWnd = NULL;
		 CurInfo->ButtonsDown = Msg->message;
      }
      else
      {
         CurInfo->LastBtnDownX = Msg->pt.x;
         CurInfo->LastBtnDownY = Msg->pt.y;
         CurInfo->LastClkWnd = (HANDLE)Msg->hwnd;
         CurInfo->LastBtnDown = Msg->time;
		 CurInfo->ButtonsDown = Msg->message;
      }
   }

   return Res;
}

BOOL static STDCALL
co_MsqTranslateMouseMessage(PUSER_MESSAGE_QUEUE MessageQueue, HWND hWnd, UINT FilterLow, UINT FilterHigh,
                            PUSER_MESSAGE Message, BOOL Remove, PBOOL Freed,
                            PWINDOW_OBJECT ScopeWin, PPOINT ScreenPoint, BOOL FromGlobalQueue)
{
   USHORT Msg = Message->Msg.message;
   PWINDOW_OBJECT Window = NULL;
   HWND hCaptureWin;
   
   ASSERT_REFS_CO(ScopeWin);

   /*
   co_WinPosWindowFromPoint can return a Window, and in that case
   that window has a ref that we need to deref. Thats why we add "dummy"
   refs in all other cases.
   */
   
   hCaptureWin = IntGetCaptureWindow();
   if (hCaptureWin == NULL)
   {
      if(Msg == WM_MOUSEWHEEL)
      {
         Window = UserGetWindowObject(IntGetFocusWindow());
         if (Window) UserRefObject(Window);
      }
      else
      {
         co_WinPosWindowFromPoint(ScopeWin, NULL, &Message->Msg.pt, &Window);
         if(Window == NULL)
         {
            Window = ScopeWin;
            if (Window) UserRefObject(Window);
         }
         else
         {
            /* this is the one case where we dont add a ref, since the returned
            window is already referenced */
         }
      }
   }
   else
   {
      /* FIXME - window messages should go to the right window if no buttons are
                 pressed */
      Window = UserGetWindowObject(hCaptureWin);
      if (Window) UserRefObject(Window);
   }



   if (Window == NULL)
   {
      if(!FromGlobalQueue)
      {
         RemoveEntryList(&Message->ListEntry);
         if(MessageQueue->MouseMoveMsg == Message)
         {
            MessageQueue->MouseMoveMsg = NULL;
         }
      }
      ExFreePool(Message);
      *Freed = TRUE;
      return(FALSE);
   }

   if (Window->MessageQueue != MessageQueue)
   {
      if (! FromGlobalQueue)
      {
         DPRINT("Moving msg between private queues\n");
         /* This message is already queued in a private queue, but we need
          * to move it to a different queue, perhaps because a new window
          * was created which now covers the screen area previously taken
          * by another window. To move it, we need to take it out of the
          * old queue. Note that we're already holding the lock mutexes of the
          * old queue */
         RemoveEntryList(&Message->ListEntry);

         /* remove the pointer for the current WM_MOUSEMOVE message in case we
            just removed it */
         if(MessageQueue->MouseMoveMsg == Message)
         {
            MessageQueue->MouseMoveMsg = NULL;
         }
      }

      /* lock the destination message queue, so we don't get in trouble with other
         threads, messing with it at the same time */
      IntLockHardwareMessageQueue(Window->MessageQueue);
      InsertTailList(&Window->MessageQueue->HardwareMessagesListHead,
                     &Message->ListEntry);
      if(Message->Msg.message == WM_MOUSEMOVE)
      {
         if(Window->MessageQueue->MouseMoveMsg)
         {
            /* remove the old WM_MOUSEMOVE message, we're processing a more recent
               one */
            RemoveEntryList(&Window->MessageQueue->MouseMoveMsg->ListEntry);
            ExFreePool(Window->MessageQueue->MouseMoveMsg);
         }
         /* save the pointer to the WM_MOUSEMOVE message in the new queue */
         Window->MessageQueue->MouseMoveMsg = Message;

         Window->MessageQueue->QueueBits |= QS_MOUSEMOVE;
         Window->MessageQueue->ChangedBits |= QS_MOUSEMOVE;
         if (Window->MessageQueue->WakeMask & QS_MOUSEMOVE)
            KeSetEvent(Window->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
      }
      else
      {
         Window->MessageQueue->QueueBits |= QS_MOUSEBUTTON;
         Window->MessageQueue->ChangedBits |= QS_MOUSEBUTTON;
         if (Window->MessageQueue->WakeMask & QS_MOUSEBUTTON)
            KeSetEvent(Window->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
      }
      IntUnLockHardwareMessageQueue(Window->MessageQueue);

      *Freed = FALSE;
      UserDerefObject(Window);
      return(FALSE);
   }

   /* From here on, we're in the same message queue as the caller! */

   *ScreenPoint = Message->Msg.pt;

   if((hWnd != NULL && Window->hSelf != hWnd) ||
         ((FilterLow != 0 || FilterLow != 0) && (Msg < FilterLow || Msg > FilterHigh)))
   {
      /* Reject the message because it doesn't match the filter */

      if(FromGlobalQueue)
      {
         /* Lock the message queue so no other thread can mess with it.
            Our own message queue is not locked while fetching from the global
            queue, so we have to make sure nothing interferes! */
         IntLockHardwareMessageQueue(Window->MessageQueue);
         /* if we're from the global queue, we need to add our message to our
            private queue so we don't loose it! */
         InsertTailList(&Window->MessageQueue->HardwareMessagesListHead,
                        &Message->ListEntry);
      }

      if (Message->Msg.message == WM_MOUSEMOVE)
      {
         if(Window->MessageQueue->MouseMoveMsg &&
               (Window->MessageQueue->MouseMoveMsg != Message))
         {
            /* delete the old message */
            RemoveEntryList(&Window->MessageQueue->MouseMoveMsg->ListEntry);
            ExFreePool(Window->MessageQueue->MouseMoveMsg);
         }
         /* always save a pointer to this WM_MOUSEMOVE message here because we're
            sure that the message is in the private queue */
         Window->MessageQueue->MouseMoveMsg = Message;
      }
      if(FromGlobalQueue)
      {
         IntUnLockHardwareMessageQueue(Window->MessageQueue);
      }

      UserDerefObject(Window);
      *Freed = FALSE;
      return(FALSE);
   }

   /* FIXME - only assign if removing? */
   Message->Msg.hwnd = Window->hSelf;
   Message->Msg.message = Msg;
   Message->Msg.lParam = MAKELONG(Message->Msg.pt.x, Message->Msg.pt.y);

   /* remove the reference to the current WM_(NC)MOUSEMOVE message, if this message
      is it */
   if (Message->Msg.message == WM_MOUSEMOVE ||
         Message->Msg.message == WM_NCMOUSEMOVE)
   {
      if(FromGlobalQueue)
      {
         /* Lock the message queue so no other thread can mess with it.
            Our own message queue is not locked while fetching from the global
            queue, so we have to make sure nothing interferes! */
         IntLockHardwareMessageQueue(Window->MessageQueue);
         if(Window->MessageQueue->MouseMoveMsg)
         {
            /* delete the WM_(NC)MOUSEMOVE message in the private queue, we're dealing
               with one that's been sent later */
            RemoveEntryList(&Window->MessageQueue->MouseMoveMsg->ListEntry);
            ExFreePool(Window->MessageQueue->MouseMoveMsg);
            /* our message is not in the private queue so we can remove the pointer
               instead of setting it to the current message we're processing */
            Window->MessageQueue->MouseMoveMsg = NULL;
         }
         IntUnLockHardwareMessageQueue(Window->MessageQueue);
      }
      else if(Window->MessageQueue->MouseMoveMsg == Message)
      {
         Window->MessageQueue->MouseMoveMsg = NULL;
      }
   }

   UserDerefObject(Window);
   *Freed = FALSE;
   return(TRUE);
}

BOOL STDCALL
co_MsqPeekHardwareMessage(PUSER_MESSAGE_QUEUE MessageQueue, HWND hWnd,
                          UINT FilterLow, UINT FilterHigh, BOOL Remove,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -