2013.8.6 学习笔记《windows核心编程》(九) 消息获取,消息派发与消息分类

《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);
		//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发送的消息并没有进入系统消息队列中去,所以不能使消息循环退出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值