正文

《白手起家Win32SDK应用程序》第八篇 关闭窗口的同时退出程序2005-11-08 17:31:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/whyhappy/6703.html

分享到:

第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程序的基本框架了!(哈,真值得我们去举杯庆祝啦!不过,我的任务还没完啊!还有许多要解决的问题等着我噢!)。

阅读(5282) | 评论(1)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册