Windows消息机制学习笔记(一)—— 消息队列

  • 基本概念
  • 实验一:使用代码画出最简单窗口
    • 第一步:编译并运行以下代码
    • 第二步:查看运行结果
    • 第三步:使用其它窗口对其进行覆盖,观察效果
    • 总结
  • 消息队列
    • 消息队列在哪
      • Linux:专用进程
      • Windows:GUI线程
    • Win32Thread
  • 总结

基本概念

接触过编程的人,或多或少用到过消息机制,但大多数人(包括我自己)只是知道相关API的基本用法,却不知道它是如何实现的

从本章起,我们将带着以下几个问题一起来学习消息机制:

  1. 什么是窗口句柄?在哪里?有什么用?
  2. 什么是消息?什么是消息队列?消息队列在哪?
  3. 什么是窗口过程?窗口过程是谁调用的?没有消息循环窗口过程会执行吗?
  4. 为什么要有w32k.sys这个模块?
  5. 为什么只有使用图形界面的程序才可以访问KeServiceDescriptorTableShadow?
  6. 界面"卡死"的时候为什么鼠标还可以动?

实验一:使用代码画出最简单窗口

第一步:编译并运行以下代码

#include <stdio.h>
#define _WIN32_WINNT 0x500
#include <windows.h>typedef struct _Color
{DWORD r;DWORD g;DWORD b;
}Color;typedef struct _WindowClass
{DWORD x;DWORD y;DWORD width;DWORD height;Color color;
}WindowClass;//按照WindowClass的参数,将hdc中的数据打印到指定设备
void PaintWindows(HDC hdc, WindowClass *p)
{HBRUSH hBrush;hBrush = (HBRUSH)GetStockObject(DC_BRUSH);SelectObject(hdc, hBrush);            //画刷SetDCBrushColor(hdc, RGB(p->color.r, p->color.g, p->color.b));MoveToEx(hdc, p->x, p->y, NULL);LineTo(hdc, p->x+p->width, p->y);LineTo(hdc, p->x+p->width, p->y+p->height);LineTo(hdc, p->x, p->y+p->height);LineTo(hdc, p->x, p->y);Rectangle(hdc, p->x, p->y, p->width, p->height+1);DeleteObject(hBrush);
}int main()
{char cMessage;     //消息HWND hwnd;          //画在哪HDC hdc;           //显卡缓存//设置窗口参数,长宽高之类的WindowClass wClass;wClass.x = 0;wClass.y = 0;wClass.width = 800;wClass.height = 400;wClass.color.r = 0xEF;wClass.color.g = 0xEB;wClass.color.b = 0xDE;//画在哪hwnd = GetDesktopWindow();//hwnd = FindWindow("dbgviewClass", NULL);//获取DC设备句柄:可以把DC理解成显卡缓存hdc = GetWindowDC(hwnd);for(;;){//画窗口PaintWindows(hdc, &wClass);cMessage = getchar();switch(cMessage){case 'a':wClass.color.r += 0x10;wClass.color.g += 0x10;wClass.color.b += 0x10;break;case 'b':wClass.color.r -= 0x10;wClass.color.g -= 0x10;wClass.color.b -= 0x10;break;}}return 0;
}

第二步:查看运行结果

第三步:使用其它窗口对其进行覆盖,观察效果

总结

  1. 画出的部分被其它窗口覆盖后就消失了
  2. 手动画出的窗口只能接收键盘发送的消息

思考:如何使窗口能够接收所有消息
答案:将所有消息放入一块内存中,这块内存被称之为“消息队列

消息队列

描述:本质上是一种数据结构,当对象接收到消息时,将接收到的所有消息放入消息队列中,等待对象进行处理
规则:先进先出

消息队列在哪

Linux:专用进程

  1. 使用专用进程捕获所有消息
  2. 判断消息所属进程,进行分发,将消息分配到目标进程的消息队列中

Windows:GUI线程

查看KTHREAD结构体

kd> dt _KTHREAD
ntdll!_KTHREAD...+0x130 Win32Thread    //若当前程序为控制台程序且无使用任何图形界面相关API,该成员为空//若当前程序使用了图形界面相关的API,该成员指向一个结构体,该结构体包含了消息队列...

GUI:微软提供的与图形界面相关的API,称为GUI
GDI:自定义的用于图形界面相关的API,称为GDI

GUI线程

  1. 当线程刚创建的时候,都是普通线程:
    Thread.ServiceTable指向KeServiceDescriptorTable
  2. 当线程第一次调用Win32k.sys(调用号大于0x100)时,会调用一个函数,将当前线程转换成GUI线程:PsConvertToGuiThread
    主要做几件事:
    a. 扩充内核栈,必须换成64KB的大内核栈,因为普通内核栈只有12KB大小
    b.创建一个包含消息队列的结构体,并挂到KTHREAD上
    c.将Thread.ServiceTable指向KeServiceDescriptorTableShadow(只有当调用GUI时,才会指向SSDTShadow)
    d.把需要的内存数据映射到本进程空间

Win32Thread

描述:位于KTHREAD,若当前程序使用了图形界面相关的API,该成员指向一个结构体,其中包含了当前线程的消息队列:THREADINFO

//FROM ReactOS v0.4.13
typedef struct _THREADINFO{...struct _USER_MESSAGE_QUEUE* MessageQueue; //消息队列...
} THREADINFO;

总结

  1. 消息队列存储在0环,通过KTHREAD.Win32Thread可以找到
  2. 并不是所有线程都要消息队列,只有GUI线程才有消息队列
  3. 一个GUI线程对应1个消息队列

Windows消息机制学习笔记(一)—— 消息队列相关推荐

  1. Windows消息机制学习笔记(三)—— 消息的接收与分发

    Windows消息机制学习笔记(三)-- 消息的接收与分发 要点回顾 消息循环 消息队列 消息的接收 GetMessage 实验1:理解GetMessage 第一步:编译并运行程序A 第二步:编译并运 ...

  2. Windows消息机制学习笔记(二)—— 窗口与线程

    Windows消息机制学习笔记(二)-- 窗口与线程 要点回顾 消息从哪里来? 实验一:Spy++捕获消息 实验二:消息捕获 消息到哪里去? 窗口在哪? 实验:分析CreateWindowExW 窗口 ...

  3. 消息机制学习笔记(四)—— 内核回调机制

    消息机制学习笔记(四)-- 内核回调机制 要点回顾 内核调用 实验1:理解内核调用 第一步:编译并运行以下代码 第二步:修改窗口过程函数,重新运行 KeUserModeCallback 实验2:在OD ...

  4. Android消息机制学习笔记

    Android的消息机制主要是指Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑: MessageQueue:消息队列,它的内存存储了一组消息,以队 ...

  5. eCos消息机制学习

    消息机制学习 消息机制介绍 消息机制也是学习eCos平台框架必不可少的一方面,主要负责CGI与各个模块以及各个模块之间的通讯机制,效果与UGW平台相似,但消息机制本身实现方式不同,下图是其整体的流程图 ...

  6. Windows x64内核学习笔记(一)—— 环境与配置

    Windows x64内核学习笔记(一)-- 环境与配置 前言 新特性 基础要求 实验环境 Guest Win10配置 问题解决 参考资料 前言 之前,跟着海哥学习了windows内核的一些机制,包括 ...

  7. Windows phone 8 学习笔记(5) 图块与通知

    基于metro风格的Windows phone 8 应用提到了图块的概念,它就是指启动菜单中的快速启动图标.一般一个应用必须有一个默认图块,还可以有若干个次要图块.另外,通知与图块的关系比较密切,我们 ...

  8. Windows驱动开发学习笔记(四)—— 3环与0环通信(常规方式)

    Windows驱动开发学习笔记(四)-- 3环与0环通信(常规方式) 设备对象 创建设备对象 设置数据交互方式 创建符号链接 IRP与派遣函数 IRP的类型 其它类型的IRP 派遣函数 派遣函数注册位 ...

  9. Windows x64内核学习笔记(五)—— KPTI(未完待续)

    Windows x64内核学习笔记(五)-- KPTI(未完待续) KPTI 实验一:构造IDT后门并读取Cr3 参考资料 KPTI 描述:KPTI(Kernel page-table isolati ...

最新文章

  1. docker 查看容器ip
  2. 在Ubuntu上通过VNC Viewer连接Jetson nano桌面
  3. php ajax mysql 分页查询_PHP中使用jQuery+Ajax实现分页查询多功能操作(示例讲解)
  4. html5页面主题,HTML5页面开发笔记
  5. Eclipse如何添加Maven的scala支持
  6. c#执行插入sql 时,报错:异常信息:超时时间已到。在操作完成之前超时时间已过或服务器未响应
  7. php和python-PHP和Python性能比较:放弃PHP改用Python
  8. 【Unity3D基础教程】给初学者看的Unity教程(一):GameObject,Compoent,Time,Input,Physics...
  9. 远程桌面命令是什么 如何使用命令连接远程桌面
  10. 如何在Visio中插入公式符号
  11. 计算机主板内存设计规范,PC 新时代!DDR5 内存规范正式发布
  12. php扑克牌随机发,PHP实现随机发放扑克牌
  13. 【月光博客】腾讯微信推出广告联盟
  14. js实现软键盘(兼容所有浏览器)
  15. 计算机教室突发事件处理,课堂突发事件处理
  16. Excel笔记(持续更新)
  17. 7 个较佳数据可视化 WordPress 插件(图表和信息图表)
  18. (转)经典广东话2010
  19. Ubuntu1804键盘输入系统无fcitx的解决方法
  20. 《追风筝的人》读后感2600字

热门文章

  1. 成功解决explicit device specific/device:GPU:0' because no supported kernel for GPU devices is available.
  2. 角点检测——发现图像的特征
  3. Anconda下的R语言
  4. 18.28 getchar()函数与缓冲区问题
  5. python操作Excel的几种方式
  6. BZOJ3110: [Zjoi2013]K大数查询
  7. 小程序 常用快捷键
  8. GitHub如何删除一个repository(仓库)
  9. 超市账单管理------之获取总记录数
  10. HTML 的特殊字符转换转义符,的两种方法。