正文

《Win32SDK应用程序》第五篇 利用已注册的窗口类来创建一个窗口 2005-10-22 21:00:00

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

分享到:

第五篇 利用已注册的窗口类来创建一个窗口 白云小飞 一 用CreateWindowEx函数来创建窗口    上篇中我们完成了向Windows系统进行窗口的“申请”工作(即注册一个窗口类)。本篇就是要用这个窗口类来创建一个窗口。    下面这个API函数就是专门用来创建一个窗口的: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可以设置的值WS_POPUP             弹出式窗口WS_OVERLAPPED    带有标题栏和边界的重叠式窗口。WS_OVERLAPPEDWINDOW    具有WS_OVERLAPPED、WS_CAPTION、WS_SYSMENU、WS_THICK、FRAME、WS_MINIMIZEBOX、WS_MAXIMIZEOBX样式的重叠式窗口WS_VISIBLE    创建之后就立即显示窗口……    (还有很多其它值呢!请自行参看其它参考书)     还记得上篇中注册窗口类时窗口类结构体成员中有一项:     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值。    下面我就给出具体的创建窗口代码:    hWnd=CreateWindowEx(NULL,”WINCLASS1”,                "这是我的第一个窗口",                WS_OVERLAPPEDWINDOW ,                0, 0,                400,400,                NULL,                NULL,                hinstance,                NULL );    if (!hWnd)   //这里应该判断是否创建成功        return 0;    程序写到这里似乎窗口就可以创建出来了。那就让我们调试调试?OK,Let’s go!请在    if (!hWnd)    return 0;   //设断点    中的return 0处设置一个断点。看看你的程序会不会执行到这个return 0;当创建不成功,则hWnd==0,程序会执行到这个return 0。反之,程序成功地创建了这个窗口。    (哦!我并不知道你是否会用VC6来设置断点并进行调试。    只要光标放在return 0 处按F9就可以设置此处的断点。如果你再按F9一次,则会取消这个断点。    设置完断点后,按F5编译运行这个程序试试。)    矣?不太对劲啊,调试中我们发现hWnd值为0,即说明窗口并没有创建成功。    (在这里请再按F5,可以从断点处继续运行,程序结束了。)    原因是?…… 二 调用缺省窗口过程DefWindowProc函数    原因是:我们还要在这个窗口的自定义窗口过程WinProc中增加如下代码(黑体字部分):LRESULT CALLBACK WinProc(HWND hwnd,                         UINT msg,                         WPARAM wparam,                         LPARAM lparam){//……   return DefWindowProc(hwnd, msg, wparam, lparam);}    真让我疑惑啊!    CreateWindowEx函数创建一个窗口与这个DefWindowProc函数什么关系。    又为什么要把这个函数写在WinProc回调函数里呢?    首先,看DefWindowProc在Winuser.h中的原型定义:LRESULT CALLBACK DefWindowProc(                        HWND hWnd,                        UINT Msg,                        WPARAM wParam,                        LPARAM lParam);    你有没有看出,它的函数格式与我们自定义WinProc回调函数的格式一完全一样的?只不过DefWindowProc是Window系统提供给我们的一个API函数。    那么在整个调用CreateWindowEx函数中到底发生了什么事啊?让我来告诉你吧!    从我们的自定义窗口过程WinPro函数说起:    当应用程序运行时,用户对该程序窗口的操作,都会自动产生一系列的消息。比如创建一个窗口会产生WM_CREATE消息;移动窗口会产生WM_MOVE消息;按下键盘时会产生WM_KEYDOWN消息;关闭窗口时会产生WM_CLOSE消息等等。也就是说,在执行CreateWindowEx函数期间会产生若干个消息(先别管都是些什么消息)。    Window系统会将这些由一系列的消息添加到该进程的消息队例中(噢,你可要有一点想象力哟!)。在CreateWindowEx函数中同时会调用我们写的WinPro函数若干次,并把消息的各项信息通过WinPro函数参数传递进来。(我再说一遍:你得有点想象力啊)    说白了,就是在执行CreateWindowEx创建窗口过程中会引发对WinPro函数的多次调用。    创建窗口过程中要用到缺省窗口过程函数DefWindowProc:    前面说过,在执行CreateWindowEx创建窗口过程中会引发对WinPro函数的多次调用。嘿嘿,这可不是可有可无的调用啊!在这里,我们要让缺省窗口过程DefWindowProc来完成一些默认的消息处理操作。你不必知道它做了什么事,只要把这一切消息都“扔”给它就行啦!只有让 DefWindowProc函数完成必要的消息处理,CreateWindowEx函数才能全程地完成窗口的创建(否则,嘿嘿!窗口的创建必将失败。)。所以我们添加了调用DefWindowProc的代码。(DefWindowProc的返回值返回的是对消息处理的结果,我们再将它作为WinPro的返回值。)    最后,本篇中所增加的全部代码总括如下(黑体部分):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;}    现在现具体地分析一下调用CreateWindowEx函数的过程:    1. 首先从调用CreateWindowEx开始,程序进入了CreateWindowEx函数体内的代码(就是Window系统的代码)。    2. 在此期间,CreateWindowEx会产生若干个消息(我们不用管是什么消息)。    3. 每当一个消息产生后,CreateWindowEx会自动调用我们自己写的WinProc函数,将消息信息传递进来。    4. 这些消息我们自己不作处理而是直接在WinProc调用缺省窗口过程DefWindowProc来作缺省处理(你不用去管DefWindowProc做了什么),并返回处理结果。    5. 每次WinProc结束后回到CreateWindowEx代码处,CreateWindowEx会根据返回值果进行判断,完成最终的窗口创建。    怪不得嘛!没有调用DefWindowProc这个函数,CreateWindowEx无法完成全部的窗口创建过程,所以最终创建窗口失败了。    很好!现在再按前面讲的调试步骤试试看。    if (!hWnd)        return 0;   //这里设断点    程序不再执行这个return 0;了。太好啦!这说明窗口创建成功了。当然并没把窗口显示出来,所以你只看到程序停都不停一下就马上就结束了。    关于窗口的显示我就留到下一篇了。

阅读(6714) | 评论(1)


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

评论

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