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

查看完整版本: 白手起家Win32SDK应用程序5 利用已注册的窗口类创建一个窗口

yidabu 2007-5-6 06:28

白手起家Win32SDK应用程序5 利用已注册的窗口类创建一个窗口

白手起家Win32SDK应用程序5 利用已注册的窗口类创建一个窗口知识若不分享 实在没有意义 http://www.d-programming-language-china.org 20070505点击下面网址查看原文:http://www.d-programming-language-china.org        by:        白云小飞        D语言论坛 http://www.d-programming-language-china.org 增加D语言实例教程用CreateWindowEx函数来创建窗口        1 参数及返回值说明:        上篇中我们完成了向Windows系统进行窗口的“申请”工作(即注册一个窗口类)。本篇就是要用这个窗口类来创建一个窗口。        下面这个API函数就是专门用来创建一个窗口的:        QUOTE:                                HWND    WINAPI    CreateWindowEx(                                    DWORD dwExStyle,                                    LPCSTR lpClassName,                                    LPCSTR lpWindowName,                                    DWORD dwStyle,                                    int X,    int Y,                                    int nWidth,    int nHeight,                                    HWND hWndParent ,                                    HMENU hMenu,                                    HINSTANCE hInstance,                                    LPVOID lpParam);                这是一个拥有一大串参数的函数。(唉!我又要一个个地介绍了。)        DWORD dwExStyle:这是用来指定扩展样式标志,绝大多数情况,我们只要指定为NULL,所以我不想多说。        LPCSTR lpClassName:我们要用前篇中注册的窗口类来完成创建窗口,所以lpCassName所指字符串值要与前篇中注册时所用的窗口类名值相同(即wndclass.lpszClassName的值)。本例中就是"WINCLASS1"字符串值。        LPCSTR lpWindowName:此指针所指的字符串会显示在标题栏上(即标题栏文字)。        DWORD dwStyle:这是用来指定窗口外观类型的。以下是它可能的值(部分):        表 dwStyle可以设置的值        QUOTE:                                WS_POPUP    弹出式窗口                WS_OVERLAPPED    带有标题栏和边界的重叠式窗口。                WS_OVERLAPPEDWINDOW    具有WS_OVERLAPPED、WS_CAPTION、WS_SYSMENU、WS_THICK、FRAME、WS_MINIMIZEBOX、WS_MAXIMIZEOBX样式的重叠式窗口                WS_VISIBLE    创建之后就立即显示窗口                ……    (还有很多其它值呢!请自行参看其它参考书)                还记得上篇中注册窗口类时窗口类结构体成员中有一项:        QUOTE:                                wndclass.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC | CS_DBLCLKS;                你可不要搞糊涂啦!wndclass.style所指的是针对窗口内在特性的类型,而CreateWindowEx参数中的dwStyle窗口类型是窗口外观的类型。        int X,        int Y,:这是指定相对于桌面的窗口左上角位置(坐标)。        int nWidth,        int nHeight,:指定窗口的宽度与高度。        (上面这四个参数应该好理解吧!)        HWND hWndParent :父窗口句柄,不明白它的作用吧?现在你只要赋值为NULL就可。        HMENU hMenu:你还记得吗?我们在前篇的窗口类结构体变量赋值中有这么一句: wndclass.lpszMenuName =NULL; 它是可以为窗口指定一个菜单的。        CreateWindowEx函数的这个hMenu菜单句柄(这又是一个句柄噢!)也可以为窗口指定一个菜单,它将代替前面的设置。不过我们现在暂时不要菜单,所以也赋值为NULL。        HINSTANCE hInstance:要与wndclass.hInstance值相同,本应用程序的句柄代入这里。        LPVOID lpParam:高级特征,现在我们只要设置为NULL就行。         (噢,好不容易介绍完这些参数了。)        返回值:如果窗口成功创建出来,则返回这个窗口的句柄,如果创建不成功,则返回0值。( 本文出处: http://www.d-programming-language-china.org )        2 具体实现代码:        下面我就给出具体的创建窗口代码:        QUOTE:                                hWnd=CreateWindowEx(NULL,”WINCLASS1”,                            "这是我的第一个窗口",                            WS_OVERLAPPEDWINDOW ,                            0, 0,                            400,400,                            NULL,                            NULL,                            hinstance,                            NULL );                if (!hWnd)    //这里应该判断是否创建成功                    return 0;                D语言论坛 http://www.d-programming-language-china.org 按:        D语言版本是这样的:        [Copy to clipboard] [ - ]CODE:                                    hwnd = CreateWindowEx(0, std.string.toStringz(ClassName), toMBSz("一大步成功社区 http://bbs.d-programming-language-china.org "), WS_OVERLAPPEDWINDOW,                    CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,                    HWND_DESKTOP, null, hInstance, null);                    if (hwnd == null)                    {                    writefln ("create window failed");                    return 0;                    }                3 调试及结果:        程序写到这里似乎窗口就可以创建出来了。那就让我们调试调试?OK,Let’s go!请在        QUOTE:                                if (!hWnd)                return 0;    //设断点                中的return 0处设置一个断点。看看你的程序会不会执行到这个return 0;当创建不成功,则hWnd==0,程序会执行到这个return 0。反之,程序成功地创建了这个窗口。        (哦!我并不知道你是否会用VC6来设置断点并进行调试。        只要光标放在return 0 处按F9就可以设置此处的断点。如果你再按F9一次,则会取消这个断点。        设置完断点后,按F5编译运行这个程序试试。)        矣?不太对劲啊,调试中我们发现hWnd值为0,即说明窗口并没有创建成功。        (在这里请再按F5,可以从断点处继续运行,程序结束了。)        原因是?……( 本文出处: http://www.d-programming-language-china.org )CreateWindowEx的一个条件:调用缺省窗口过程DefWindowProc函数        1 在WinProc中增加调用DefWindowProc函数        原因是:我们还要在这个窗口的自定义窗口过程WinProc中增加如下代码(黑体字部分):( 本文出处: http://www.d-programming-language-china.org )        QUOTE:                                LRESULT CALLBACK WinProc(HWND hwnd,                                     UINT msg,                                     WPARAM wparam,                                     LPARAM lparam)                {                    //……                    return DefWindowProc(hwnd, msg, wparam, lparam);                }                真让我疑惑啊!        CreateWindowEx函数创建一个窗口与这个DefWindowProc函数什么关系。        又为什么要把这个函数写在WinProc回调函数里呢?        首先,看DefWindowProc在Winuser.h中的原型定义:        QUOTE:                                LRESULT CALLBACK DefWindowProc(                                    HWND hWnd,                                    UINT Msg,                                    WPARAM wParam,                                    LPARAM lParam);                在D语言标准库的windows.d是这样定义的:        [Copy to clipboard] [ - ]CODE:                                export LRESULT DefWindowProcA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);                你有没有看出,它的函数格式与我们自定义WinProc回调函数的格式完全一样的?只不过DefWindowProc是Window系统提供给我们的一个API函数。        那么在整个调用CreateWindowEx函数中到底发生了什么事啊?让我来告诉你吧!        2 原因何在        从我们的自定义窗口过程WinProc函数说起:        当应用程序运行时,用户对该程序窗口的操作,都会自动产生一系列的消息。比如创建一个窗口会产生WM_CREATE消息;移动窗口会产生WM_MOVE消息;按下键盘时会产生WM_KEYDOWN消息;关闭窗口时会产生WM_CLOSE消息等等。也就是说,在执行CreateWindowEx函数期间会产生若干个消息(先别管都是些什么消息)。        Window系统会将这些由一系列的消息添加到该进程的消息队例中(噢,你可要有一点想象力哟!)。在CreateWindowEx函数中同时会调用我们写的WinProc函数若干次,并把消息的各项信息通过WinPro函数参数传递进来。(我再说一遍:你得有点想象力啊)        说白了,就是在执行CreateWindowEx创建窗口过程中会引发对WinProc函数的多次调用。        创建窗口过程中要用到缺省窗口过程函数DefWindowProc:        前面说过,在执行CreateWindowEx创建窗口过程中会引发对WinProc函数的多次调用。嘿嘿,这可不是可有可无的调用啊!在这里,我们要让缺省窗口过程DefWindowProc来完成一些默认的消息处理操作。你不必知道它做了什么事,只要把这一切消息都“扔”给它就行啦!只有让 DefWindowProc函数完成必要的消息处理,CreateWindowEx函数才能全程地完成窗口的创建(否则,嘿嘿!窗口的创建必将失败。)。所以我们添加了调用DefWindowProc的代码。(DefWindowProc的返回值返回的是对消息处理的结果,我们再将它作为WinProc的返回值。)        3 本篇增加的全部代码        最后,本篇中所增加的全部代码总括如下(黑体部分):( 本文出处: http://www.d-programming-language-china.org )        QUOTE:                                LRESULT CALLBACK WinProc(HWND hwnd,                                     UINT msg,                                     WPARAM wparam,                                     LPARAM lparam)                {                    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;                        //……                    return 0;                }                D语言论坛 http://www.d-programming-language-china.org 按:        D语言的版本如下:        [Copy to clipboard] [ - ]CODE:                                extern (Windows):                LRESULT WinProc(HWND hwnd,                                     UINT msg,                                     WPARAM wparam,                                     LPARAM lparam)                {                    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,std.string.toStringz(WND_CLS_NAME),                            std.windows.charset.toMBSz("一大步成功社区 http://bbs.d-programming-language-china.org "),                            WS_OVERLAPPEDWINDOW|WS_VISIBLE ,                            CW_USEDEFAULT, 0,                            400,400,                            null,                            null,                            hinstance,                            null );                    if (hWnd== null)                        return 0;                        //……                    return 0;                }                4 具体分析        现在现具体地分析一下调用CreateWindowEx函数的过程:        1. 首先从调用CreateWindowEx开始,程序进入了CreateWindowEx函数体内的代码(就是Window系统的代码)。        2. 在此期间,CreateWindowEx会产生若干个消息(我们不用管是什么消息)。        3. 每当一个消息产生后,CreateWindowEx会自动调用我们自己写的WinProc函数,将消息信息传递进来。        4. 这些消息我们自己不作处理而是直接在WinProc调用缺省窗口过程DefWindowProc来作缺省处理(你不用去管DefWindowProc做了什么),并返回处理结果。        5. 每次WinProc结束后回到CreateWindowEx代码处,CreateWindowEx会根据返回值果进行判断,完成最终的窗口创建。        怪不得嘛!没有调用DefWindowProc这个函数,CreateWindowEx无法完成全部的窗口创建过程,所以最终创建窗口失败了。        5 再调试        很好!现在再按前面讲的调试步骤试试看。        QUOTE:                                if (!hWnd)                    return 0;    //这里设断点                程序不再执行这个return 0;了。太好啦!这说明窗口创建成功了。当然并没把窗口显示出来,所以你只看到程序停都不停一下就马上就结束了。        关于窗口的显示我就留到下一篇了。( lastupdate:20070506 最新文章请访问http://www.d-programming-language-china.org )关于一大步成功社区:yidabu提倡在交流中学习,在分享中提高收集感兴趣的知识,写下心得,通过网络与别人一起分享理解一点就实践一步,收获什么就分享什么,成功就是这样一点点一步步累积起来的网络只是一个工具,只有自己身心提高才是实实在在的。d-programming-language-china.org为大家提供一个学习交流各种知识的平台
页: [1]
查看完整版本: 白手起家Win32SDK应用程序5 利用已注册的窗口类创建一个窗口