11.2.1 WinMain()函数(2)
如果需要两个或多个选项,那么可以使用按位或运算符 | 组合这些常量,从而产生一个复合值。例如:
- WindowClass.style = CS_HREDRAW | CS_VREDRAW;
选项CS_HREDRAW告诉Windows,如果窗口的水平宽度改变,则重画该窗口;而CS_VREDRAW指出,如果窗口的垂直高度改变,那么重画相应的窗口。在前面这条语句中,我们选择在这两种情况下都重画窗口。因此,只要用户更改了窗口的宽度或高度,Windows就给程序发送一条指出应该重画窗口的消息。每种可能的窗口样式选项都是通过将32位字中独特的某个位设置为1而定义的,这就是要使用按位或运算符组合它们的原因。这些表示某种特定样式的位通常称为标志。标志不仅在Windows中,而且在C++(www.cppentry.com)中也使用得非常频繁,因为它们是表示并处理非有即无特征或非真即假参数的有效方法。
成员lpfnWndProc存储着指向程序中处理消息的函数(被处理的消息属于创建的窗口)的指针。该成员名称的前缀表明这是一个指向函数的long指针。如果我们也像大多数人那样调用WindowProc()函数来处理应用程序的消息,那么应当用下面这条语句初始化该成员:
- WindowClass.lpfnWndProc = WindowProc;
接下来两个成员cbClsExtra和cbWndExtra允许我们请求Windows在内部为特别用途提供额外空间。例如,当需要关联其他数据与窗口的每个实例,以参与各个窗口实例的消息处理过程时。通常不需要分配额外的空间,这种情况下必须将cbClsExtra和cbWndExtra成员设置为0。
hInstance成员容纳当前应用程序实例的句柄,因此应该将该成员设置为Windows传递给WinMain()函数的hInstance值。
- WindowClass.hInstance = hInstance;
成员hIcon、hCursor和hbrBackground都是句柄,它们依次引用如下对象:
最小化时的应用程序
窗口使用的光标
窗口客户区的背景色
如前所述,句柄只不过是用作表示某种事物的32位整数ID,当以64位模式编译时则表示64位整数ID。这3个成员应当使用Windows API函数设置。例如:
- WindowClass.hIcon = LoadIcon(0, IDI_APPLICATION);
- WindowClass.hCursor = LoadCursor(0, IDC_ARROW);
- WindowClass.hbrBackground = static_cast<HBRUSH>(GetStockObject(GRAY_BRUSH));
这3次函数调用将这3个成员设置为标准的Windows值。图标是Windows提供的默认图标,光标是大多数Windows应用程序使用的标准箭头光标。画笔是用来填充某块区域(这里是窗口的工作区)的Windows对象。函数GetStockObject()返回所有原料对象的泛型类型,因此需要将其强制转换为HBRUSH类型。在上面的示例中,该函数返回的是标准灰色画笔的句柄,因此将窗口的背景色设置为灰色。该函数也可以用来为窗口获得其他标准对象,如字体。也可以将hIcon和hCursor成员设置为空,那样Windows将提供默认的图标和光标。如果将hbrBackground设置为空,则该程序将等待窗口背景的绘制,而只在必要时Windows才将绘制消息发送给应用程序。
lpszMenuName成员应当设置为定义窗口菜单的资源的名称;如果该窗口没有菜单,则应当将其设置为NULL:
- WindowClass. lpszMenuName = NULL;
后面将在使用AppWizard时介绍菜单资源的创建和使用。
该struct的lpszClassName成员存储着为标识该特定的窗口类而提供的名称。通常,使用应用程序的名称为该成员赋值。需要记住该名称,因为在创建窗口时将再次需要它。该成员通常是用下面的语句设置的:
- static LPCTSTR szAppName = _T("OFWin"); // Define window class name
- WindowClass.lpszClassName = szAppName; // Set class name
此处使用tchar.h头文件中的_T()宏定义szAppName。如果为该应用程序定义UNICODE,则将LPCTSTR类型定义为const wchar_t *,反之则定义为const char*。_T()宏会自动创建正确类型的字符串。
最后一个成员是hIconSm,它标识某个与该窗口类相联系的小图标。如果将该成员设置为空,则Windows将搜索与hIcon成员相关的小图标并使用。
2. 创建程序窗口
将WNDCLASSEX结构的所有成员都设置为所需的值后,下一步是把相关情况告诉Windows。可以使用Windows API函数RegisterClassEx()来做这件事。假定WNDCLASSEX结构对象是WindowClass,则相应的语句如下所示:
- RegisterClassEx(&WindowClass);
很简单,不是吗?只需要给RegisterClassEx()函数传递该struct的地址,Windows就会提取并记录所有结构成员的设定值。该过程称为注册窗口类。再次提醒一下,这里的术语"类"是在"分类"的意义上使用的,与C++(www.cppentry.com)中"类"的概念不同,因此不要混淆两者。应用程序的每个实例都必须确保注册自己需要的窗口类。