在上一篇博文《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头文件中定义了窗口风格如下:
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头文件中同样定义了一些窗口风格的组合,可以方便我们直接使用,具体如下:
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