刚刚开始学习 windows 编程,就遇到一件比较尴尬的事。学着孙鑫老师的例子,马马虎虎搭了一个框。没想到最后的地方落了一句:在消息处理函数中,对于默认消息的处理,本应该这么写:
default:
return DefWindowProc(hWnd,message,wParam,lParam);
不过我却写成了这样:
default:
DefWindowProc(hWnd,message,wParam,lParam);
少了一个返回值,结果是窗口就显示不出来了。但是这个进程却开启了。
为找到错误而松了一口气的同时,开始思索这到底是为什么。接下来写上自己的思考,并无结论,仅仅是脑海里的笔记而已,只为自己日后参考。企图寻找答案的同胞请赶紧另寻它途免得浪费时间;而已知其中奥秘的大神请不要吝啬写下你们的良方。谢谢。
我理解一个windows程序的运行,会有四个部件参与:
a. 应用程序主体。
b. windows操作系统。
c. 一个关于本程序的消息队列。
d. 一个关于本程序的消息处理函数。
a.应用程序主体负责构建窗口类,并注册它,创建对应窗口,然后令其显示更新。接下来就进入消息循环主体,在这里进行轮复一轮的运转,直到有退出消息使其解脱。
b. windows操作系统负责从c. (一个关于本程序的消息列表) 中提取消息。然而事实上它不是第一提取人。应用程序主体才是。因为应用程序主体中有GetMessage(&msg,NULL,0,0)函数,它将消息队列提取到msg结构体中。消息队列在哪里?它对我们不可见,我们不知道它在哪里。但却总能通过msg来获悉消息。接下来,应用程序调用函数TranslateMessage(&msg)做了一些翻译,不必知道细节,因为不影响结果。再然后,应用程序调用DispatchMessage(&msg)把消息传递给了windows,可以说这个时侯,windows才开始接管该消息,而且window也开始介入该应用程序,接手其控制权。那么DispatchMessage(&msg)做了什么?网上查了一下,它把该消息发给了d. ( 一个关于本程序的消息处理函数) 。而且只有当消息处理函数返回后,它才返回。也就是说,消息处理函数的运作,是包含在DispatchMessage(&msg)这一步里的。
c.关于本程序的消息队列,对程序员透明。至少目前对我来说透明。
d.消息处理函数,由应用程序编写,但却由操作系统调用。孙鑫老师比喻的好,应用程序好比一家汽车生产厂家,windows好比顾客,而消息处理函数好比对应汽车品牌的修理厂家。汽车生产商不负责修理汽车,但却会为顾客指定一家修理商。以后汽车坏了,不必找生产商,而是直接找修理商。不过这个比喻虽然生动,细想还是不太妥当。因为程序毕竟不是汽车生产商,程序可以直接负责传递消息给自己,然后再自己处理,这种情况不是实现不了,但为何中间一定要通过windows来插这一脚呢?想必一定有它的道理,我认为这中间的原委深刻而合理,所以也不怀疑。
根据以上的分析,再来思考为什么没有return就显示不了窗口。我在想为什么需要消息处理函数需要返回值?既然有返回值,那应该是用来判断这条消息处理成功了没有。它的返回值带有处理结果的某种信息。操作系统根据该信息来做下一步的部署。比如,如果处理成功了,那么应该把控制权交回给应用程序,这时应用程序会接着从消息队列里取出下一条消息;如果没成功,那么可能(我不知道,猜的)windows会等待其响应直到处理完毕得到结果。这样的话,因为我的程序里没有写上这个return,因此windows就永远也不知道消息处理得怎么样了,它将会一直等待在这里。这时程序就卡住了。
又想了想感觉是在胡扯,因为发现,这么写程序照样运转的很好:
switch(uMsg)
{
case WM_PAINT:
HDC hDC;
PAINTSTRUCT ps;
hDC=BeginPaint(hwnd,&ps);
EndPaint(hwnd,&ps);
break;
case WM_CLOSE:
if(IDYES==MessageBox(hwnd,"是否真的结束?","weixin",MB_YESNO))
{
DestroyWindow(hwnd);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
//return 0; 去掉这个返回值
}
当产生WM_PAINT、 WM_CLOSE、 WM_DESTROY这样的消息时,程序应该不会返回值了吧,但还能运转。Jesus Christ.