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發送的消息要進消息隊列等待分發、處理。