首页
社区
课程
招聘
[原创]Windows内核之鼠标处理
发表于: 2天前 641

[原创]Windows内核之鼠标处理

2天前
641

前言:

最近在研究Windows内核的一些技术,把毛德操老师的《Windows内核情景分析》上册看了一遍。又买了潘爱民老师的《Windows内核原理与实现》和潘爱民老师翻译的《深入解析Windows操作系统》第四版。这几本书也推荐给大家,都是绝版书,不过可以买二手的,看完了还可以垫显示器。


由于我只看完了上册,所以鼠标驱动部分就不介绍了,直接从这个函数开始,注意本文的代码都是ReactOS 0.3.3:

1.鼠标事件

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);
}

在鼠标的处理线程中首先读取鼠标的数据,然后调用上面的函数,这个函数最重要的部分就是将消息Msg写入消息队列

SystemMessageQueue[SystemMessageQueueTail] = *Msg;

同时叫醒正在睡眠的线程,这是通过

KeSetEvent(&HardwareMessageEvent, IO_NO_INCREMENT, FALSE);

实现的,这一句会将正在等待HardwareMessageEvent事件的线程唤醒。


2.被叫醒的线程

被叫醒的线程获得消息队列中 的消息后主要会判断当前的鼠标移动是不是在自己的窗口范围内,如果是就接收这个事件,那么这次鼠标移动的事件就被基本处理了,如果不是就将事件转发给当前正在鼠标之下的那个窗口处理。

被叫醒的线程都是main函数中调用了GetMessage()函数的线程,这样就从系统中获得了一个msg,接下来介绍msg如何传递给窗口过程函数WndProc,这个是Windows用户程序的主要处理函数。


3.从用户空间回调过程函数WndProc

在获得msg后,一般会调用DispatchMessage(&msg)函数,该函数负责回调过程函数WndProc。


3.从系统空间回调过程函数WndProc

有时需要从系统空间调用用户空间函数,在系统空间中最终会调用KeUserModeCallback()函数,在这个函数中会伪造内核栈内容从而使得返回到用户态时会执行KiUserCallbackDispatcher()函数,在这个函数中会调用用户注册的WndProc函数,并在执行完后返回到内核中去。回到内核后退出KeUserModeCallback()函数。






[培训]《冰与火的战歌:Windows内核攻防实战》!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。

收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回