发新话题
打印

白手起家Win32SDK应用程序8 关闭窗口的同时退出程序

白手起家Win32SDK应用程序8 关闭窗口的同时退出程序

知识若不分享 实在没有意义 http://www.d-programming-language-china.org 20070506

点击下面网址查看原文:
http://www.d-programming-language-china.org

by: 白云小飞 D语言论坛 http://www.d-programming-language-china.org 增加D语言实例教程

还记得上篇中最后说到一个问题吗?当我们关闭程序窗口时,窗口确实是关闭了,可是程序并没有退出啊。为什么呢???

理解程序的退出条件

首先,我们要先明白程序退出的条件,看上篇中的这段代码:

QUOTE:
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里只有一句:

QUOTE:
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函数:( 本文出处: http://www.d-programming-language-china.org )

QUOTE:
PostQuitMessage(0);

参数代入0值就可。它将产生一个WM_QUIT消息。WM_QUIT消息最终会被GetMessage函数“摘取”到并返回0值。从而退出循环,结束程序。看我实现代码:

QUOTE:
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;
}

D语言论坛 http://www.d-programming-language-china.org 按:
写成D语言代码是这样的:

extern (Windows):
LRESULT WinProc(HWND hwnd,
                     UINT msg,
                     WPARAM wparam,
                     LPARAM lparam)
{
    switch (msg)    //msg中保存的就是正要处理的消息
    {
        case WM_DESTROY:    //这是我们自行处理的第一个消息
        {
            PostQuitMessage(0);    //发出一个WM_QUIT消息
            return 0;    //然后直接返回。
        }
        default:
            return (DefWindowProc(hwnd, msg, wparam, lparam));
    }

}

extern (Windows):
int WinMain(HINSTANCE hinstance,
             HINSTANCE hprevinstance,
             LPSTR lpcmdline,
             int ncmdshow)
{
    HWND hWnd;
    MSG msg;
    WNDCLASSEX wndclass;
    //……    这里省略了前面所述的注册窗口类的过程
    //
    hWnd=CreateWindowEx(NULL,WND_CLS_NAME,
                "一大步成功社区 http://bbs.d-programming-language-china.org ",
                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中已定义如下:

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

( lastupdate:20070506 最新文章请访问http://www.d-programming-language-china.org )

关于一大步成功社区:
yidabu提倡在交流中学习,在分享中提高
收集感兴趣的知识,写下心得,通过网络与别人一起分享
理解一点就实践一步,收获什么就分享什么,成功就是这样一点点一步步累积起来的
网络只是一个工具,只有自己身心提高才是实实在在的。d-programming-language-china.org为大家提供一个学习交流各种知识的平台

TOP

发新话题