文章目录

  • 前奏
  • 窗口代码
  • 你能回答这些问题吗?
  • 消息队列:
  • 消息队列在何处呢?
  • 那么Windows如何解决的呢?
  • 重点:
  • 总结:

前奏

首先我们来画一个窗口:

窗口代码

#include<Windows.h>
#include <stdio.h>
#define _WIN32_WINNT 0x0500typedef struct _Color {DWORD r;DWORD g;DWORD b;
}Color;typedef struct _WindowClass {DWORD x;DWORD y;DWORD width;DWORD hight;Color color;
}WindowClass;void PaintWindwos(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->hight);LineTo(hdc, p->x, p->y + p->hight);LineTo(hdc, p->x, p->y);Rectangle(hdc, p->x, p->y, p->x + p->width, p->y + p->width + 1);DeleteObject(hBrush);
}
void main() {char cMessage;   //消息HWND  hwnd;       //画在哪HDC  hdc;      //显卡缓存//设置窗口参数:长宽高之类的WindowClass wClass;wClass.x = 0;wClass.y = 0;wClass.width = 800;wClass.hight = 400;wClass.color.r = 0xEF;wClass.color.g = 0xEB;wClass.color.b = 0xDE;//画在哪hwnd = GetDesktopWindow();//hwnd=FindWindow("notepad.exe",NULL);//获取DC设备句柄:可以把DC理解成显卡缓存hdc = GetWindowDC(hwnd);cMessage = getchar();for(;;) {//画窗口PaintWindwos(hdc, &wClass);//接收消息switch (cMessage){case 'a':wClass.color.r += 0x10;wClass.color.g += 0x10;wClass.color.b += 0x10;break;case 'b':wClass.color.r += 0x20;wClass.color.g += 0x20;wClass.color.b += 0x20;break;default:break;}}
}


在这里呢我们可以通过控制台去控制窗口的颜色,那么接下来让我们一起来看看原理:

你能回答这些问题吗?

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

消息队列:

消息队列在何处呢?

首先我们假设把消息队列放在用户空间(3环),那么谁又来往用户空间的消息队列存储这些东西呢?
最好的解决方案就是找一个专用进程来监听鼠标和键盘等,再来进行判断是属于哪个进程的消息队列,最后来进行消息分发(Linux解决方案)
弊端:涉及了跨进程通信问题,专用进程传给其它进程。大量时间都花在跨进程。

那么Windows如何解决的呢?

首先普及一下:
kernel32.dll ----------> ntoskrnl.exe(进程,线程,内存管
user32.dll gdi32.dll -----------> win32k.sys(图形界面,消息管理)

Windows已经画好的界面(windows提供的)GUI编程 user32.dll
不用Windows提供的那些界面 GDI编程 gdi32.dll

窗口句柄HWN

针对窗口的句柄表,只有一个,(放在内核中)表是全局的,所有窗口共用的

HDC   hdc;
HPEN hpen;
1.设备对象  画在哪
hwnd    =(HWND)0x0003543;
2.获取设备对象上下文
hdc=GetDC(hwnd);
3.创建画笔  设置线条属性
hpen=CreatePen(PS_S0LID,5,RGB(0xFF,00,00));
4.关联
SelectObject(hdc,hpen);
5.开始画
LineTo(hdc,400,400);//gdi32.dll
6.释放资源
DeleteObject(hpen);
ReleaseDC(hwnd,hdc);

它把消息队列放在(内核空间)0环中,

微软的解决方案:GUI线程
GUI(自己使用微软提供的窗口函数,比如CreateWindow,CreateButton等创建的图形界面,这种API就叫做GUI)

GDI(如果觉得微软提供的窗口不符合自己所需条件,需要自己画,所用的那些API就叫GDI)

重点:

1.当线程刚创建的时候,都是普通线程:
Thread.ServiceTable -->KeServiceDescriptorTable(SSDT表)
ServiceTable中存储了一张表,叫做系统服务表

2.当线程第一次调用(与图形界面相关的模块 )Win32k.sys时(只要试图正常调用Win32k中的任何一个函数),会调用一个函数:PsConvertToGuiThread(把普通线程转换为GUI线程)

PsConvertToGuiThread主要做几件事:
a.扩充内核栈,必须换成64KB 的大内核栈,因为普通内核栈只有12KB大小。
b.创建一个包含消息队列的结构体,并挂到KTHREAD上(也就是KTHREAD中的Win32Thread)
c.Thread.ServiceTable–>KeServiceDescriptorShadow(SSDTShadow表)
d.把需要的内存数据映射到本进程空间

(SSDT表中只引用了一张表,只有一张系统服务表,也就是ntoskernel,win32k的第二张表它没有。但是SSDTShaow表中既包含了ntoskernel中的函数,又包含了Win32k(与图形界面相关的)中的函数)
解释:
如果是一个普通线程的话,那么ETHRED结构体中成员KTHREAD结构体中有一个Win32Thread成员它是为空(未使用图形界面相关的API)
如果是一个GUI线程的话,那么ETHRED结构体中成员KTHREAD有一个Win32Thread成员它是一个地址值,指向一个结构体,指向一个_THREADINFO结构体,这个结构体里面又有一个成员,存放着消息队列

总结:

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

消息机制(GUI线程讲解)相关推荐

  1. Qt 之 消息机制和事件讲解

    1.图形界面应用程序的消息处理模型 特点: 基于操作系统才能运行: GUI应用程序提供的功能必须由用户触发: 用户操作界面时操作系统是第一个感知的 : 系统内核的消息通过事件处理转变成QT的信号. 2 ...

  2. windows消息机制详解-3

    1. 引言 Windows 在操作系统平台占有绝对统治地位,基于Windows 的编程和开发越来越广泛. Dos 是过程驱动的,而Windows 是事件驱动的[6],这种差别的存在使得很多Dos 程序 ...

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

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

  4. Handler消息机制(四):子线程可以创建Handler吗

    默认情况下,ActivityThread类为我们创建的了主线程的Looper和消息队列,所以当你创建Handler之后发送消息的时候,消息的轮训和handle都是在ui线程进行的.这种情况属于子线程给 ...

  5. Handler消息机制(二):一个线程有几个Handler

    在消息机制里面,有一个非常重要的东西,那就是Looper,Looper的作用主要是从消息队列里面取出消息交给Handler处理,不过不仅限于此,在这里面还有很多东西值得我们去源码看一看: 1.从Loo ...

  6. 图解 Android Handler 线程消息机制

    从现实生活中理解线程消息机制 android 有一种叫消息队列的说法,这里我们可以这样理解:假如一个隧道就是一个消息队列,那么里面的每一部汽车就是一个一个消息,这里我们先忽略掉超车等种种因素,只那么先 ...

  7. 多线程之旅七——GUI线程模型,消息的投递(post)与处理

    基于消息的GUI构架 在过去的日子中,大部分编程语言平台的GUI构架几乎没有发生变化.虽然在细节上存在一些差异,比如在功能和编程风格上,但大部分都是采用了相同的构架来响应用户输入以及重新绘制屏幕.这种 ...

  8. Android消息机制(Handler机制) - 线程的等待和唤醒

    我们都知道,Android的Handler机制,会在线程中开启消息循环,不断的从消息队列中取出消息,这个机制保证了主线程能够及时的接收和处理消息. 通常在消息队列中(MessageQueue)中没有消 ...

  9. 【Android】线程间通信——Handler消息机制

    文章目录 引言 Java层 永动机跑起来 示例 Looper Handler MessageQueue 永动机停下 Native层 nativeInit() nativePollOnce() nati ...

最新文章

  1. 人工智能进阶-CIFAR-10数据集介绍
  2. .NET中的IO操作之文件流
  3. 尝试远程添加Git存储库时收到“致命错误:不是git存储库”
  4. SpiderData 2019年2月22日 DApp数据排行榜
  5. mwArray与C++接口
  6. SAP fiori上直接连接到操作系统层面 然后进行相关操作的需求
  7. ubuntu mysql 防火墙_mysql、ubuntu系统防火墙常规操作
  8. 怎么用记事本写java_如何用记事本写下第一个Java程序-Fun言
  9. 2019年退税可以开始申报了 | 一笔3000元的意外收入
  10. Linux镜像资源收集
  11. WebEx Recorder:性能最好的录屏软件
  12. 黑马培训一个月多月的心得体会
  13. 互联网运营常用8大数据分析模型
  14. 在雨雾中穿行--张家界之旅103
  15. Python办公自动化实战 01 | Python优势与自动化思维让你的工作化繁为简
  16. Windows7 Ghost 旗舰装机版
  17. html语言%3cspan%3e,比较好的网站HTML语言.doc
  18. linux write函数长度,【转】linux驱动中的write函数
  19. Table sink ‘default_catalog.default_database.t3‘ doesn‘t support consuming update and delete changes
  20. MATLAB-三维插值运算

热门文章

  1. 用python做毕业设计小程序_用Python写一个模拟qq聊天小程序的代码实例
  2. Python编程语言学习:包导入和模块搜索路径简介、使用方法之详细攻略
  3. Python函数封装:利用正则表达式compile、findall对多组关键词进行模糊查询并返回统计个数,findall截取两个指定符号之间的内容
  4. ML之nyoka:基于nyoka库利用LGBMClassifier模型实现对iris数据集训练、保存为pmml模型并重新载入pmml模型进而实现推理
  5. Python:Python语言编程软件安装的几大姿势之详细攻略
  6. DayDayUp:追梦赤子心——1024,你好!程序猿们的节日!
  7. 在Python中使用lightgbm
  8. JAVA_OA(十四)番外:JAVAWEB防止表单重复提交的方法整合(包括集群部署)
  9. [Python]小甲鱼Python视频第002课(第一个游戏)课后题及参考解答
  10. 用jquery ajax做的select菜单,选中的效果