Windows消息机制学习笔记(二)—— 窗口与线程
Windows消息机制学习笔记(二)—— 窗口与线程
- 要点回顾
- 消息从哪里来?
- 实验一:Spy++捕获消息
- 实验二:消息捕获
- 消息到哪里去?
- 窗口在哪?
- 实验:分析CreateWindowExW
- 窗口对象
- 总结
要点回顾
一个GUI线程对应一个消息队列
本篇要解决的问题:
- 消息从哪里来?
- 消息到哪里去?
- 谁来做这些事情?
消息从哪里来?
1)Spy++ 捕捉消息:鼠标消息、键盘消息
2)程序发送消息
实验一:Spy++捕获消息
1)编译并运行以下代码
#include <windows.h>LRESULT CALLBACK WindowProc(IN HWND hwnd,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam
){return DefWindowProc(hwnd, uMsg, wParam, lParam);
}int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd
){//窗口的类名TCHAR className[] = "My First Window";//创建一个自己的窗口WNDCLASS wndclass = {0};wndclass.hbrBackground = (HBRUSH)COLOR_MENU;wndclass.lpfnWndProc = WindowProc;wndclass.lpszClassName = className;wndclass.hInstance = hInstance;//注册RegisterClass(&wndclass);//创建窗口HWND hwnd = CreateWindow(className,TEXT("我的第一个窗口"),WS_OVERLAPPEDWINDOW,10,10,600,300,NULL,NULL,hInstance,NULL);if(hwnd == NULL)return 0;//显示窗口ShowWindow(hwnd, SW_SHOW);//消息循环MSG msg;while(GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}return 0;
}
运行结果
2)使用spy++定位窗口
3)在窗口中进行任意操作,例如鼠标移动,鼠标点击,键盘敲击等,观察消息列表
实验二:消息捕获
1)进程A运行以下代码
#include <windows.h>LRESULT CALLBACK WindowProc(IN HWND hwnd,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam
){switch(uMsg){case 0x401:MessageBoxA(NULL, "接收到消息", "新消息", MB_OK);return false;}return DefWindowProc(hwnd, uMsg, wParam, lParam);
}int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd
){//窗口的类名TCHAR className[] = "My First Window";//创建一个自己的窗口WNDCLASS wndclass = {0};wndclass.hbrBackground = (HBRUSH)COLOR_MENU;wndclass.lpfnWndProc = WindowProc;wndclass.lpszClassName = className;wndclass.hInstance = hInstance;//注册RegisterClass(&wndclass);//创建窗口HWND hwnd = CreateWindow(className,TEXT("我的第一个窗口"),WS_OVERLAPPEDWINDOW,10,10,600,300,NULL,NULL,hInstance,NULL);if(hwnd == NULL)return 0;//显示窗口ShowWindow(hwnd, SW_SHOW);//消息循环MSG msg;while(GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}return 0;
}
2)进程B运行以下代码
#include <stdio.h>
#include <windows.h>int main()
{HWND hwnd = FindWindow("My First Window", "我的第一个窗口");SendMessage(hwnd, 0x401, 0, 0);return 0;
}
执行结果
消息到哪里去?
描述:
- 当我们使用鼠标某个窗口进行点击与滑动时,都会产生一个消息,消息会进入当前窗口对应线程的消息队列中
- 当我们编写程序时,并不会去特地启动两个线程去监控鼠标和键盘,w32k.sys负责了这个事情
当初始化w32k.sys这个模块时,会调用一个叫做InitInputImpl的函数
这个函数会启动两个线程,分别用来监控鼠标和键盘,这两个线程都是0环的线程
平时我们的电脑遭遇“死机”时,常常是屏幕动不了,鼠标还能动,这正式由于鼠标是有一个独立的线程在监控它的行动
//FROM ReactOS v3.12
InitInputImpl(VOID)
{...Status = PsCreateSystemThread(&RawInputThreadHandle, //监控鼠标THREAD_ALL_ACCESS,NULL,NULL,&RawInputThreadId,RawInputThreadMain,NULL);if (!NT_SUCCESS(Status)){DPRINT1("Win32K: Failed to create raw thread.\n");}Status = PsCreateSystemThread(&KeyboardThreadHandle, //监控键盘THREAD_ALL_ACCESS,NULL,NULL,&KeyboardThreadId,KeyboardThreadMain,NULL);if (!NT_SUCCESS(Status)){DPRINT1("Win32K: Failed to create keyboard thread.\n");}...
}
思考:w32k.sys如何区分用户点击的是哪个窗口/消息要去哪个线程
窗口在哪?
当调用CreateWindow时,该函数实际上是一个宏,其CreateWindowA实际对应CreateWindowExA函数,CreateWindowW对应CreateWindowExW函数,可在编辑器中跟踪观察
实验:分析CreateWindowExW
函数位于user32.dll中
总结:窗口在0环被画出(由w32k.sys实现)
窗口对象
描述:
- 每个窗口对应一个WINDOW_OBJECT结构体,位于0环,包含当前窗口所有信息
- 除了大窗口之外,窗口中的每个控件也都是一个窗口,也分别对应一个WINDOW_OBJECT结构体
- 一个窗口内包含着许多个窗口,按钮,对话框也都属于窗口,属于同一个线程
- 一个线程可以包含多个窗口,但每个窗口只能属于一个线程
//FROM ReactOS v3.12
typedef struct _WINDOW_OBJECT
{...PWND Wnd; //包含大量窗口信息PTHREADINFO pti; //线程...
}
//FROM ReactOS v3.12
typedef struct _WND
{.../* Style. */DWORD style; //包含窗口风格/后一个窗口/前一个窗口/父窗口/子窗口等信息...
} WND, *PWND;
消息进入窗口消息队列的过程:
- 当使用鼠标在某个窗口上点击时,鼠标监控线程检测到点击的窗口对象
- 根据窗口对象成员,找到窗口对应线程
- 将消息放入该线程的消息队列中
注意:在3环得到的窗口的句柄只是一个索引(参考句柄表章节)
总结
- 窗口在0环创建
- 窗口句柄是全局的
- 一个线程可以使用多个窗口,但每个窗口只能属于一个线程
Windows消息机制学习笔记(二)—— 窗口与线程相关推荐
- Windows消息机制学习笔记(三)—— 消息的接收与分发
Windows消息机制学习笔记(三)-- 消息的接收与分发 要点回顾 消息循环 消息队列 消息的接收 GetMessage 实验1:理解GetMessage 第一步:编译并运行程序A 第二步:编译并运 ...
- Windows消息机制学习笔记(一)—— 消息队列
Windows消息机制学习笔记(一)-- 消息队列 基本概念 实验一:使用代码画出最简单窗口 第一步:编译并运行以下代码 第二步:查看运行结果 第三步:使用其它窗口对其进行覆盖,观察效果 总结 消息队 ...
- 消息机制学习笔记(四)—— 内核回调机制
消息机制学习笔记(四)-- 内核回调机制 要点回顾 内核调用 实验1:理解内核调用 第一步:编译并运行以下代码 第二步:修改窗口过程函数,重新运行 KeUserModeCallback 实验2:在OD ...
- Android消息机制学习笔记
Android的消息机制主要是指Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑: MessageQueue:消息队列,它的内存存储了一组消息,以队 ...
- 注意力机制学习笔记二(Attention-GAN、SAGAN、YLG-SAGAN)
一.Attention-GAN 论文地址:Attention-GAN for Object Transfiguration in Wild Images Object Transfiguration不 ...
- Windows编程课程学习笔记
一. Windows程序内部运行机制--Windows编程课程学习笔记 二. MFC框架程序分析--Windows编程课程学习笔记 三. 简单绘图--Windows编程课程学习笔记 四. 文本编程-- ...
- wxpython应用程序对象与顶级窗口_wxPython学习笔记(二)
如何创建和使用一个应用程序对象? 任何wxPython应用程序都需要一个应用程序对象.这个应用程序对象必须是类wx.App或其定制的子类的一个实例.应用程序对象的主要目的是管理幕后的主事件循环. 父类 ...
- Windows事件等待学习笔记(二)—— 线程等待与唤醒
Windows事件等待学习笔记(二)-- 线程等待与唤醒 要点回顾 等待与唤醒机制 可等待对象 可等待对象的差异 线程与等待对象 一个线程等待一个对象 实验 第一步:编译并运行以下代码 第二步:在Wi ...
- Windows驱动开发学习笔记(二)—— 驱动调试内核编程基础
Windows驱动开发学习笔记(二)-- 驱动调试&内核编程基础 基础知识 驱动调试 PDB(Program Debug Database) WinDbg 加载 PDB 实验:调试 .sys ...
最新文章
- BREW 计费模式概览
- MIT与商汤科技成立人工智能联盟
- 计算机计量g代表,计算机中的有些计量单位例如G、MB是表示什么意思?
- linux HZ Tick Jiffies
- 配置kubernetes服务basic auth
- 修改程序配置文件 以及写一个结构体数组到文件(以及整数和结构体)
- 结婚戒指为什么戴在无名指上的原因
- Scala代码案例: StdIn和if..else
- SwaggerUI看烦了,IGeekFan.AspNetCore.Knife4jUI 帮你换个新皮肤
- 最佳的开源云项目有哪些?
- 连接Android与ASP.NET Core Web API的完整教程
- C/C++获取文件大小
- Android 仿PhotoShop调色板应用(一)概述
- IBM与红帽联手构建开源混合云环境
- DirectX修复工具使用技巧之一——解除被占用的文件,完整修复C++
- Yate架构分析概要
- Android下磁盘分区表损坏,硬盘分区表丢失错误怎么修复TestDisk使用教程
- vscode + prettier 专治代码洁癖
- 抖音做外卖会颠覆美团吗?
- 计算机台式和电脑的区别吗,直观:工业计算机和家用台式计算机有什么区别
热门文章
- DL之DNN:基于Tensorflow框架对神经网络算法进行参数初始化的常用九大函数及其使用案例
- TF:利用是Softmax回归+GD算法实现MNIST手写数字图片识别(10000张图片测试得到的准确率为92%)
- os_mutex.c(全)
- PL/SQL的快捷键设置
- 【转载】[OS X笔记]安装MacPorts
- 怎样在android平台上使用第三方jar包
- MPDU 和 MSDU 的区别及关系
- VS2017-MFC-生成二维码测试小程序
- C++ Primer 5th笔记(chap 17 标准库特殊设施)bitset类型
- 深度探索C++ 对象模型(2)-类的对象的内存大小_2