您的位置:首页 > 编程语言

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函数,或者在这空闲时间可以让操作系统做别的事。

代码如下:
// 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发送的消息并没有进入系统消息队列中去,所以不能使消息循环退出。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: