第8篇 关闭窗口的同时退出程序 白云小飞 还记得上篇中最后说到一个问题吗?当我们关闭程序窗口时,窗口确实是关闭了,可是程序并没有退出啊。为什么呢???一. 理解程序的退出条件: 首先,我们要先明白程序退出的条件,看上篇中的这段代码: while(GetMessage(&msg, NULL, 0, 0)) //获取一个消息,成功后会放在msg中。 { TranslateMessage(&msg); //消息进行必要的预处理转换。 DispatchMessage(&msg); //调用WinProc回调函数,将msg传递给WinProc函数 } 如果程序一直在这个消息循环中,程序就没能退出。只有当GetMessage收到一个WM_QUIT的消息,则返回值才会为零,退出循环,程序得以结束。(这个道理应该好理解吧?)二. 点关闭按钮时,发生了什么 当我们点窗口右上角的关闭按钮时,到底发生了什么事呢?(请边看源代码,边体会下面的分析噢!) 第一. 它并没有(或最终没有导致)发出WM_QUIT的消息。因此GetMessage函数不会收到WM_QUIT消息,就没法跳出循环了。(那么又产生了什么消息呢?) 第二. 点关闭按钮时,产生WM_CLOSE的消息。GetMessage会收到WM_CLOSE消息的MSG结构信息。 第三. 按前篇所述的消息处理流程可知:DespatchMessage会调用WinProc回调函数,并把WM_CLOSE消息的相关信息传递给WinProc函数参数中。 第四. 现在我们的WinProc里只有一句:LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam){//这里可以添加你的消息处理代码 return DefWindowProc(hwnd, msg, wparam, lparam);} 它将WM_CLOSE继续传递给缺省窗口过程函数DefWindowProc。 第五. 在DefWindowProc函数里,判断是WM_CLOSE消息后,就会对参数hwnd所代表的窗口进行销毁。(看吧,销毁窗口的事也是由DefWindowProc来完成了。) 第六. 成功销毁窗口后,DefWindowProc里接着还会发一个WM_DESTROY的消息到消息队列中(表示说窗口已经被销毁了)。然后DefWindowProc函数才结束。 第七. 回到我们的消息循环的GetMessage函数。这个函数又会获得WM_DESTROY消息的信息,开始了下一个消息处理过程。 第八. 这个WM_DESTROY可在WinProc函数中由我们处理。但在WinProc函数体的代码中我们没有自己去处理它。仍然是让DefWindowProc去处理。 第九. 然而,DefWindowProc只是简单地把它给“扔掉”了。 第十. 整个点窗口右上角的关闭按钮作所的所有动作就这样完成了。 你看,上述中,上述程序始终没有产生WM_QUIT的消息,所以窗口确实是销毁了,但程序并没有退出这个消息处理循环。 哦,怪不得我们的程序没法结束了。(那该怎么办呢?)三. 如何使程序结束。 退出程序的三点说明:1. 我们希望是通过单击这个窗口右上角的关闭按钮时来退出程序。2. 应该在窗口成功销毁后,才让程序退出。3. 只要让程序产生一个WM_QUIT消息,就可以退出循环而结束程序。 终上所述,程序应在收到WM_DESTROY消息后才能退出程序。因为WM_DESTROY消息表示窗口已经销毁。 那么我们又如何才能产生一个WM_QUIT的消息呢?用下面这个--API函数:PostQuitMessage(0); 参数代入0值就可。它将产生一个WM_QUIT消息。WM_QUIT消息最终会被GetMessage函数“摘取”到并返回0值。从而退出循环,结束程序。看我实现代码:LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam){ switch (msg) //msg中保存的就是正要处理的消息 { case WM_DESTROY: //这是我们自行处理的第一个消息 { PostQuitMessage(0); //发出一个WM_QUIT消息 return 0; //然后直接返回。 }break; default:break; } return DefWindowProc(hwnd, msg, wparam, lparam);}int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow){ HWND hWnd; MSG msg; WNDCLASSEX wndclass; //…… 这里省略了前面所述的注册窗口类的过程 // hWnd=CreateWindowEx(NULL,WND_CLS_NAME, "这是我的第一个窗口", WS_OVERLAPPEDWINDOW|WS_VISIBLE , CW_USEDEFAULT, 0, 400,400, NULL, NULL, hinstance, NULL ); if (!hWnd) return 0; ShowWindow(hWnd, ncmdshow); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } WinProc函数参数中的UINT msg就是程序传递进来的消息标识。我们只要判断msg是否为WM_DESTROY消息,如果是就发一个WM_QUIT消息。 补充说明一点: WinProc函数参数中有一个msg变量,而WinMain函数中也定义了一个msg。不要把它们给混了啊!它们可是不同的变量啊!WinMain中定义的msg类型是MSG,在Winuser.h中已定义如下:typedef struct tagMSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt;} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG; 你看,它是一个结构体。而WinProc参数中的msg是一个UINT类型,它其实只是WinProc函数里的msg结构成员message的值。 你看看DispatchMessage(&msg);是如何传递这个msg给WinProc的: 它在调用WinProc时,会—— 将msg.hwnd值传递给WinProc参数中的HWND hwnd; 将msg.message值传递给WinProc参数中的UINT msg; 将msg.wParam传递给WinProc参数中的WPARAM wParam; 将msg.lParam值传递给WinProc参数中的LPARAM lParam。 整个程序实现退出的流程还是让你自行去分析啦!应该不会太难吧!? 至此,终于完成了这个SDK程序的基本框架了!(哈,真值得我们去举杯庆祝啦!不过,我的任务还没完啊!还有许多要解决的问题等着我噢!)。

评论