D语言中国主页  D语言编辑器SciTE4D   DWin库 D语言官方网站
D语言编译器1.x最新版 OpenSource   Tango   webnews  Wiki

查看完整版本: D语言GUI入门6 GetMessage消息循环的错误分析

yidabu 2007-5-10 14:41

D语言GUI入门6 GetMessage消息循环的错误分析

D语言GUI入门6 GetMessage消息循环的错误分析知识若不分享 实在没有意义 http://www.d-programming-language-china.org 20070510点击下面网址查看原文:http://www.d-programming-language-china.org        by:        孙鑫(VC++深入详解)        D语言论坛 http://www.d-programming-language-china.org 增加D语言相关说明tag:GetMessage函数,windows sdk编程        消息循环的错误分析        有不少初学者学完前面内容后,编写了下面的代码:        QUOTE:                                …                HWND hwnd;                hwnd=CreateWindow(…);                …                MSG msg;                while(GetMessage(&msg,hwnd,0,0))                {                    TranslateMessage(&msg);                    DispatchMessage(&msg);                }                …                注意代码中以粗体显示的部分。这段代码基于这样一个想法:第1章的程序只有一个窗口,而我们前面说了GetMessage函数的hWnd参数是用于指定接收属于哪一个窗口的消息,于是不少人就在消息循环中为GetMessage函数的hWnd参数指定了CreateWindow函数返回的窗口句柄。        读者可以用上述代码中的消息循环部分替换1.5节代码中的消息循环部分,然后运行程序,关闭程序。你会发现你的机器变慢了,同时按下键盘上的Ctrl + Alt + Delete键,启动Windows的任务管理器,切换到“进程”选项卡,单击“CPU”项进行排序,你会发现WinMain.exe的CPU占用率接近100,难怪机器“变慢了”。那么这是什么原因呢?实际上这个问题的答案在MSDN中就可以找到,并且就在GetMessage函数的说明文档中。不少初学者在遇到问题时,首先是头脑一片空白,接着就去找人求助,这种思想用在程序开发的学习中,没有什么好处。笔者经常遇到学员问问题,结果有不少问题的答案在MSDN关于某个函数的解释中就可看到(由于显示器的限制,有的答案需要滚动窗口才能看到 J)。所以在这里,笔者也建议读者遇到问题一定要记得查看MSDN,学会使用MSDN并从中汲取知识,将使你受用无穷。        回到正题,在前面介绍GetMessage函数时,曾说过如果hWnd参数是无效的窗口句柄或lpMsg参数是无效的指针时,GetMessage函数将返回-1。当我们关闭窗口时,调用了DestroyWindow来销毁窗口,由于窗口被销毁了,窗口的句柄当然也就是无效的句柄了,那么GetMessage将返回-1。在C/C++语言中,非0即为真,由于窗口被销毁,句柄变为无效,GetMessage总是返回-1,循环条件总是为真,于是形成了一个死循环,机器当然就“变慢了”。J        在MSDN关于GetMessage函数的说明文档中给出了下面的代码:        http://msdn2.microsoft.com/en-us/library/ms644936.aspx( 本文出处: http://www.d-programming-language-china.org )        QUOTE:                                BOOL bRet;                while( (bRet = GetMessage( &msg, hWnd, 0, 0 )) != 0)                {                    if (bRet == -1)                    {                        // handle the error and possibly exit                    }                    else                    {                        TranslateMessage(&msg);                        DispatchMessage(&msg);                    }                }                针对我们这个问题,可以修改上述代码如下:        QUOTE:                                …                HWND hwnd;                hwnd=CreateWindow(…);                …                MSG msg;                BOOL bRet;                while( (bRet = GetMessage( &msg, hwnd, 0, 0 )) != 0)                {                    if (bRet == -1)                    {                        // handle the error and possibly exit                        return -1;                    }                    else                    {                        TranslateMessage(&msg);                        DispatchMessage(&msg);                    }                }                …                D语言论坛 http://www.d-programming-language-china.org 按:        上面孙鑫确实讲得很细致。很多人没有看msdn的习惯,往往会忽略这点。yidabu也实验过了,窗体虽然销毁了,程序却没有退出,陷入死循环,占用CPU近100%。下面是D语言版本代码:        [Copy to clipboard] [ - ]CODE:                                int nRet;                while ( (nRet = GetMessage(&msg, hwnd, 0,0)) !=0 )                {                    if (nRet==-1)                    {                        return -1;                    }                    else                    {                        TranslateMessage(&msg);                        DispatchMessage(&msg);                    }                }                读者可以再次运行修改后的程序,看看运行的结果。        现在全部D语言代码是这样:        [Copy to clipboard] [ - ]CODE:                                import std.utf;        //for toUTF16z                import win32.api;        //for windows api                import std.stdio;        //for writefln                                extern(C) void gc_init();                extern(C) void gc_term();                extern(C) void _minit();                extern(C) void _moduleCtor();                extern(C) void _moduleDtor();                extern(C) void _moduleUnitTests();                                //TextOut函数                pragma(lib,"gdi32.lib");                                const char[] ClassName = "http://www.d-programming-language-china.org";                                extern(Windows)                int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow)                {                    int result;                    gc_init();                    _minit();                    try                    {                        _moduleCtor();                        _moduleUnitTests();                                        result = myWinMain(hInstance,hPrevInstance,lpCmdLine,nCmdShow);                                        _moduleDtor();                    }                    catch(Exception e)                    {                        printf("catch %.*s\n",e.msg);                        result = 0;                    }                    gc_term();                    return result;                }                                int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow)                {                    WNDCLASSEX wc;                    MSG msg;                    HWND hWnd;                                    wc.cbSize = WNDCLASSEX.sizeof;                    wc.style = CS_HREDRAW | CS_VREDRAW ;                    wc.lpfnWndProc = &WindowProc;                    wc.cbClsExtra = 0;                    wc.cbWndExtra = 0;                    wc.hInstance = hInstance;                    //bbs.d-programming-language-china.org注: D语言标准库的windows.d主要服务于ascii字符集的windows api,IDI_APPLICATION被定义为CHAR*,所以这里要转换成wchar*                    //如果IDI_APPLICATION来定义是CHAR,就可以用toUTF16z来转换                    wc.hIcon = LoadIcon (cast(HINSTANCE)null,cast(wchar*)IDI_APPLICATION);                    wc.hIcon = LoadIcon (hInstance,toUTF16z("IDI_MYICON"));                    wc.hCursor = LoadCursor(cast(HINSTANCE)null,cast(wchar*)IDC_ARROW);                    wc.hbrBackground = cast(HBRUSH)(COLOR_WINDOW+1);                    wc.lpszMenuName = null;                    //转换类名到以0结尾的宽字符集                    wc.lpszClassName = toUTF16z(ClassName);                    wc.hIconSm = LoadIcon(hInstance,std.utf.toUTF16z("IDI_MYICON"));                                    if ( !RegisterClassEx (&wc) )                        return 0;                                    hWnd = CreateWindowEx(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE | WS_EX_TOPMOST,                        toUTF16z(ClassName),                        std.utf.toUTF16z("D语言论坛 http://www.d-programming-language-china.org "),                        WS_OVERLAPPEDWINDOW,                        CW_USEDEFAULT,CW_USEDEFAULT,800,600,                        HWND_DESKTOP,                        cast(HMENU) null,                        hInstance,                        null);                                    if (hWnd == null)                    {                        MessageBoxEx(null,toUTF16z("欢迎来到 http://bbs.d-programming-language-china.org "),toUTF16z("error"),MB_ICONERROR | MB_HELP,0);                        return -2;                    }                    //显示和更新窗体                    ShowWindow(hWnd, SW_SHOWNORMAL);                    UpdateWindow(hWnd);                                                    int nRet;        //防止GetMessage=-1时陷入死循环                    while ( (nRet = GetMessage(&msg, cast(HWND)null, 0, 0)) != 0 )                    {                        if (nRet == -1 )                        {                            return -1;                        }                        else                        {                            TranslateMessage(&msg);                            DispatchMessage(&msg);                        }                    }                    return msg.wParam;                }                                                extern(Windows)                LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)                {                                    switch (uMsg)                    {                        case WM_CHAR:                            writefln("你按了键盘键 %d",wParam);                            break;                        case WM_LBUTTONDOWN:                            HDC hDc;                            hDc = GetDC(hwnd);                            wchar[] s = "你左键单击了";                            //用TextOut函数,必须加上gid32.lib库编译                            TextOut(hDc,50,50, s.ptr, s.length);                            ReleaseDC(hwnd,hDc);                            break;                        case WM_PAINT:                            HDC hDc;                            PAINTSTRUCT ps;                            hDc = BeginPaint(hwnd, &ps);                            wchar[] s = "你现在还好吗,D语言学得还好吧 http://www.d-programming-language-china.org";                            TextOut(hDc,100,200, s.ptr, s.length);                            EndPaint(hwnd,&ps);                            break;                        case WM_CLOSE:                            if ( IDYES== MessageBoxEx(hwnd, toUTF16z("真的要退出吗?"), toUTF16z("请选择"), MB_YESNO,0) )                                DestroyWindow(hwnd);                            break;                        case WM_DESTROY:                            PostQuitMessage(0);                            break;                        default:                            return DefWindowProc(hwnd, uMsg, wParam, lParam);                    }                    return 0;                }                至此,我们完整建立了一个windows GUI应用程序。建议上面所有的代码都手动输入而不是copy paste,以加深理解。理解了程序流程,windows api参数的意义,api函数的参数也就记住了。( lastupdate:20070510 最新文章请访问http://www.d-programming-language-china.org )关于一大步成功社区:yidabu提倡在交流中学习,在分享中提高收集感兴趣的知识,写下心得,通过网络与别人一起分享理解一点就实践一步,收获什么就分享什么,成功就是这样一点点一步步累积起来的网络只是一个工具,只有自己身心提高才是实实在在的。d-programming-language-china.org为大家提供一个学习交流各种知识的平台
页: [1]
查看完整版本: D语言GUI入门6 GetMessage消息循环的错误分析