窗口类(Window Class)概述

windows窗口编程(通常意义上的win32)有几个比较核心的概念:入口函数WinMain、窗口类Window Class、窗口过程、消息处理机制、通用控件。本文主要介绍窗口类的相关概念,包括:

  • 窗口类的类型;
  • 窗口类的注册及使用;
  • 窗口类的构成。

窗口类是基于进程的,每个应用程序在创建窗口之前必须注册窗口类(或者使用操作系统定义的窗口类),使用完成之后需要销毁(反注册)。

介绍窗口类的主要目的在于明确windows窗口编程的相关概念,掌握windows内部对于GUI处理的机制。如果你在用mfc或者其他界面框架,本文是没有必要阅读的。

一、窗口类的类型

windows下窗口类分为三种:

  • 系统窗口类
  • 应用程序全局窗口类
  • 应用程序局部窗口类

三者主要区别在于作用域、注册销毁的时刻及方式上。

1. 系统窗口类

顾名思义,系统窗口类是有操作系统注册的。一些系统窗口类是所有进程都可以访问的,一些系统窗口类是只能被操作系统内部使用的。对于系统窗口类,应用程序是不能销毁的。

操作系统在应用程序首次调用GUI函数时,为当前进程注册系统窗口类。也就是说每个独立的应用程序都会用于一份同样的系统窗口类注册。下面表格中给出了任意进程都可以使用的系统窗口类名称。

窗口类 描述信息
Button 按钮的窗口类名称。
ComboBox 组合框的窗口类名称。
Edit 编辑框控件的窗口类名称。
ListBox 列表框的窗口类名称。
MDIClient MDI子窗口的窗口类名称。
ScrollBar 滚动条的窗口类名称。
Static 静态控件的窗口类名称。

下表是仅由操作系统内部使用的窗口类名称。

窗口类 描述信息
ComboLBox
组合列表框的窗口类名称。

The class for the list box contained in a combo box.

DDEMLEvent
动态数据交换管理库(DDEML)事件的窗口类名称。

The class for Dynamic Data Exchange Management Library (DDEML) events.

Message The class for a message-only window.
#32768 菜单的窗口类名称。
#32769 桌面窗口的窗口类名称。
#32770 对话框的窗口类名称。
#32771 任务栏切换窗口的窗口类名称。
#32772 图标标题栏的窗口类名称。The class for icon titles.

2. 应用程序全局窗口类

应用程序全局窗口类指的是由可执行程序或者DLL注册的,可以被当前进程其他模块使用的窗口类。比如你在某个DLL中注册一个全局窗口类,应用程序可以通过加载该DLL之后就可以使用对应的窗口类。

全局窗口类在不使用时必须由用户自行销毁(使用 UnregisterClass)。

3. 应用程序局部窗口类

应用程序局部窗口类指的是由可执行程序或者DLL注册的,仅用于当前模块的窗口类。我们可以注册很多局部窗口类,但推荐的做法是仅注册一个窗口类,用于创建应用程序主窗口。

操作系统在应用程序退出时自动销毁局部窗口类,我们也可通过 UnregisterClass函数手动销毁局部窗口类。

二、窗口类的注册及使用

窗口类定义了windows下的窗口属性,包括窗口样式、图标、光标、菜单项、窗口过程等。要注册窗口类,首先需要填充WNDCLASS 、WNDCLASSEX结构,然后使用设置好的参数调用RegisterClassRegisterClassEx函数(二者主要区别在于RegisterClass函数不支持小图标设置,在通常使用中可以统一使用RegisterClassEx函数)。

如果需要注册应用程序全局窗口类,需要设置WNDCLASSEX结构的style属性为 CS_GLOBALCLASS;注册局部窗口类请勿指定 CS_GLOBALCLASS属性。

窗口类主要用于CreateWindowCreateWindowEx函数的调用(第一个参数lpClassName),原型如下:

HWND WINAPI CreateWindow(
  _In_opt_  LPCTSTR lpClassName,
  _In_opt_  LPCTSTR lpWindowName,
  _In_      DWORD dwStyle,
  _In_      int x,
  _In_      int y,
  _In_      int nWidth,
  _In_      int nHeight,
  _In_opt_  HWND hWndParent,
  _In_opt_  HMENU hMenu,
  _In_opt_  HINSTANCE hInstance,
  _In_opt_  LPVOID lpParam
);

HWND WINAPI CreateWindowEx(
  _In_      DWORD dwExStyle,
  _In_opt_  LPCTSTR lpClassName,
  _In_opt_  LPCTSTR lpWindowName,
  _In_      DWORD dwStyle,
  _In_      int x,
  _In_      int y,
  _In_      int nWidth,
  _In_      int nHeight,
  _In_opt_  HWND hWndParent,
  _In_opt_  HMENU hMenu,
  _In_opt_  HINSTANCE hInstance,
  _In_opt_  LPVOID lpParam
);

窗口类是按照字符串进行查找匹配的。

1. 系统如何查找窗口类

操作系统会维护一个按照三种类型分类的窗口类列表,在应用程序需要创建窗口的时候,按照下列顺序搜索定位窗口类:

  • 使用窗口类名称及当前模块实例句柄查找应用程序局部窗口类列表(注意当前模块实例句柄主要为了区分不同模块注册的同名窗口类);
  • 若局部窗口类列表中未找到,则继续查找应用程序全局窗口类列表;
  • 若全局窗口类列表中未找到,则超找系统窗口类列表。

所有的窗口创建都会遵循上面的查找顺序。因此这样也提供了重写系统窗口类的一种方法,在应用中注册和系统窗口类的同名的局部窗口类,这样即可以修改当前应用程序中替换某些系统窗口,同时不影响其他应用程序的系统窗口类使用。

2. 窗口类的归属

窗口类通常意义可以认为是属于注册该类的可执行程序或者DLL。操作系统使用调用RegisterClassEx函数的WNDCLASSEX结构的hInstance 判断窗口类的所有权。也就是说DLL在注册窗口类的时候必须使用DLL本身的句柄。

当动态加载的DLL卸载时,使用DLL注册窗口类的窗口可能还会存在。这就需要调用者保证DLL卸载之前,关闭所有引用DLL所注册窗口类的窗口,同时使用 UnregisterClass函数销毁窗口类。否则可能存在访问越界等情况。(因为DLL卸载之后,其过程函数地址是无效的。)

三、窗口类的构成

窗口类给出了使用该类的windows窗口的一些属性。主要参数设置位于WNDCLASSEX结构中。其定义如下:

typedef struct tagWNDCLASSEX {
  UINT      cbSize;
  UINT      style;
  WNDPROC   lpfnWndProc;
  int       cbClsExtra;
  int       cbWndExtra;
  HINSTANCE hInstance;
  HICON     hIcon;
  HCURSOR   hCursor;
  HBRUSH    hbrBackground;
  LPCTSTR   lpszMenuName;
  LPCTSTR   lpszClassName;
  HICON     hIconSm;
} WNDCLASSEX, *PWNDCLASSEX;

在实际使用时,系统仅要求提供类名称(lpszClassName)、回调函数地址(lpfnWndProc)、实例句柄(hInstance)三个参数,其他参数用于设置window窗口属性。下面逐一说明窗口类的元素构成:

类名称(字段:lpszClassName)

用于唯一标识窗口类。窗口类是进程相关的,使用时必须保证窗口类的类名称在当前进程中是唯一的。

另外由于类名称占用系统私有元表格(system‘s private atom table),注册时请保证类名尽可能短。

可以使用 GetClassName函数获取当前窗口的窗口类名称。

窗口过程地址(字段:lpfnWndProc)

系统用该地址回调windows所有的消息。具体看参考Window Procedures。原型必须符合下面定义:

LRESULT CALLBACK WindowProc(
  _In_  HWND hwnd,
  _In_  UINT uMsg,
  _In_  WPARAM wParam,
  _In_  LPARAM lParam
);

实例句柄(字段:hInstance

窗口类需要使用实例句柄来标识其归属的可执行程序或DLL。系统在启动可执行程序或DLL时都会给其设置实例句柄,用于管理各模块,该实例句柄可在可执行模块的入口函数中获取(比如在WinMain或DllMain中)。

类光标(字段:hCursor)

用于指定鼠标在客户区显示的样式。可使用 LoadCursor函数加载一个光标文件,用于设置该字段。

可使用 SetCursor函数设置光标属性。其他详细信息可参考Cursors

类图标(字段:hIcon和hIconSm

类图标是一张图片,用于标识特殊的窗口类。分为大图标和小图标。大图标用于窗口切换(ALT+Tab)以及大图标视图下的任务栏和桌面浏览器(explorer.exe)。小图标用于显示在标题栏、小图标视图下的任务栏和桌面浏览器。

图标实际大小可通过 GetSystemMetrics函数获取。设置字段SM_CXICONSM_CYICON可获取大图标的长宽,设置字段 SM_CXSMICONSM_CYSMICON可获取小图标的长宽。

类背景画刷(字段:hbrBackground

用于设置窗口客户区重绘的画刷,详细设置可参考WM_ERASEBKGND消息。使用可以创建自定义画刷,也可使用系统画刷(GetSysColorBrush)。

类菜单(字段:hMenu)

用于设置系统默认菜单。可使用菜单名称,也可以使用 MAKEINTRESOURCE 。详细设置建议参考Menus

窗口类样式(字段:style

指定窗口类创建的一些默认参数,可参考Window Class Styles

附加窗口类存储空间(字段:cbClsExtra

所有窗口共享的唯一的类存储空间,类似于c++中类的静态成员函数,操作系统默认存储在WNDCLASSEX后面,如果不需要,该字段必须设置为0。

附加类存储空间是分配在系统本地堆(local heap)中的,建议字段长度不要太大(不超过40个字节)。可使用 SetClassWordSetClassLong函数设置对应字段,使用GetClassWordGetClassLong函数获取相应参数。

很多经典的win32编程数据可能会提到这个字段,目前多数应用是不需要设置这个参数的。也不推荐使用。

附加窗口存储空间(字段:cbWndExtra

概念跟附件窗口类存储空间类似,只是附件窗口存储空间是按照每个窗口分配的,类似于c++中的成员变量,每个实例有一个。附件窗口存储空间一般用于存储窗口相关数据。

可使用 SetWindowLong和 GetWindowLong函数来获取、设置附件窗口存储空间中的数据。

四、总结

windows编程的核心在于消息处理机制,而窗口类作为一个独立的抽象单元,为我们提供了注册窗口类并创建的方式,有些内容是值得借鉴和学习的。虽然概念比较老,但是如果想深入了解win32内部的处理方式,还是需要在理解的基础上深化下。

windows窗口类的构成有很多参数,如果有一些默认参数无法确认,建议查看msdn上对应的内容,一般都会有描述的。

时间: 2025-01-19 14:31:46

窗口类(Window Class)概述的相关文章

Window 窗口类

窗口类 WNDCLASS 总结 总结为下面的几个问题: 1. 什么是窗口类 2. 窗口类的三种类型 3. 窗口类各字段含义 4. 窗口类的注册和注销 5. 如何使用窗口类,子类化.超类化是什么 下面分别描述: 1. 什么是窗口类? 窗口类定义了一系列属性,系统使用这些属性作为模板来创建出一个或多个 window (窗口). 每个窗口类都关联了一个窗口过程函数(window procedure), 由窗口类创建出的所有窗口(window), 都共享同一个窗口过程函数. 在进程中创建窗口之前必须先注

JavaScript之DOM-6 BOM概述 、Window对象(Window对象概述、窗口与对话框、定时器)

一.BOM 概述 BOM 概述 - DHTML 对象模型回顾 BOM 概述 - BOM: Browser Object Model,浏览器对象模型,用来访问和操纵浏览器窗口,使 JavaScript 有能力与浏览器"对话" - 通过使用 BOM,可移动窗口.更改状态栏文本.执行其他不与页面内容发生直接联系的操作 - 没有相关标准,但被广泛支持 BOM 模型 - BOM 模型主要包括如下对象 二.Window 对象概述 Window 对象概述 - window 对象表示浏览器中打开的窗口

4.win32注册窗口类和创建窗口

1.注册窗口类函数 (1)RegisterClass/RegisterClassEx ATOM RegisterClass(CONST WNDCLASS *lpWndClass); ATOM RegisterClassEx(CONST WNDCLASSEX *lpwcx); 注册成功后,返回一个非0数字标识,失败返回0. (2)窗口类的风格 CS_GLOBALCLASS - 应用程序全局窗口类 CS_BYTEALIGNCLIENT - 窗口客户区的水平位置8整倍数据对齐 CS_BYTEALIGN

VC++编程之第三课笔记——MFC窗口创建过程以及窗口类的封装

第三课 MFC窗口创建过程以及窗口类的封装 MFC的每一个类都是以C开头的,表明这是一个Class. 工程包含(单文档) 创建工程名为aaa的工程(单文档)时,在类视图中可看见五个类: CAboutDlg CMainFrame CAaaApp CAaaDoc CAaaView 其中: 类CAboutDlg继承自CDialog类,对话框的类 类CMainFrame继承自CFrameWnd类,创建整个程序的框架窗口 类CAaaApp继承自CWinApp类,创建唯一的应用程序对象 类CAaaDoc继承

【转】Android应用程序窗口(Activity)窗口对象(Window)创建指南

在前文中,我们分析了Android应用程序窗口的运行上下文环境的创建过程.由此可知,每一个Activity组件都有一个关联的ContextImpl对象,同时,它还关联有一个Window对象,用来描述一个具体的应用程序窗口.由此又可知,Activity只不过是一个高度抽象的UI组件,它的具体UI实现其实是由其它的一系列对象来实现的.在本文中,我们就将详细分析Android应用程序窗口对象的创建过程. 从前面Android应用程序窗口(Activity)实现框架简要介绍和学习计划一文可以知道,在PH

第3章 窗口与消息_3.2面向对象的窗口类的封装

3.2.1 MFC单文档大致框架 (1)MFC类继承略图 (2) MFC单文档应用程序类层次结构图 CWinApp:应用程序类,每个应用程序有且只有一个继承于CWinApp的派生类对象 CWnd:是一个通用的窗口类,用于提供Windows中的所有通用特性.对话框和控件. (3)应用程序执行过程图 3.2.2 应用程序QWinApp的设计 //QWinApp.h文件 #include "stdAfx.h" class QWinApp { public: QWinApp(); ~QWinA

关于WNDCLASSEX窗口类

WNDCLASSEX窗口类原型如下 1 typedef struct WNDCLASSEX { 2 UINT cbSize; 3 UINT style; 4 WNDPROC lpfnWndProc; 5 int cbClsExtra; 6 int cbWndExtra; 7 HINSTANCE hInstance; 8 HICON hIcon; 9 HCURSOR hCursor; 10 HBRUSH hbrBackground; 11 LPCTSTR lpszMenuName; 12 LPCT

5.窗口类和窗口的附加数据

附加数据的作用: 注册窗口时,设置这两个数据的大小,可以提供窗口类和窗口存放自己的数据的空间. 1.窗口类附加数据 int cbClsExtra    //窗口类附加数据buff大小 (1)用法: a.申请缓冲区 窗口对象.cbClsExtra = 200;  //一般赋4的倍数 b.写入数据 DWORD SetClassLong( HWND  hWnd;         //窗口句柄 int       nIndex;        //字节索引号(从哪个字节开始存) LONG  dwNewL

MFC注册窗口类以及FindWindow按窗口类名查询(避免用#32770获取窗口句柄)

呵呵,最近在研究SendMessage函数,其中需要用到m_hWnd,之后延伸着又尝试获得窗口的句柄,于是遇到了FindWindow函数,原型如下: HWND FindWindow ( LPCSTR lpClassName,    //输入窗口的类名,其实需要是注册过的类名才行,否则是要报错或者查找失败的. LPCSTR lpWindowName, //输入窗口的名称,就是窗口上面蓝色的那行玩意儿写的字. ); 对于这个函数,如果按照窗口的名称查找,相信大家都非常简单,因为名称在rc文件里,是已