Windows程序设计04:注册窗口类以及创建窗口

  在上一篇博文《Windows程序设计03:创建窗口类》(http://www.cnblogs.com/menlsh/archive/2013/01/26/2878162.html)中,我们提到创建一个应用程序窗口需要五个步骤,并实现了第一个步骤:创建窗口类。

  在本篇博文中,将继续介绍第二步和第三步的实现方法,调用RegisterClass函数注册窗口类和调用CreateWindow函数创建窗口。

1窗口类的注册

  当我们创建好了窗口类之后,为了能够使用该窗口类,就必须先注册该窗口类。注册窗口类是通过调用RegisterClass函数来实现的。

  在WinUser.h头文件中定义了RegisterClass函数,其函数原型如下:

 1   WINUSERAPI
 2   ATOM
 3   WINAPI
 4   RegisterClassA(
 5       __in CONST WNDCLASSA *lpWndClass);
 6   WINUSERAPI
 7   ATOM
 8   WINAPI
 9   RegisterClassW(
10       __in CONST WNDCLASSW *lpWndClass);
11   #ifdef UNICODE
12   #define RegisterClass  RegisterClassW
13   #else
14   #define RegisterClass  RegisterClassA
15   #endif // !UNICODE

  可以看出该函数的唯一参数是指向窗口类WNDCLASS的指针。实际上,系统存在两种不同的用于注册窗口类的函数:RegisterClassA和RegisterClassW,它们的参数则分别是指向上述定义中的WNDCLASSA的指针和WNDCLASSW的指针。程序利用哪个函数注册窗口类决定着传递给窗口的消息是包含ASCII文本还是UNICODE文本。

  当我们定义了UNICODE标识符时,程序显然会调用RegisterClassW函数来完成窗口类的注册。在Windows NT下运行程序时,这是没有问题的。但是在Windows98下运行程序时,RegisterClassW函数实际上并没有实现,而且会返回零值表示出现了错误。在这种情况下,应该通知用户应用程序发生错误并终止程序。所以可以参照如下方法使用RegisterClass函数注册窗口类。

1   if(!RegisterClass(&wndclass))
2   {
3       MessageBox(NULL, TEXT("该应用程序只能运行在Windows NT上!"), szAppName, MB_ICONERROR);
4       return 0;
5   }

  可以看出,以上代码添加了容错处理,当在程序中定义了UNICODE标识符,而用户又是在Windows98下运行该程序的,就会得到一个错误的提示框“该应用程序只能运行在Windows NT上!”,并终止程序的运行。

  当然,这种情况是很难发生的了,因为很显然,现在的Windows操作系统绝大多数都是Windows NT了,从图1就可以清楚的看出这一点了。

图1 Windows家族

  不过,出于对应用程序的健壮性方面的考虑,增加这样的容错处理还是很有必要的。

 

2窗口的创建

  由于窗口类只是定义了窗口的一般特征,而许多与窗口有关的细节信息则可以在创建窗口时定义。

  创建窗口是通过调用CreateWindow函数来实现的。在WinUser.h头文件中定义了CreateWindow的函数原型如下:

 1   #define CreateWindowA(lpClassName, lpWindowName, dwStyle, x, y,\
 2   nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)\
 3   CreateWindowExA(0L, lpClassName, lpWindowName, dwStyle, x, y,\
 4   nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)
 5   #define CreateWindowW(lpClassName, lpWindowName, dwStyle, x, y,\
 6   nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)\
 7   CreateWindowExW(0L, lpClassName, lpWindowName, dwStyle, x, y,\
 8   nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)
 9   #ifdef UNICODE
10   #define CreateWindow  CreateWindowW
11   #else
12   #define CreateWindow  CreateWindowA
13   #endif // !UNICODE

  可以看出,CreateWindow函数总共有11项参数,下面对这些参数做个简单的介绍,这也是使用CreateWindow函数的前提。

2.1窗口类名称

  CreateWindow函数的第一个参数lpClassName指定了该窗口是基于哪个窗口类创建的。可见,我们所要创建的窗口正是通过这种方式与之前创建和注册的窗口类建立起了联系。

2.2窗口标题

  CreateWindow函数的第二个参数lpWindowName指定了该窗口的标题,当应用程序运行起来之后,该标题将显示在应用程序的窗口左上角(默认情况下)。

2.3窗口风格

  CreateWindow函数的第三个参数dwStyle指定了窗口的风格。在WinUser.h头文件中定义了窗口风格如下:

View Code
 1   /*
 2    * Window Styles
 3    */
 4   #define WS_OVERLAPPED       0x00000000L
 5   #define WS_POPUP            0x80000000L
 6   #define WS_CHILD            0x40000000L
 7   #define WS_MINIMIZE         0x20000000L
 8   #define WS_VISIBLE          0x10000000L
 9   #define WS_DISABLED         0x08000000L
10   #define WS_CLIPSIBLINGS     0x04000000L
11   #define WS_CLIPCHILDREN     0x02000000L
12   #define WS_MAXIMIZE         0x01000000L
13   #define WS_CAPTION          0x00C00000L     /* WS_BORDER | WS_DLGFRAME  */
14   #define WS_BORDER           0x00800000L
15   #define WS_DLGFRAME         0x00400000L
16   #define WS_VSCROLL          0x00200000L
17   #define WS_HSCROLL          0x00100000L
18   #define WS_SYSMENU          0x00080000L
19   #define WS_THICKFRAME       0x00040000L
20   #define WS_GROUP            0x00020000L
21   #define WS_TABSTOP          0x00010000L
22   
23   #define WS_MINIMIZEBOX      0x00020000L
24   #define WS_MAXIMIZEBOX      0x00010000L
25 
26   #define WS_TILED            WS_OVERLAPPED
27   #define WS_ICONIC           WS_MINIMIZE
28   #define WS_SIZEBOX          WS_THICKFRAME
29   #define WS_TILEDWINDOW      WS_OVERLAPPEDWINDOW

  这些宏定义标识符都代表着什么式样的窗口风格呢?可以参考百度百科CreateWindow(http://baike.baidu.com/view/1001690.htm)。其中,比较常用的窗口风格有以下一些:

  单边框的窗口WS_BORDER

  带标题框的窗口WS_CAPTION

  带对话框边框的窗口WS_DLGFRAME

  初始状态为禁止的窗口WS_DISABLED

  初始状态为最小化的窗口WS_ICONIC

  初始状态为最大化的窗口WS_MAXIMIZE

  带有水平滚动条的窗口WS_HSCROLL

  带有垂直滚动条的窗口WS_VSCROLL

  带有最大化按钮的窗口WS_MAXIMIZEBOX

  带有最小化按钮的窗口WS_MINIMIZEBOX

  标题条上带有窗口菜单的窗口WS_SYSMENU

  如果需要使创建的窗口同时具有上述的几种窗口风格,可以通过使用按位或运算(|)来实现。在WinUser.h头文件中同样定义了一些窗口风格的组合,可以方便我们直接使用,具体如下:

View Code
 1   /*
 2    * Common Window Styles
 3    */
 4   #define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED     | \
 5                                WS_CAPTION        | \
 6                                WS_SYSMENU        | \
 7                                WS_THICKFRAME     | \
 8                                WS_MINIMIZEBOX    | \
 9                                WS_MAXIMIZEBOX)
10   
11   #define WS_POPUPWINDOW      (WS_POPUP          | \
12                                WS_BORDER         | \
13                                WS_SYSMENU)
14   
15   #define WS_CHILDWINDOW      (WS_CHILD)

  可以看出,WS_OVERLAPPEDWINDOW同时组合了WS_OVERLAPPED、WS_CAPTION、WS_SYSMENU、WS_THICKFRAME、WS_MINIMIZEBOX、WS_MAXIMIZEBOX六种窗口风格。而WS_POPUPWINDOW则同时组合了WS_POPUP、WS_BORDER、WS_SYSMENU三种窗口风格。

2.4初始x、y坐标

  CreateWindow函数的第四个参数x和第五个参数y指定了窗口左上角相对于屏幕左上角的初始位置。通常可以将其设为默认值CW_USEDEFAULT,那么Windows会将连续新建的窗口的左上角位置沿水平方向和垂直方向分别作步长为1的偏移。

2.5初始x、y方向尺寸

  CreateWindow函数的第六个参数nWidth和第七个参数nHeight指定了窗口的初始化宽度和高度。通常可以将其设为默认值CW_USEDEFAULT,表明希望Windows将窗口的尺寸取为默认值。

2.6父窗口句柄

  CreateWindow函数的第八个参数hWndParent表示应用程序的父窗口句柄。应用程序窗口总是位于桌面的前方,但不必为了调用CreateWindow函数而去设法获取桌面窗口的句柄。可以将我们新建的应用程序窗口看作是顶级窗口,直接将hWndParent参数值置为NULL即可。通常,当两个窗口之间存在父子关系时,子窗口总是位于父窗口的前面。

2.7窗口菜单句柄

  CreateWindow函数的第九个参数hMenu表示应用程序窗口的菜单句柄。如果应用程序窗口没有菜单栏,则直接将该参数设置为NULL即可。

2.8程序实例句柄

  CreateWindow函数的第十个参数hInstance表示应用程序的实例句柄。该参数可以直接被设置为WinMain函数的第一个传入参数即可。

2.9创建参数

  CreateWindow函数的最后一个参数lpParam表示创建参数,通常设置为NULL,也可以将该参数指向某些数据,以便在后续的程序中加以引用(这个参数具体怎么使用现在还不清楚,有待以后继续学习)。

2.10返回值

  CreateWindow函数的返回值为一个指向所创建窗口的句柄。Windows系统中,每一个窗口都有一个句柄,在程序中可以使用句柄来对窗口进行调用。很多Windows函数都以窗口句柄作为输入参数,以便Windows获知该函数是要对哪一个窗口进行操作。如果一个程序创建了多个窗口,则每个窗口都应该具有不同的窗口句柄,以方便进行区分和调用。

  清楚了CreateWindow函数的参数以及返回值的使用方法,便可以实际编写CreateWindow函数了,下面的代码给出了一个简单的示例:

 1   HWND hwnd;            //窗口句柄
 2   hwnd = CreateWindow(szAppName,    //窗口类名称
 3       TEXT("博客园-依旧淡然"),        //窗口标题
 4       WS_OVERLAPPEDWINDOW,          //窗口风格
 5       CW_USEDEFAULT,                //初始x坐标
 6       CW_USEDEFAULT,                //初始y坐标
 7       CW_USEDEFAULT,                //初始x方向尺寸
 8       CW_USEDEFAULT,                //初始y方向尺寸
 9       NULL,                //父窗口句柄
10       NULL,                //窗口菜单句柄
11       hInstance,           //程序实例句柄
12       NULL);               //创建参数

 

相关资料:

关于RegisterClass的注册位置

http://blog.csdn.net/testcs_dn/article/details/7634711

 

作者:依旧淡然
邮箱:menlsh@163.com
本文版权归作者所有,未经作者同意,严禁转载及用作商业传播,否则将追究法律责任。
原文地址:https://www.cnblogs.com/menlsh/p/2890256.html