-
-
[原创]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内核攻防全技术栈,打造具备自动化能力的内核开发高手。