windows消息机制
创始人
2024-06-02 12:54:19
0

windows消息机制

文章目录

      • windows消息机制
        • 1.创建基本的窗口程序
        • 2.消息传递的原理
          • (1)消息类型
          • (2)消息的传递
          • (3)相应的发送消息的函数SendMessage/PostMessage

1.创建基本的窗口程序

/*
基本的窗口程序的步骤:
1.注册窗口类(RegisterClass()),就像事件驱动一样,只有在相应的事件驱动里面注册了,分发的机制才会在事件触发时调用已经注册的对象,此对象成为实例对象hInstance
2.创建窗口( CreateWindow()),为实例对象hInstance创建一个窗口
3.显示窗口
4.接下来进入消息等待阶段,当所注册的事件被触发,那么在这个事件注册的过程将会被调用
*/
#include 
#include 
#include 
#define WM_TEST_MSG (WM_USER+1)LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {//如果自己不进行处理就交给默认的处理函数处理,当然自己处理之后还是可以交给默认的处理函数bool b_ret = false;do {switch (message) {case WM_TEST_MSG: {int recv_data = (int)wParam;std::cout << "recv_data:" << recv_data;return (LRESULT)recv_data;//将接收的数据返回给sendMessagebreak;}case WM_PAINT:break;case WM_DESTROY: {MessageBoxA(NULL, "exit", "tips", 0);//b_ret = true;//这样就不交给默认处理函数处理,如果需要默认函数处理这里进行注释就好PostQuitMessage(0);//使用这个停止消息队列,不然只是关闭了窗口,但是消息队列仍然存在,程序未退出break;}}} while (false);if (!b_ret) b_ret = DefWindowProc(hwnd, message, wParam, lParam); //默认的处理函数return b_ret;
}int main() {static TCHAR szAppName[] = TEXT("MyWindow");auto hInstance = GetModuleHandleA(NULL);HWND hwnd;MSG msg;WNDCLASS wndclass;        //声明一个窗口类对象//以下为窗口类对象wndclass的属性wndclass.lpfnWndProc = WndProc;                                   //窗口处理函数wndclass.hInstance = hInstance;					  //窗口实例句柄wndclass.lpszClassName = szAppName;                               //窗口类名wndclass.style = CS_HREDRAW | CS_VREDRAW;                         //窗口样式wndclass.lpszMenuName = NULL;                                     //窗口菜单:无wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);    //窗口背景颜色wndclass.cbWndExtra = 0;                                          //窗口实例扩展:无wndclass.cbClsExtra = 0;                                          //窗口类扩展:无wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);               //窗口最小化图标:使用缺省图标wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);                 //窗口采用箭头光标if (!RegisterClassW(&wndclass)){    //注册窗口类, 如果注册失败弹出错误提示MessageBox(NULL, TEXT("窗口注册失败"), TEXT("错误"), MB_OK | MB_ICONERROR);return 0;}hwnd = CreateWindowW(               //创建窗口szAppName,                     //窗口类名TEXT("test_windows"),   //窗口标题WS_OVERLAPPEDWINDOW,           //窗口的风格CW_USEDEFAULT,                 //窗口初始显示位置x:使用缺省值CW_USEDEFAULT,                 //窗口初始显示位置y:使用缺省值CW_USEDEFAULT,                 //窗口的宽度:使用缺省值CW_USEDEFAULT,                 //窗口的高度:使用缺省值NULL,                          //父窗口:无NULL,                          //子菜单:无hInstance,                     //该窗口应用程序的实例句柄 NULL);ShowWindow(hwnd, SW_NORMAL);         //显示窗口while (GetMessageW(&msg, nullptr, 0, 0))        //从消息队列中获取消息,null则获取该进程所有的窗口的消息{TranslateMessage(&msg);                 //将虚拟键消息转换为字符消息DispatchMessage(&msg);                  //分发到回调函数(过程函数)}return msg.wParam;
}

2.消息传递的原理

(1)消息类型
消息队列消息非队列消息系统队列消息线程队列消息

<1> 所有线程产生时并没有消息队列,在第一次调用GDI时会产生线程消息队列.
<2> 队列消息到达系统队列消息,然后再到达线程队列消息.
<3> 非队列消息直接传递给窗口过程

(2)消息的传递

<1> 例如鼠标的单击,鼠标的驱动程序会把事件换成相应的消息,然后传到系统队列消息,系统会根据HWND,把消息传递到相应的窗口的线程队列消息.而进程使用GetMessage获取线程队列消息,然后进行翻译TranslateMessage,分发DispatchMessage,分发的过程就是将此消息传递给所有在进程这里注册的窗口类,然后就会触发窗口类绑定的回调函数
<2> 一般来讲,系统总是将消息Post在消息队列的末尾。这样保证窗口以先进先出的顺序接受消息。然而,WM_PAINT是一个例外,同一个窗口的多个 WM_PAINT被合并成一个 WM_PAINT 消息, 合并所有的无效区域到一个无效区域。合并WM_PAIN的目的是为了减少刷新窗口的次数。

鼠标驱动程序转成相应的消息根据HWND,把消息传递到相应的窗口的线程队列消息GetMessage 获取线程消息队列第一个分发给在消息队列中注册的窗口类,触发处理过程鼠标左键单击系统队列消息进程(线程)队列消息GetMessage/TranslateMessage/DispatchMessageslef_proc
(3)相应的发送消息的函数SendMessage/PostMessage

<1>SendMessage 一直等到消息被处理之后才会返回。不过需要注意的是,如果接收消息的窗口是同一个应用程序的一部分,那么这个窗口的窗口函数就被作为一个子程序马上被调用;如果接收消息的窗口是被另外的线程所创建的,那么窗口系统就切换到相应的线程并且调用相应的窗口函数,这条消息不会被放进目标应用程序队列中。如果是其他进程发送的则会加入到消息队列,等待执行,但是调用sendmessage的进程还是得继续等待返回.

<2> PostMessage的原型如下:BOOL PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam),该函数把一条消息放置到创建hWnd窗口的线程的消息队列中,该函数不等消息被处理就马上将控制返回。需要注意的是,如果hWnd参数为 HWND_BROADCAST,那么,消息将被寄送给系统中的所有的重叠窗口和弹出窗口,但是子窗口不会收到该消息;如果hWnd参数为NULL,则该函数类似于将dwThreadID参数设置成当前线程的标志来调用PostThreadMessage函数。

//程序1,SendMessagge
#include 
#include "log/logx.h"
#include 
#include 
using namespace std;#define WM_TEST_MSG (WM_USER+1)int main(int argc, char** argv) {std::string window_name("test_windows");HWND window = FindWindowA(NULL, "test_windows");LOGXD(VAR_DATA(window),VAR_DATA(window_name));UINT value = 123;auto ret= SendMessageA(window, WM_TEST_MSG,(WPARAM)value ,NULL);LOGXD(VAR_DATA(ret));return 0;
}
/*
[+] log construction, can use it  C:\Desktop\code\test\exe/_log/log.html
[0]08:12:40[debg][9628] [main]  window:  00E70506  window_name:  test_windows   (wtest_main.cpp:12)
[1]08:12:40[debg][9628] [main]  ret:  123   (wtest_main.cpp:15)
[+] ~log deconstruction
*///程序2 接收消息的窗口(例子1.创建基本的窗口程序)
/*
recv_data:123
*/

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...