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中的代碼沒有執行。

這就證明了SendMessage和PostMessage的另一個不同之處:SendMessage發送的消息直接交給對應的窗口過程函數處理,不進消息隊列,而PostMessage發送的消息要進消息隊列等待分發、處理。

發佈了63 篇原創文章 · 獲贊 86 · 訪問量 40萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章