windows消息机制的有趣发现(二)
3.一个有窗口和窗口过程函数但没有消息循环的程序
一个程序,如果我们创建了窗口,也定义了窗口过程函数,但是没有建立消息循环会怎样呢?我们在win32控制台项目下编写如下代码:
#include <windows.h>#define WM_TEST 10000LRESULT 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 10000LRESULT 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发送的消息要进消息队列等待分发、处理。
- 1楼chennengtao2小时前
- 还真没有这么想过和折腾过,楼主高手