2013.8.6 学习笔记《windows核心编程》(九) 消息获取,消息派发与消息分类
2013-08-06 22:39
459 查看
《windows核心编程》(九)-----------2013.8.6
一、概念
Windows常用消息
WM_QUIT - 用于结束消息循环处理。
wParam - PostQuitMessage 函数传递的参数。
lParam - 不使用
当GetMessage收到这个消息后,会返回FALSE,结束while处理,退出消息循环。
WM_PAINT - 绘图消息
键盘消息
鼠标消息
定时器消息
消息的获取
•GetMessage - 从系统获取消息,将消息从系统中移除,阻塞函数。当系统无消息时,GetMessage会等候下一条消息。
•PeekMessage - 以查看的方式从系统获取消息,可以不将消息从系统移除,非阻塞函数。当系统无消息时,返回FALSE,继续执行后续代码。
BOOL PeekMessage(
LPMSG lpMsg, // message information
HWND hWnd, // handle to window
UINT wMsgFilterMin, // first message
UINT wMsgFilterMax, // last message
UINT wRemoveMsg //移除标识
);
GetMessage函数与PeekMessage函数的区别:
因为GetMessage函数时阻塞函数,所以当cpu处理GetMessage函数时,当没有消息发送,则程序阻塞在GetMessage函数中,一直等待消息,这大大的浪费了cpu的时间片时间,所以我们可以用PeekMessage函数进行处理,当没有消息发送则不调用GetMessage函数,或者在这空闲时间可以让操作系统做别的事。
代码如下:
运行结果:
•SendMessage - 发送消息,会等候消息处理的结果。
•PostMessage - 投递消息,消息发出后立刻返回,不等候消息执行结果。
BOOL SendMessage/PostMessage(
HWND hWnd,//消息发送的目的窗口
UINT Msg, //消息ID
WPARAM wParam, //消息参数
LPARAM lParam //消息参数
);
我们知道WM_QUIT消息是用于结束消息循环,那么我们就调用SendMessage函数和PostMessage函数进行比较。
首先调用SendMessage函数:
代码如下:
经过测试可知,调用SendMessage函数当窗口关闭了,但是程序进程不会销毁,这是为什么呢?
我们再来调用PostMessage函数测试看看:
代码如下:
得出结果,调用PostMessage函数可以退出程序。
消息的分类
1 系统消息 - ID范围 0 - 0x03FF
由系统定义好的消息,可以在程序中直接使用。
2 用户自定义消息 - ID范围 0x0400 - 0x7FFF (31743)
由用户自己定义,满足用户自己的需求。由用户自己发出消息,并响应处理。
定义宏 WM_USER 代表0x400,自定义消息ID时
#define WM_MYMESSAGE WM_USER+n
3 应用程序消息 - ID范围 0x8000 - 0xBFFF
程序之间通讯时使用的消息。
应用程序消息宏:WM_APP
4 系统注册消息 - ID范围 0xC000 - 0xFFFF
在系统注册并生成相应消息,然后可以在各个程序中使用这个消息。
那么我们自己定义一个消息来测试看看,我们定义一个消息名为WM_MYMESSAGE,我们再分别用SendMessage函数与PostMessage函数进行测试,看看会有什么区别吗。
代码如下:
可以弹出MessageBox
我们再用PostMessage函数试试:
代码如下:
运行结果:
三、问题
SendMessage不是将消息发送到操作系统中,为什么GetMessage也可以获取到SendMessage发送的用户自定义的消息?
SendMessage不将消息发送到消息队列中,而是系统直接调用目标窗口的消息处理程序,并不是GetMessage函数获取到了SendMessage函数的发送的消息。
至于使用PostMessage函数发送WM_QUIT消息可以退出程序而使用SendMessage函数不行是因为:GetMessage函数在消息队列里面获取到了WM_QUIT消息时,GetMessage函数的才会返回FALSE,而SendMessage发送的消息并没有进入系统消息队列中去,所以不能使消息循环退出。
一、概念
Windows常用消息
WM_QUIT - 用于结束消息循环处理。
wParam - PostQuitMessage 函数传递的参数。
lParam - 不使用
当GetMessage收到这个消息后,会返回FALSE,结束while处理,退出消息循环。
WM_PAINT - 绘图消息
键盘消息
鼠标消息
定时器消息
消息的获取
•GetMessage - 从系统获取消息,将消息从系统中移除,阻塞函数。当系统无消息时,GetMessage会等候下一条消息。
•PeekMessage - 以查看的方式从系统获取消息,可以不将消息从系统移除,非阻塞函数。当系统无消息时,返回FALSE,继续执行后续代码。
BOOL PeekMessage(
LPMSG lpMsg, // message information
HWND hWnd, // handle to window
UINT wMsgFilterMin, // first message
UINT wMsgFilterMax, // last message
UINT wRemoveMsg //移除标识
);
GetMessage函数与PeekMessage函数的区别:
因为GetMessage函数时阻塞函数,所以当cpu处理GetMessage函数时,当没有消息发送,则程序阻塞在GetMessage函数中,一直等待消息,这大大的浪费了cpu的时间片时间,所以我们可以用PeekMessage函数进行处理,当没有消息发送则不调用GetMessage函数,或者在这空闲时间可以让操作系统做别的事。
代码如下:
// WinCreate.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "windows.h" HINSTANCE g_hInstance = 0;//用于接受应用程序实例句柄 HANDLE g_hOutput = 0; //窗口处理函数 LRESULT CALLBACK WndProc(HWND hWnd,UINT nMsg, WPARAM wParam,LPARAM lParam) { switch(nMsg) { case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hWnd,nMsg,wParam,lParam); } //注册窗口类 BOOL Register(LPSTR lpClassName,WNDPROC wndproc) { WNDCLASSEX wce = {0}; wce.cbSize = sizeof(wce); wce.cbClsExtra = 0; wce.cbWndExtra = 0; wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wce.hCursor = NULL; wce.hIcon = NULL; wce.hIconSm = NULL; wce.hInstance = g_hInstance; wce.lpfnWndProc = wndproc; wce.lpszClassName = lpClassName; wce.lpszMenuName = NULL; wce.style = CS_HREDRAW | CS_VREDRAW; ATOM nAtom = RegisterClassEx(&wce); if(nAtom == 0) { return FALSE; } return TRUE; } //创建主窗口 HWND CreateMain(LPSTR lpClassName,LPSTR lpWndName) { HWND hWnd = CreateWindowEx(0,lpClassName,lpWndName, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL,NULL,g_hInstance,NULL); return hWnd; } //显示窗口 void Display(HWND hWnd) { ShowWindow(hWnd,SW_SHOW); UpdateWindow(hWnd); } //消息循环 void Message() { MSG nMsg = {0}; while(true) { if(PeekMessage(&nMsg,NULL,0,0,PM_NOREMOVE)) { if(GetMessage(&nMsg,NULL,0,0)) { TranslateMessage(&nMsg); DispatchMessage(&nMsg); } else { return; } } else { //当没有消息时 WriteConsole(g_hOutput,"空闲处理\n",strlen("空闲处理\n"),NULL,NULL); } } } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // TODO: Place code here. AllocConsole(); g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); g_hInstance = hInstance; Register("Main",WndProc); HWND hWnd = CreateMain("Main","Window"); Display(hWnd); Message(); return 0; }
运行结果:
•SendMessage - 发送消息,会等候消息处理的结果。
•PostMessage - 投递消息,消息发出后立刻返回,不等候消息执行结果。
BOOL SendMessage/PostMessage(
HWND hWnd,//消息发送的目的窗口
UINT Msg, //消息ID
WPARAM wParam, //消息参数
LPARAM lParam //消息参数
);
我们知道WM_QUIT消息是用于结束消息循环,那么我们就调用SendMessage函数和PostMessage函数进行比较。
首先调用SendMessage函数:
代码如下:
// WinCreate.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "windows.h" HINSTANCE g_hInstance = 0;//用于接受应用程序实例句柄 HANDLE g_hOutput = 0; //窗口处理函数 LRESULT CALLBACK WndProc(HWND hWnd,UINT nMsg, WPARAM wParam,LPARAM lParam) { switch(nMsg) { case WM_DESTROY: //PostQuitMessage(0); SendMessage(hWnd,WM_QUIT,0,0); break; } return DefWindowProc(hWnd,nMsg,wParam,lParam); } //注册窗口类 BOOL Register(LPSTR lpClassName,WNDPROC wndproc) { WNDCLASSEX wce = {0}; wce.cbSize = sizeof(wce); wce.cbClsExtra = 0; wce.cbWndExtra = 0; wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wce.hCursor = NULL; wce.hIcon = NULL; wce.hIconSm = NULL; wce.hInstance = g_hInstance; wce.lpfnWndProc = wndproc; wce.lpszClassName = lpClassName; wce.lpszMenuName = NULL; wce.style = CS_HREDRAW | CS_VREDRAW; ATOM nAtom = RegisterClassEx(&wce); if(nAtom == 0) { return FALSE; } return TRUE; } //创建主窗口 HWND CreateMain(LPSTR lpClassName,LPSTR lpWndName) { HWND hWnd = CreateWindowEx(0,lpClassName,lpWndName, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL,NULL,g_hInstance,NULL); return hWnd; } //显示窗口 void Display(HWND hWnd) { ShowWindow(hWnd,SW_SHOW); UpdateWindow(hWnd); } //消息循环 void Message() { MSG nMsg = {0}; /* while (GetMessage(&nMsg,NULL,0,0)) { TranslateMessage(&nMsg); DispatchMessage(&nMsg); } */ while(true) { if(PeekMessage(&nMsg,NULL,0,0,PM_NOREMOVE)) { if(GetMessage(&nMsg,NULL,0,0)) { TranslateMessage(&nMsg); DispatchMessage(&nMsg); } else { return; } } else { //当没有消息时 WriteConsole(g_hOutput,"空闲处理\n",strlen("空闲处理\n"),NULL,NULL); } } } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // TODO: Place code here. AllocConsole(); g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); g_hInstance = hInstance; Register("Main",WndProc); HWND hWnd = CreateMain("Main","Window"); Display(hWnd); Message(); return 0; }
经过测试可知,调用SendMessage函数当窗口关闭了,但是程序进程不会销毁,这是为什么呢?
我们再来调用PostMessage函数测试看看:
代码如下:
// WinCreate.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "windows.h" HINSTANCE g_hInstance = 0;//用于接受应用程序实例句柄 HANDLE g_hOutput = 0; //窗口处理函数 LRESULT CALLBACK WndProc(HWND hWnd,UINT nMsg, WPARAM wParam,LPARAM lParam) { switch(nMsg) { case WM_DESTROY: //PostQuitMessage(0); 4000 //SendMessage(hWnd,WM_QUIT,0,0); PostMessage(hWnd,WM_QUIT,0,0); break; } return DefWindowProc(hWnd,nMsg,wParam,lParam); } //注册窗口类 BOOL Register(LPSTR lpClassName,WNDPROC wndproc) { WNDCLASSEX wce = {0}; wce.cbSize = sizeof(wce); wce.cbClsExtra = 0; wce.cbWndExtra = 0; wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wce.hCursor = NULL; wce.hIcon = NULL; wce.hIconSm = NULL; wce.hInstance = g_hInstance; wce.lpfnWndProc = wndproc; wce.lpszClassName = lpClassName; wce.lpszMenuName = NULL; wce.style = CS_HREDRAW | CS_VREDRAW; ATOM nAtom = RegisterClassEx(&wce); if(nAtom == 0) { return FALSE; } return TRUE; } //创建主窗口 HWND CreateMain(LPSTR lpClassName,LPSTR lpWndName) { HWND hWnd = CreateWindowEx(0,lpClassName,lpWndName, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL,NULL,g_hInstance,NULL); return hWnd; } //显示窗口 void Display(HWND hWnd) { ShowWindow(hWnd,SW_SHOW); UpdateWindow(hWnd); } //消息循环 void Message() { MSG nMsg = {0}; /* while (GetMessage(&nMsg,NULL,0,0)) { TranslateMessage(&nMsg); DispatchMessage(&nMsg); } */ while(true) { if(PeekMessage(&nMsg,NULL,0,0,PM_NOREMOVE)) { if(GetMessage(&nMsg,NULL,0,0)) { TranslateMessage(&nMsg); DispatchMessage(&nMsg); } else { return; } } else { //当没有消息时 WriteConsole(g_hOutput,"空闲处理\n",strlen("空闲处理\n"),NULL,NULL); } } } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // TODO: Place code here. AllocConsole(); g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); g_hInstance = hInstance; Register("Main",WndProc); HWND hWnd = CreateMain("Main","Window"); Display(hWnd); Message(); return 0; }
得出结果,调用PostMessage函数可以退出程序。
消息的分类
1 系统消息 - ID范围 0 - 0x03FF
由系统定义好的消息,可以在程序中直接使用。
2 用户自定义消息 - ID范围 0x0400 - 0x7FFF (31743)
由用户自己定义,满足用户自己的需求。由用户自己发出消息,并响应处理。
定义宏 WM_USER 代表0x400,自定义消息ID时
#define WM_MYMESSAGE WM_USER+n
3 应用程序消息 - ID范围 0x8000 - 0xBFFF
程序之间通讯时使用的消息。
应用程序消息宏:WM_APP
4 系统注册消息 - ID范围 0xC000 - 0xFFFF
在系统注册并生成相应消息,然后可以在各个程序中使用这个消息。
那么我们自己定义一个消息来测试看看,我们定义一个消息名为WM_MYMESSAGE,我们再分别用SendMessage函数与PostMessage函数进行测试,看看会有什么区别吗。
代码如下:
// WinCreate.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "windows.h" HINSTANCE g_hInstance = 0;//用于接受应用程序实例句柄 HANDLE g_hOutput = 0; #define WM_MYMESSAGE WM_USER + 10001//定义一个用户自定义消息 //窗口处理函数 LRESULT CALLBACK WndProc(HWND hWnd,UINT nMsg, WPARAM wParam,LPARAM lParam) { switch(nMsg) { case WM_MYMESSAGE: MessageBox(NULL,"WM_MYMESSAGE","Infor",MB_OK);//弹出一个MessageBox break; case WM_CREATE: SendMessage(hWnd,WM_MYMESSAGE,1,2); break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hWnd,nMsg,wParam,lParam); } //注册窗口类 BOOL Register(LPSTR lpClassName,WNDPROC wndproc) { WNDCLASSEX wce = {0}; wce.cbSize = sizeof(wce); wce.cbClsExtra = 0; wce.cbWndExtra = 0; wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wce.hCursor = NULL; wce.hIcon = NULL; wce.hIconSm = NULL; wce.hInstance = g_hInstance; wce.lpfnWndProc = wndproc; wce.lpszClassName = lpClassName; wce.lpszMenuName = NULL; wce.style = CS_HREDRAW | CS_VREDRAW; ATOM nAtom = RegisterClassEx(&wce); if(nAtom == 0) { return FALSE; } return TRUE; } //创建主窗口 HWND CreateMain(LPSTR lpClassName,LPSTR lpWndName) { HWND hWnd = CreateWindowEx(0,lpClassName,lpWndName, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL,NULL,g_hInstance,NULL); return hWnd; } //显示窗口 void Display(HWND hWnd) { ShowWindow(hWnd,SW_SHOW); UpdateWindow(hWnd); } //消息循环 void Message() { MSG nMsg = {0}; while(true) { if(PeekMessage(&nMsg,NULL,0,0,PM_NOREMOVE)) { if(GetMessage(&nMsg,NULL,0,0)) { TranslateMessage(&nMsg); DispatchMessage(&nMsg); } else { return; } } else { //当没有消息时 WriteConsole(g_hOutput,"空闲处理\n",strlen("空闲处理\n"),NULL,NULL); } } } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // TODO: Place code here. AllocConsole(); g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); g_hInstance = hInstance; Register("Main",WndProc); HWND hWnd = CreateMain("Main","Window"); Display(hWnd); Message(); return 0; }
可以弹出MessageBox
我们再用PostMessage函数试试:
代码如下:
// WinCreate.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "windows.h" HINSTANCE g_hInstance = 0;//用于接受应用程序实例句柄 HANDLE g_hOutput = 0; #define WM_MYMESSAGE WM_USER + 10001//定义一个用户自定义消息 //窗口处理函数 LRESULT CALLBACK WndProc(HWND hWnd,UINT nMsg, WPARAM wParam,LPARAM lParam) { switch(nMsg) { case WM_MYMESSAGE: MessageBox(NULL,"WM_MYMESSAGE","Infor",MB_OK);//弹出一个MessageBox break; case WM_CREATE: PostMessage(hWnd,WM_MYMESSAGE,1,2); break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hWnd,nMsg,wParam,lParam); } //注册窗口类 BOOL Register(LPSTR lpClassName,WNDPROC wndproc) { WNDCLASSEX wce = {0}; wce.cbSize = sizeof(wce); wce.cbClsExtra = 0; wce.cbWndExtra = 0; wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wce.hCursor = NULL; wce.hIcon = NULL; wce.hIconSm = NULL; wce.hInstance = g_hInstance; wce.lpfnWndProc = wndproc; wce.lpszClassName = lpClassName; wce.lpszMenuName = NULL; wce.style = CS_HREDRAW | CS_VREDRAW; ATOM nAtom = RegisterClassEx(&wce); if(nAtom == 0) { return FALSE; } return TRUE; } //创建主窗口 HWND CreateMain(LPSTR lpClassName,LPSTR lpWndName) { HWND hWnd = CreateWindowEx(0,lpClassName,lpWndName, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL,NULL,g_hInstance,NULL); return hWnd; } //显示窗口 void Display(HWND hWnd) { ShowWindow(hWnd,SW_SHOW); UpdateWindow(hWnd); } //消息循环 void Message() { MSG nMsg = {0}; while(true) { if(PeekMessage(&nMsg,NULL,0,0,PM_NOREMOVE)) { if(GetMessage(&nMsg,NULL,0,0)) { TranslateMessage(&nMsg); DispatchMessage(&nMsg); } else { return; } } else { //当没有消息时 WriteConsole(g_hOutput,"空闲处理\n",strlen("空闲处理\n"),NULL,NULL); } } } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // TODO: Place code here. AllocConsole(); g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); g_hInstance = hInstance; Register("Main",WndProc); HWND hWnd = CreateMain("Main","Window"); Display(hWnd); Message(); return 0; }
运行结果:
三、问题
SendMessage不是将消息发送到操作系统中,为什么GetMessage也可以获取到SendMessage发送的用户自定义的消息?
SendMessage不将消息发送到消息队列中,而是系统直接调用目标窗口的消息处理程序,并不是GetMessage函数获取到了SendMessage函数的发送的消息。
至于使用PostMessage函数发送WM_QUIT消息可以退出程序而使用SendMessage函数不行是因为:GetMessage函数在消息队列里面获取到了WM_QUIT消息时,GetMessage函数的才会返回FALSE,而SendMessage发送的消息并没有进入系统消息队列中去,所以不能使消息循环退出。
相关文章推荐
- 2013.8.5 学习笔记《windows核心编程》(八) 常用消息
- MFC学习笔记之四————菜单编程与windows消息分类
- 2013.8.13 学习笔记《windows核心编程》(十一) 键盘消息与翻译消息
- 2013.8.15 学习笔记《windows核心编程》(十二) 鼠标消息与定时器消息
- MFC学习笔记之四————菜单编程与windows消息分类
- 百度IFE学习笔记(三)js获取页面内容及后续处理
- JavaScript学习笔记之获取日期间隔天数
- 【ext学习笔记】JS获取各种浏览器窗口的大小
- AIDL学习笔记2之从Service获取地理位置
- Apache Shiro学习笔记(二)身份验证获取SecurityManager
- 设计模式分类--学习笔记
- Cocos2d-x 3D功能学习笔记 分类: cocos2d代码编写 2015-07-27 18:57 8人阅读 评论(0) 收藏
- python3.4学习笔记(二十三) Python调用淘宝IP库获取IP归属地返回省市运营商实例代码
- redis lua脚本学习笔记math.random()获取随机数
- iOS学习笔记-协议,代码块,分类
- 第106讲:解析Akka中的消息的不同发送方式方式详解学习笔记
- WinApi学习笔记-获取光驱中的信息
- JavaScript学习笔记之获取当前目录的实现代码
- 【Struts2学习笔记(8)】访问或添加request/session/application属性获取HttpServletRequest / HttpSession / ServletContex
- DeepLearning学习笔记-回归-分类-梯度下降