msgqueue.c

来自「一个类似windows」· C语言 代码 · 共 1,894 行 · 第 1/5 页

C
1,894
字号
/*
 *  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 21292 2006-03-11 23:50:04Z jimtabor $
 *
 * 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 = PsGetWin32Thread();
   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 = PsGetWin32Thread();
   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 = LargeTickCount.u.LowPart;
   
   /*
    * 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 (PsGetWin32Thread()->Desktop == NULL)
   {
      return FALSE;
   }

   WinStaObject = PsGetWin32Thread()->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;

⌨️ 快捷键说明

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