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发送的消息要进消息队列等待分发、处理。