日期:2014-05-16  浏览次数:20814 次

windows消息机制的有趣发现(二)

3.一个有窗口和窗口过程函数但没有消息循环的程序

一个程序,如果我们创建了窗口,也定义了窗口过程函数,但是没有建立消息循环会怎样呢?我们在win32控制台项目下编写如下代码:

#include <windows.h>
#define WM_TEST 10000

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
 
void main()
{
	static TCHAR szAppName[]=TEXT("Test!");		
	HWND hwnd;														
	WNDCLASS wndclass = {NULL};
	wndclass.lpfnWndProc = WndProc;
	wndclass.style = CS_HREDRAW|CS_VREDRAW;
	wndclass.lpszClassName	= szAppName;
	RegisterClass(&wndclass);
	hwnd=CreateWindow(szAppName,
		TEXT("The Test Program"),										
		WS_OVERLAPPEDWINDOW,											
		CW_USEDEFAULT,												
		CW_USEDEFAULT,												
		CW_USEDEFAULT,													
		CW_USEDEFAULT,
		NULL,
		NULL,	
		NULL,
		NULL);	
	ShowWindow(hwnd,SW_SHOW);
	UpdateWindow(hwnd);	

	system("pause");
}


LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM IParam) 
{	
	switch(message)
	{
	case WM_TEST:
		MessageBox(NULL,TEXT("消息响应!"),TEXT("消息响应!"),MB_OK);
		return 50;
	}
	return DefWindowProc(hwnd,message,wParam,IParam);
}

这是一个简单的win32窗口程序,但是我们在窗口过程函数WndProc中没有定义对WN_PAINT消息的处理,在main函数中创建完窗口后也没有建立消息循环,运行程序后会发生什么呢?

运行发现,窗口确实被创建出来了。但是鼠标移动上去就会发现该窗体如图假死一样没有了响应。这是因为包括自绘消息WM_PAINT在内的所有消息都被放入了线程的消息队列里,但是我们没有消息循环!没有取出消息队列中的消息,更没有处理这些消息,我们连窗口过程中对应WM_PAINT的消息处理函数都没有。界面自然就假死了。

4.SendMessage和PostMessage消息的另一个区别

之前我写过一篇博文说过SendMessage和PostMessage的却别在于SendMessage要等消息被处理完成后才返回,如果调用SendMessage后该消息一直未处理完,SendMessage会一直阻塞到处理完为止。而PostMessage不会阻塞,不等处理结果直接返回。实际上他们还有一个区别:PostMessage发送的消息会进入消息队列等待提取,而SendMessage发送的消息不进消息队列,直接交给窗口过程函数处理。为了验证这个说法,我们编写如下代码:

#include <windows.h>
#define WM_TEST 10000

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
 
void main()
{
	static TCHAR szAppName[]=TEXT("Test!");		
	HWND hwnd;														
	WNDCLASS wndclass = {NULL};
	wndclass.lpfnWndProc = WndProc;
	wndclass.style = CS_HREDRAW|CS_VREDRAW;
	wndclass.lpszClassName	= szAppName;
	RegisterClass(&wndclass);
	hwnd=CreateWindow(szAppName,
		TEXT("The Test Program"),										
		WS_OVERLAPPEDWINDOW,											
		CW_USEDEFAULT,												
		CW_USEDEFAULT,												
		CW_USEDEFAULT,													
		CW_USEDEFAULT,
		NULL,
		NULL,	
		NULL,
		NULL);	
	ShowWindow(hwnd,SW_SHOW);
	UpdateWindow(hwnd);	

	int i = SendMessage(hwnd,WM_TEST,NULL,NULL);

	system("pause");
}


LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM IParam) 
{	
	switch(message)
	{
	case WM_TEST:
		MessageBox(NULL,TEXT("消息响应!"),TEXT("消息响应!"),MB_OK);
		return 50;
	}
	return DefWindowProc(hwnd,message,wParam,IParam);
}

我们在创建完窗口后用SendMessage发送了一条WM_TEST的自定义消息,在窗口过程函数WndProc中我们定义对WM_TEST的处理方式为弹出一个MessageBox并返回50。

运行后发现,纵使我们创建的窗体依然是假死状态,仍然弹出了MessageBox,并且SendMessage的返回值i为50。说明我们在窗口过程函数WndProc中定义的对WM_TEST消息的处理代码成功执行!注意,我们这个程序中是没有消息循环的,但是我们用SendMessage发送的消息还是被窗口过程函数WndProc处理了。

我们把SendMessage改为PostMessage再试。运行后发现没有弹出MessageBox。为什么呢?因为PostMessage发送的消息要进消息队列,但我们没有消息循环,没有用GetMessage之类的函数从消息队列中取消息,更没有用DispatchMessage分发消息,所以我们用PostMessage发送的WM_TEST还在消息队列里待着呢。窗口过程函数WndProc中的代码没有执行。