探索Win32系统之窗口类(Window Classes in Win32)

MiniGUI编程速查表 前言 自己学习MiniGui也快一年了,粗浅的学习了一下,本文是根据《MINIGUI-PROG-GUIDE-V3.0-C》中的内容整理而来,根据自己的理解做了一些分类,大部分都是一些函数的说明,方便自己以后学习MiniGui时查阅。现在分享出来,供大家一起学习。当然在学习的过程中也遇到过一些坑,像自定义控件,主窗口透明背景,窗口弹出动画啊,控件动画等等,有时间也会分享出来。 1 窗口的创... 阅读详情
 

翻译说明: 以前一直没有很在意窗口类的使用,我近期在用vc做一些界面时遇到窗口类定义的概念,这次翻MSDN的时候看到了一篇文章,讲到窗口类的一些基本概念,匆匆看完,翻译出来当学习笔记,可能有一些细节上的谬误,请包涵。放在网上,如果大家觉得值得参考,就看看。

vcbear翻译

 

 


 

<正文>

vcbear@163.com

探索Win32系统之窗口类

(Window Classes in Win32)

Kyle Marsh
Microsoft Developer Network Technology Group
MSDN

  •  

  • 摘要

     

技术组win32系统里窗口类的运做和使用机制,探索一些细节问题,使win32窗口类的信息更加明朗化。,"类","窗口类"这两个术语等同,都不是指C++类,而是指和窗口相关的一组信息的集合。(register)一个相应的窗口类。32位Windows操作系统类可以注册被系统里所有的程序所使用的窗口类。RegisterClass函数,修改一下部分参数而已。这仿佛有些轻视了,没有发挥窗口类的作用。本文将对此进行探索,并且描述窗口类如何的使应用程序得到优化。(Windows Classes)

 

 

 


 

 

一:窗口类的类型

window

  •  

  • 系统全局类(
  • 应用程序全局类(
  • 应用程序局部类(
系统提供了三种类型的窗口类System global classes)

 

 

Application global classes)

 

 

Application local classes)

 

1.系统全局窗口类(

System Global Classes)

windows

  •  

以及其他不那么常用的控件如TabCtrl等.

还有:

  •  

  • 菜单窗口

     

     

  • 桌面窗口

     

     

  • 对话框窗口

     

     

  • 任务条窗口

     

     

  • 题头带图标的窗口

     

  • ComboLBox
  • MDIClient:
本身注册了几个系统全局类供全部的应用程序使用,这些类包括了以下的常用标准窗口控件

 

  • Listbox
  • ComboBox
  • ScrollBar
  • Button
  • Static
  • Edit
(列表框)

 

 

(下拉组合框)

 

 

(滚动条)

 

 

(按钮)

 

 

(静态标签)

 

 

(编辑框)

 

 

控件的下拉列表窗口

 

 

风格窗口的子窗口

 

WindowsNT

为DDEML(Dynamic Data Exchange Management Library)增加了DDEMLEvent类,因为DDEML功能已经结合到USER里去了。

Windows 95/98

所有的

应用程序可以通过

在

系统全局窗口类实现

现在的

  •  

    • 在

    系统全局类在

    •  

    • 如果在
    • 复制一份被子类化的窗口类的信息 。将复制的新类填加到应用程序的
    • 强制进程里所有的子类化过的窗口实例使用这个系统类的拷贝。但这不影响已经存在的窗口,窗口是使用事先已经拷贝到窗口实例数据区的类信息,并非直接使用进程里保存的类的信息。子类化只更新了进程的窗口类列表里的类的信息,而没有更新窗口实例里的类。

       

不注册类 #32772,因为它不使用题头带图标风格的窗口(由于我用的是win2k操作系统,这一点没有尝试)win32应用程序都可以使用系统全局类,但不能增加或删除一个这样的类。“子类化”(SubClassing)这些类来改变系统全局类的属性。在Win32里,应用程序子类化某个系统全局类只会影响本进程内窗口的表现,而不会影响另外一个进程或应用程序。比起相应的操作会影响其他窗口的win16时代,这是一个进步。Win32里,Ms鼓励“子类化”系统类的行为。因为这个技术可以非常有效和方便的改变窗口的表现。例如:如果应用程序希望限制edit控件的输入和编辑行为,可以通过子类化edit类并设置一个新的窗口过程(WindowProc)来自己处理处理键盘操作来实现。子类化以后,此应用程序里创建的edit控件将使用新的窗口过程,以代替标准的edit控件窗口过程。win32平台使系统类和各32位进程互不相干,系统类如何实现的并不会直接影响应用程序。本节将描述系统类的实现,当然,跳过此节并不妨碍全文的阅读和理解。win9x里的实现

 

win9x和win3.1的实现使相当相象的。在系统启动时,USER模块创建了系统类。win9x和win3.1不同的是:当发现一个应用程序子类化了某个系统类的时候,win9x将进行如下工作:debug模式下运行,在debug屏幕上显示一个 warning 信息

 

 

“私有”系统类列表里。win9x系统里,系统为每个进程都保持了这样的一个列表,以供系统存放系统全局类的克隆信息。

 

 

16

  •  
位应用程序共享相同的进程空间。在win9x里,16位程序的表现和它在win3.1里是一样的。

 

  • winNT
的实现

 

winNT

服务进程管理每个

在

则有很多的不同。winNT包括了两个win32子系统:一个服务进程和一个在各win32进程里运行的动态连接库(DLL)。以edit类为例,winNT在各进程空间里,从DLL里导出和注册edit类。这样,处理EDIT控件的代码可以存在于DLL里,也即在各进程空间里。不需要系统分配局部过程调用来处理Edit控件,应用程序对控件的频繁调用所导致的系统开销也被避免了。因为EDIT 控件实例仅仅在各进程空间里操作自身数据,所以对系统鲁棒性的冲击就降低了。win32应用程序的信息,包括应用程序的公有和私有窗口类。当创建一个win32线程的过程开始(即某个线程调用USER模块或GDI模块的函数时),USER模块检查该线程是否该进程的第一个线程,如果是(一般是主线程),USER模块为该进程注册系统类。当为了任何一个进程而注册一个类(服务模块进程除外),该类就会添加到该进程的公有或私有列表里。为了提高效率,windows为每个进程都注册系统类,并且把类信息的拷贝储存在应用程序的空间里。这增加了鲁棒性,但是比起Windows95,增加了需要使用的内存。windowsNT也由此获得了更高的性能,因为当子类化一个系统类的时候,winNT不需要象window95那样重新分配内存和拷贝类信息。winNT里,16位的应用程序依然共享同一进程,也共享所有的系统全局类。16位程序总是不稳定因素的起源。

2.应用程序全局类。

应用程序全局类是注册的时候指定了

CS_GLOBALCLASS标志的类(该标志还有后续叙述)。

16

位系统比如win3.1的应用程序“全局”类是真正意义的“全局”的,一个DLL或应用程序注册的应用程序全局类,系统内所有的DLL和应用程序都可以使用。一个应用程序全局类在“全局”的意义上和系统全局类一致,只是它是由应用程序创建的而不是系统创建的而已。

Win32

作为这个特性的扩展,

的应用系统全局类本质的不同是:应用程序全局类只是在进程内部的“全局”而已。这是什么意思呢?一个DLL或.EXE可以注册一个类,这个类可以让在相同的进程空间里其他.EXE和DLL使用。如果一个DLL注册了一个非应用程序全局类的窗口类,那么,只有该DLL可以使用该类,同样的,.EXE里注册的非应用程序全局类也适用这个规则,即该类只在该.EXE里有效。win32有一项技术,允许一个第三方窗口控件在DLL里实现,然后把这个DLL载入和初始化到每个Win32进程空间里。这项技术的细节是,把DLL的名字写入注册表的指定键值里:
HKEY_LOCAL_MACHINE/Software/Microsoft/Windows NT/CurrentVersion/Windows/APPINIT_DLLS

这样当任意一个

 

win32应用程序加载的时候,系统也同时将该dll加载到进程空间里(这可能有点过于奢侈,因为很多win32程序不一定会使用该控件)。DLL在初始化的时候注册应用程序全局类,这样的窗口类就可以在每个进程空间的.EXE或DLL里使用了。这个技术基于win32系统的这个特性:允许在每个进程空间里自动的(也是强制的)加载特定的DLL(事实上,这也是打破进程边界,把你的代码切入到其他进程里的一种办法)。

3. 应用程序局部类

WIN32

 

应用程序局部类是使用最频繁的类(绝大部分的应用程序为主窗口注册的类都是应用程序局部类),仅仅在声明和注册该类的应用程序模块或DLL自身里使用。注册一个应用程序局部类和应用程序全局类的区别是,局部类不包括CS_GLOBAL CLASS标志。

 


 

二:窗口类包含的信息和作用

窗口类都包含些什么信息呢?让我们看以下窗口类结构体。

WNDCLASS

结构包含的是一般的窗口类的信息
typedef struct tagWNDCLASS {   
    UINT      style;
    WNDPROC   lpfnWndProc;
    int       cbClsExtra;
    int       cbWndExtra;
    HINSTANCE hInstance;
    HICON     hIcon;
    HCURSOR   hCursor;
    HBRUSH    hbrBackground;
    LPCSTR    lpszMenuName;
    LPCSTR    lpszClassName;
} WNDCLASS;

 

成员

描述

style

一组标志位的组合。定义比如窗口位置,设备上下文

(DC)分配,双击的处理等特征。

lpfnWndProc

指向窗口过程的地址,该窗口过程负责处理窗口类相应的窗口消息

cbClsExtra

指明需要额外分配的内存数量,单位为

byte,系统为该类分配保留指定数量的额外内存

cbWndExtra

指明需要额外分配的内存数量,单位为

byte,系统为每个该类所对应的窗口实例分配保留指定数量的额外内存

hInstance

标识注册该类的

DLL或应用程序实例

hIcon

当一个属于该类的窗口被最小化的时候,显示的图标

.

hCursor

属于鼠标该类的窗口里显示的指针

hbrBackground

定义当程序打开或重画某个属于该类的窗口是,填充窗口客户区的颜色和样式

lpszMenuName

如果没有显性定义菜单时,窗口的默认菜单

lpszClassName

字符串的类名

以下详细讨论各成员的具体意义:

  •  

 

  • Class Styles (style)

     

Style

成员决定了从该类创建出来的窗口的风格,可以使用下列值的一个或几个的组合。
CS_BYTEALIGNCLIENT
,CS_BYTEALIGNWINDOW

如果使用这两个标志,窗口的的客户区或整个窗口都在“字节边界”上对齐,也就是说,系统调整窗口的水平位置,客户区或整个窗口的左边坐标是

看看系统如何摆放一个边框宽度为

8的倍数。win32 SDk的文档说这两个标志影响窗口的宽度,但是实际上笔者没有发现这个现象,此标志只影响窗口的水平位置(左边)。4的窗口:

Original window location

Placement with CS_BYTEALIGNWINDOW

Placement with CS_BYTEALIGNCLIENT

0,y

0,y

4,y

1,y

0,y

4,y

2,y

0,y

4,y

3,y

0,y

4,y

4,y

8,y

4,y

5,y

8,y

4,y

6,y

8,y

4,y

7,y

8,y

4,y

8,y

8,y

12,y

9,y

8,y

12,y

10,y

8,y

12,y

11,y

8,y

12,y

12,y

16,y

12,y

13,y

16,y

12,y

14,y

16,y

12,y

15,y

16,y

12,y

16,y

16,y

20,y

这两个标志在以下两个情况中无效:

  •  

  • 如果显示设备对每个象素使用
  • 如果使用
8个或更多的位数,字节对齐并不会带来什么好处。这种情况下,系统在创建和移动的时候忽略了CS_BYTEALIGNCLIENT和CS_BYTEALIGNWINDOW这两个标志。

 

 

SetWindowPos函数改变窗口的位置,此函数忽略窗口的CS_BYTEALIGNCLIENT和CS_BYTEALGNWINDOW标志指定的位置限定。在Win32 SDK文档关于WM_WINDOWPOSCHANGEING的描述让人费解,它说:“对于一个有WS_OVERLAPPED和WS_THICKFRAME风格的窗口来说,DefWindowProc函数响应WM_WINDOWPOSCHANGING消息,并向窗口发送一个WM_GETMINMAXINFO消息,此消息的处理是验证窗口的新位置和尺寸,迫使窗口接受CS_BYTEALIGNCLIENT和CS_BYTEALIGNWINDOW限定”

 

其实当

DefWindowProc接受到WM_WINDOWPOSCHANGING消息后,确实发送一条WM_GETMINMAXINFO消息,但是并不迫使窗口接受字节对齐的风格,为了确保字节对齐风格,应用程序必须通过计算再改变其水平位置

CS_BYTEALIGNCLIENT

如果程序使用

其实对于可以显示

使用

和CS_BYTEALIGNWINDOW的存在是为了优化程序的性能,尤其在是3.0版本的windows系统以前。那时侯,所有的系统字体宽度都是固定的,系统可以通过使窗口字节对齐优化字体的显示。在3.0以后的window里,这一点已经被忽略了。BitBlt函数从一个窗口向另一个窗口,或者从窗口的某个矩形区域向另一个矩形区域拷贝象素,还是可以通过设置CS_BYTEALIGNCLIENT标志来获得更好的性能。如果客户区是字节对齐的,程序也可以尽量保证BitBlt操作发生在字节对齐的矩形里, BitBlt操作将会比发生于非字节对齐的矩形里的操作更快。当然,字节对齐仅仅是对窗口的左边界而言的,如果要进一步的提高性能,应该连宽度都进行字节对齐。256及以上颜色的视频卡或显示器,对字节对齐的需求已经微乎其微了。256色显示器已经自己实现了字节对齐,实际上,一些16色的显示器也是字节对齐的。在大部分显示器上根本看不出来字节对齐限定对窗口位置的影响。一句话,字节对齐标志已经没有什么重要的作用了。CS_BYTEALIGNWINDOW的时候也等同于包含了CS_BYTEALIGNCLIENT;对话框类本身已经默认包含了CS_BYTEALIGNWINDOW标志
CS_OWNDC, CS_CLASSDC
, CS_PARENTDC

这几个标志决定窗口的默认

  •  
  •  

  • 如果使用了
  •  

  • 如果不指定

在

出于对

DC

 

  • 如果使用
CS_OWNDC标志,属于此窗口类的窗口实例都有自己的DC(称为私有DC),私有DC仅属于该窗口实例,所以程序只需要调用一次GetDC或BeginPaint获取DC,系统就为窗口初始化一个DC,并且保存程序对其进行的改变。ReleaseDC和EndPaint函数不再需要了,因为其他程序无法访问和改变私有DC。当选择了CS_OWNDC,程序改变影射模式(Mapping Mode)的时候必须小心,当由系统擦除窗口的背景时,系统假定和默认其影射模式是MM_TEXT。如果私有DC的影射模式不一样,窗口被擦除的地方将不再可见。

 

CS_OWNDC

如果使用

为

标志在WinNT和Win9x的作用也是有差别的。在WinNT,win32子系统和其他NT进程有相同的地址空间(4GB),应用程序使用此地址空间里的2GB,每个有CS_OWNDC标志窗口实例占用800个字节,在NT下,这里面没有什么问题。而Win9x为GDI保留了64K的局部堆,DC进入这个堆之后,即使其他GDI对象数据被释放,DC依然在。这意味着每个CS_OWNDC的窗口都在这个宝贵的内存空间里占用800个字节。所以,为win9x写的程序最好尽量少的使用CS_OWNDC这个标志。win9x的修正版打算解决这个问题,但效果不明显(而且win9x已经开始式微了)CS_CLASSDC标志,所有属于该类的窗口实例共享相同的DC(称为类DC).类DC有一些私有DC的优点,而更加节约内存(因为不需要为每个窗口实例都分配800字节的DC空间了)。每个窗口实例都通过GetDC或BeginPaintde得到设备上下文(DC)句柄,如果没有别的窗口需要该DC,不需要调用ReleaseDC或EndPaint释放DC。在一个窗口实例上通过GetWindowDC,GetDC,GetDCEx,BeginPaint获得 DC,并对其中的一些参数进行更改的话,所进行的更改除了剪切区域和设备本身属性(Device origin)之外对所有其他窗口实例都是有效的。和CS_OWNDC相同的是,必须确保影射模式也是MM_TEXT,否则,被系统擦除的背景将不再可见。NT编写的程序最好不要使用这个标志,因为“节约内存”的好处根本不明显。对于win9x来说,却是有用的,因为对于win9x的64K的GDI局部堆来说,节约的空间意义更重大一些。CS_PARENTDC标志,属于这个类的窗口都使用它的父窗口的句柄。和CS_CLASSDC相似的是,多个窗口共享一个DC,不同的是,这多个窗口(虽然有父子关系并且共享DC)并不要求都属于同一个窗口类。

 

WIN9x

下,所有的标准窗口控件都有CS_PARENTDC标志。WinNT下,除了ComBoBox之外的窗口控件都有此标志。因此,比如Edit控件和ListBox控件都共享他们的父窗口(比如对话框)的DC

(

使用

注:这一段是我根据原文再加上自己的理解,不一定完全正确:) CS_PARENTDC带来的好处就一个字:速度。Win9x系统为每个线程预留了5个DC缓冲区,如果一个窗口(比如一个对话框)有多于5个的字窗口(比如有6个或以上的编辑框),而每个子窗口都有自己的DC的话,DC缓冲区就失去了效力,系统得为每个子窗口根据剪切边界和设备属性重新初始化一个DC,这多于5个的DC在DC缓冲里不停交换,不能确保在缓冲里被访问。而如果每个子窗口都和父窗口共享一个DC,在频繁访问该DC时,该DC在于DC 缓冲里被找到的几率显然相当的高,从而可以被高速的访问,显著的提高了速度,所以一般来说标准窗口控件都和父窗口共享DC。WinNT可以拥有多于5个的DC缓冲,所以它可能可以提供足够的DC缓冲 -- 但是不保证时时如此。CS_PARENTDC的另一个效果是,子窗口可以在父窗口的客户区随意做画,就象画在自己的客户区一样. 负责表现Edit控件和ListBox控件周围的3D效果的CTL3D库就是利用了这个特性。注意如果程序需要改变各子窗口的影射模式,那么最好不要用CS_PARENTDC标志,否则将很容易引起各子窗口影射模式的混乱,因为所有的子窗口都使用同一个DC。CS_OWNDC,CS_CLASSDC或CS_PARENTDC这几个标志,此类的窗口使用一个通用DC,并置于DC缓冲里以供使用。通用DC在使用前获取,使用后释放,在DC获取的时候,DC里的上下文按默认值初始化,除非当时该DC已经在窗口的DC缓冲里(比如没有调用ReleaseDC或EndPaint释放DC),这样的话DC的剪切边界和设备属性都不需要被重新初试化,可以节约一些时间。

 

WinNT里,DC缓冲没有确定的数量。如果所有的DC缓冲都在使用中,而程序调用了GetDC和BeginPaint,NT则再分配一个缓冲。win9x的兼容考虑,win32程序最好把 DC的使用限制在5个以下,并且尽可能快的释放DC.

如果要忽略类创建时由标志位决定的窗口的默认

ScrollWindow

  •  
DC,程序可以使用GetDCEx函数,指定DCX_CACHE标志,则完全忽略CS_OWNDC和CS_CLASSDC标志,并从缓冲里返回一个通用DC.和ScrollWindowEx函数处理DC的方法则有所不同:

 

  • ScrollWindow
  • ScrollWindowEx
使用窗口默认的DC。因此,如果窗口使用CS_OWNDC或CS_CLASSDC标志,ScrollWindow使用相应的DC(窗口私有DC或类DC,其影射模式有可能被程序改变,不为MM_TEXT).传递给ScrollWindow的坐标值必须和DC的影射模式相一致。

 

 

使用系统通用DC(这种DC使用MM_TEXT的影射模式),而忽略窗口的标志。传递给ScrollWindowEx的坐标值必须是MM_TEXT影射模式下的客户区坐标值。

 

CS_DBLCLKS

CS_DBLCLKS

  •  

  • 如果窗口没有
  •  

  • WM_LBUTTONUP

     

     

  • WM_LBUTTONDOWN

     

     

  • WM_LBUTTONUP.

     

  •  

  • 如果窗口有
  •  

  • WM_LBUTTONUP

     

     

  • WM_LBUTTONDBLCLK

     

     

  • WM_LBUTTONUP.

     

注意,在上述序列中间可能会插入其他的一条或一些消息,所以这两个消息序列不一定是完全连续的。

其实,在没有指定

所有的标准窗口控件,对话框,桌面窗口类都默认拥有

标志使窗口可以检测到双击事件。窗口响应双击的细节如下:CS_DBLCLKS标志,系统向窗口依次发送如下消息:

 

WM_LBUTTONDOWN

其实相当于两个单击。

CS_DBLCLKS标志,则系统向窗口依次发送如下消息:

 

WM_LBUTTONDOWN

第一种情况中的第二个

WM_LBUTTONDOWN被WM_LBUTTONDBLCLK代替了。CS_DBLCLKS标志时,程序本身也可以检测到双击事件的。参见MSDN里Dr.GUT的"Simulating Mouse Button Clicks"文章,不过要有一些技巧.一般的情况下,如果没有指定CS_DBLCLKS,在窗口的消息循环里将不会得到WM_LBUTTONDBLCLK消息。CS_DBLCLKS标志。第三方控件最好也加上此风格,以使其在对话框编辑器里可以正常工作。
CS_GLOBALCLASS

CS_GLOBALCLASS

是唯一一个针对类本身起作用而不是对单个窗口起作用的标志.系统将包含这种标志的窗口类作为应用程序全局类保存,这样类可以应用于注册该类的进程内的所有EXE和DLL,当EXE或DLL退出或卸载,或对该类调用UnregisterClass后,该类则被销毁。在注册该窗口的程序退出前,所有从该类创建的窗口都必须先关闭(对于DLL来说,这是自动进行的)。
CS_HREDRAW ,CS_VREDRAW

CS_HREDRAW

标志表示当窗口的水平尺寸(宽度)改变的时候,重画整个窗口。CS_VREDRAW则是在窗口垂直尺寸(高度)改变时重画整个窗口。按钮和滚动条都有这两种风格。
CS_NOCLOSE

如果指定了

CS_NOCLOSE标志,则窗口上的关闭按钮和系统菜单上的关闭命令失效。
CS_SAVEBITS

菜单,对话框,下拉框都拥有

CS_SAVEBITS标志。当窗口使用这个标志时,系统用位图形式保存一份被窗口遮盖(或灰隐)的屏幕图象。首先,系统要求显示驱动保存图象位数据,如果显示驱动本身的存储空间足够,保存操作成功,window系统也可以使用这些保存的位数据。如果不够,系统将位数据在全局内存里以位图的方式保存,并且在USE模块局部堆里为每个窗口分配空间,保存一些事务数据(比如位图数据缓冲的大小)的结构。当程序使遮盖屏幕的窗口消失时,系统可以很快的从内存里恢复屏幕图象。

CS_SAVEBITS

 

以上都是style成员的可选标志。

 

  •  
的效率本身是很难度量的。CS_SAVEBITS提高了“临时”窗口比如菜单,对话框,下拉框的性能。但是,存贮位信息的开销也是很明显的,尤其由系统代替显示驱动存储位信息的时候,系统承担了速度和存储开销。 使用CS_SAVEBITS的好处其实依赖于窗口遮盖的区域发生了什么事情,如果该区域相当复杂,需要重画很多的效果,那么,存储该区域可能比重画该区域要来的轻松,如果反之,该区域可以相当快速的重画,或者在被遮盖的时候还经常发生变化并且变化很显著,保存的方案反而影响了整体性能。

  • The Window Procedure (lpfnWndProc)

WNDCLASS

当一个程序或

  •  
结构里的lpfnWndProc成员保存了该窗口类的窗口过程地址。该窗口类的所有窗口都使用该过程地址,对于从该类创建的窗口,系统将所有相关的消息交给此窗口过程来处理。窗口过程实现窗口的功能,程序可以使用SetClassLong函数来改变窗口类的窗口过程。这个操作叫“子类化”(Subclassing)。当程序改变了该过程的地址,在改变前已经创建的窗口还是使用原来的地址,而以后创建的窗口才使用新的过程地址。DLL子类化一个窗口或设置窗口过程函数,必须在模块定义文件里输出该新窗口过程。

 

  • Extra Class and Window Bytes (cbClsExtra and cbWndExtra)

     

cbClsExtra

在

成员指明为每个窗口类多分配的额外数据量,cbWndExtra成员则是指明为每个窗口实例分配的额外数据量。如果程序不需要分配额外的数据,这两个成员的值都应该设置为 0,以免产生不确定的数(比如一个非常大的数)而使系统进行错误分配,如果是负数,则该窗口类将不会被注册。Win9x和NT,分配40个及以下字节是没有多大意义的,当然,开发人员可以根据需要分配额外数据大小。

如果用类声明并注册一个对话框类型的窗口,cbWndExtra的值必须设置为DLGWINDOWEXTRA,系统对话框管理器需要这么多的额外数据对对话框进行管理。

  •  

 

  • Instance Handle (hInstance)

     

WNDCLASS

  •  
的hInstance成员标识类所在的模块。此成员可以为进程的hInstance,或DLL的hInstance,但不可以为NULL.

 

  • Class Icon (hIcon)

     

WNDCLASS

  •  
的hIcon成员标识此窗口类的图标。程序一般使用LoadIcon,从系统标准图标库(如IDI_APPLICATION)或用户指定的图标资源中来获取一个图标句柄。如果hIcon的值为NULL,当系统给程序发送WM_ICONERASEBKGND消息的时候,程序给窗口画上程序的主图标.

 

  • Class Cursor (hCursor)

     

WNDCLASS

  •  
里的hCursor成员表示属于该类窗口的默认鼠标指针。当设置了该值,当鼠标移入窗口区域时,系统将指针由系统默认形状变成所设置的指针形状。程序可以使用LoadCursor函数从标准系统指针库(比如IDC_ARROW)或用户指定指针资源中获取指针句柄。程序可以通过SetCursor函数随时改变指针。如果hCursor的值未设置(设置为NULL),程序必须在鼠标指针移入窗口时进行设置,否则将使用系统默认的鼠标指针形状。

 

  • Class Background Brush (hbrBackground)

     

WNDCLASS

里的hbrBackground成员变量表示背景颜色的,类型为HBRUSH,即GDI刷子句柄。可以对其赋值为一个刷子句柄(比如用GetStockObject获取系统内置刷子对象句柄,或者自己创建指定颜色和风格的刷子的句柄)或者颜色值。如果是选择颜色值的话,必须使用下列系统标准颜色之一。

COLOR_ACTIVEBORDER

COLOR_HIGHLIGHTTEXT

COLOR_ACTIVECAPTION

COLOR_INACTIVEBORDER

COLOR_APPWORKSPACE

COLOR_INACTIVECAPTION

COLOR_BACKGROUND

COLOR_INACTIVECAPTIONTEXT

COLOR_BTNFACE

COLOR_MENU

COLOR_BTNSHADOW

COLOR_MENUTEXT

COLOR_BTNTEXT

COLOR_SCROLLBAR

COLOR_CAPTIONTEXT

COLOR_WINDOW

COLOR_GRAYTEXT

COLOR_WINDOWFRAME

COLOR_HIGHLIGHT

COLOR_WINDOWTEXT

用颜色值赋值时,必须强制类型转换为

如果

  •  
hbrBackground成员设置为NULL,程序必须在响应WM_PAINT的时候负责画背景。程序也可以响应WM_ERASEBKGND消息,或根据调用BeginPaint函数时填充的PAINTSTRUCT结构里的成员fErase的值类判断是否需要重画背景。

 

  • Class Menu (lpszMenuName)

     

WNDCLASS

  •  
里的lpszMenuName成员表示默认主菜单。可以使用MAKEINTRESOURCE宏把资源里菜单项的ID号转变成连续的字符串值赋给该成员。如果使用CreateWindow或CreateWindowEx函数从该类创建窗口时没有在函数参数里指定别的菜单资源,那么出现在各窗口上的主菜单就是lpszMenuName指定的菜单。如果lpszMenuName为NULL,窗口则没有默认的主菜单。

 

  • Class Name (lpszClassName)

     

WNDCLASS

里的lpszClassName结构表示类的名字。局部窗口类名在进程范围必须为唯一的,由于仅要求“在进程内唯一”,对于两个不同的程序来说,其中的窗口类名有可能相同,比如,两个程序都可能拥有各自的"Main Wnd"窗口。全局窗口类的名字必须在全局窗口类和系统窗类口范围里唯一,比如,程序可以注册一个名字为"Edit"的局部窗口类,但是无法注册同样名字的一个全局窗口类。

 


 

 

三

系统如何定位窗口类

当程序需要根据一个类创建一个窗口,系统通过以下步骤来定位该类

1

.系统在本进程的局部窗口类列表里寻找有相同名字的类。如果找到,由于局部窗口类是属于某一个.EXE模块或DLL的,所以所找到的类的进程实例句柄(hInstance)和本模块的实例句柄应该保持一致。这样的规则是为了防止进程内一个模块或DLL里注册的局部类被进程其他及其的模块或DLL发现。

2

在

  1.  

  2. 如果系统还是无法发现同名窗口类,则继续搜索全局系统类列表。

     

.如果系统无法发现一个同名的局部类,那么,就继续搜索进程的全局类列表,这次的搜索不比较实例句柄。win9x,如果在程序全局类空间里无法发现同名类,则继续查询进程内的系统窗口类列表。

winNT

将此过程应用于所有由程序创建的窗口,包括从主窗口再创建出的其他窗口,比如对话框和消息框。

win9x

同样将此过程应用于所有的窗口,除了消息框以外。当程序弹出一个消息框,Win9x不对局部类列表进行搜索,而是直接进行后续步骤。

 


 

四 应用程序的如何使用窗口类信息。

一旦注册了一个类,一般来说除了使用该类创建窗口之外就没有什么需要作的事情了。当然,如果需要访问该类信息,子类化,或者超类化该类,介绍一些方法就是有用的。

  •  

    • 类访问函数

       

    如果需要获取和改变类的信息,可以使用以下函数:

    •  
    •  

    具体的调用参数以及其他相关的一些类函数可以参见

    •  

 

  • GetClassLong
  • SetClassLong
  • GetClassWord
从类信息读回来一个Long类型的值(比如,窗口类的窗口过程地址)

 

 

对该类的某成员写入一个long类型的值。比如,写入一个新的窗口过程的地址。

 

 

从类信息读回来一个word类型的值。比如以下调用得到类的额外数据量:

 

nClassExtra = GetClassWord(hwnd,GCW_CBCLSEXTRA);

SetClassWord

向类信息写入一个word类型的值。比如改变窗口类图标。

 

  • GetClassName
  • GetClassInfo
获取窗口类的名字。

 

 

获取除类名和菜单以外的全部类信息。

 

MSDN里windows classs Functions 一节。

 

  • 子类化:(SubClassing)

     

术语“子类化”

在

  •  
(subclassing)描述的是用一个新的窗口过程代替原窗口过程。术语“实例子类化”(即子类化单个窗口)是指使用SetWindowLong函数改变某一个窗口实例的窗口过程。“全局子类化”(子类化整个窗口类)则是指使用SetClassLong改变整个类的默认窗口过程函数。32位windows 系统里,可能难于子类化另一个进程里的窗口或窗口类,一般来说,子类化都是发生于同一个进程里的(“打破进程边界”的相关的主题本文没有涉及)。

 

  • 超类化:(Superclassing)

     

术语

关于子类化和超类化的具体描述,请参阅

 

"超类化"(Superclassing)指创建一个新的类,该类使用某个现存类的窗口过程,继承该类的基本功能,并可以在此基础上进行扩展。MSDN里"safe subclasing in Win32"一文

结束语

: win32的窗口类给开发人员带来了很多有用的信息,在win32平台上开发程序,最好是注意使用兼容winNT和win9x的一些特性以保证程序的兼容性。
,
HBRUSH类型:
cls.hbrBackground   = (HBRUSH)(COLOR_WINDOW+1);
MDI
:ComBoBox

本文主要介绍

在本文中

  •  

    • 简介

       

    窗口类的风格决定了窗口的外观和风格。所有的窗口都会属于某一个窗口类。在创建一个窗口之前,必须注册

    大部分开发人员认为窗口类是个麻烦的东西,他们顶多就是从例子或其他代码中拷贝一个

    我们的将讨论的题目包括:

    •  

    • 什么是窗口类
    • 系统全局,应用程序全局,应用程序局部类的区别

       

       

    • 类里包含了那些信息

       

       

    • 这些信息如何影响窗口的表现

       

       

    • 应用程序如何使用窗口类信息。

       

在MFC编程里,窗口类的概念接触的已经比较少了,在SDK编程的时候则至少还需要声明一个WNDCLASS(EX)类RegisterClass(Ex)一下。但是窗口类在windows中是无所不在的,虽然不是很深奥的东西,了解一下其中细节,个人觉得对编程应该是有好处的。

[ windows程序设计(programing windows) ] - 窗口滚动条 本次要介绍的控件是ScrollBars滚动条。滚动条一般在要现实的东西过多以至于屏幕无法完整呈现时使用。此时,你可以用它来滚动窗口,来显示内容的不同部分。 滚动条这个东西用电脑应该都见得多了,由两个中间包含三角的方块和一个位于两个方块之间的长条组成,一般来说这个长条是可以随着显示内容占总内容的多少来改变长度的这个比例越小,长条越小。 阅读详情

相关推荐

win32-注册窗口类、创建窗口

win32-注册窗口类、创建窗口

Jackey_Song的博客 2453

ScrollWindow()函数

在学习windows编程第五版时,介绍scrollbar时,改进的程序用到了ScrollWindow()函数。按照我的理解,如果使用了UpdateWindow()函数可以 不使用ScrollWindow()函数。因为UpdateWindow()函数会产生一个WM_PAINT消息。为了搞清楚ScrollWindow()函数的作用,我将代码加了些调试 代码/*-------------------

yongan1006的专栏 6043

在Modelsim中手动添加仿真库

缘由:在使用rom ip核的时候发现仿真需要altera_mf库的支持,而我的ModelSim没有这个库,所以想写一篇手动添加仿真库的文章方便自己以后使用:首先新建一个库,名字叫做altera_mf:然后编译对应的库文件:这里altera_mf.v文件是在quartus安装路径下quartus\eda\sim_lib文件夹下,点击编译后退出:最后在modelsim->example文件夹下可以找到编译好的库文件:

欢迎一起交流问题! 3402

探索Win32系统之窗口类(Window Classes in Win32)

Kyle MarshMicrosoft Developer Network Technology Groupvcbear翻译•摘要 本文主要介绍win32系统里窗口类的运做和使用机制,探索一些细节问题,使win32窗口类的信息更加明朗化。在本文中,"类","窗口类"这两个术语等同,都不是指C++类,而是指和窗口相关的一组信息的集合。•简介 窗口类的风格决定了窗口的外观和风格。所有的窗口都会属于

落叶的专栏 1444

AD9176 双通道高速DAC调试记录

AD9176是一款高性能双通道16位数模转换器,支持高达12.6GSPS采样率,专为多频段无线应用设计。该器件集成8通道15.4Gbps JESD204B接口,支持复数/实数数据输入,每通道最大输入速率达3.08GSPS。关键特性包括:48位高精度NCO、灵活的插值滤波器(最高12倍)、优异的动态性能(SFDR达-83dBc@1.84GHz)以及多芯片同步功能。硬件调试需重点关注时钟配置(建议250M基准时钟)、JESD参数匹配及交流耦合设计。测试指标要求SFDR>55dBc@312MHz,实测值可达65d

universaldata的博客 1489

YOLOv11【第三章:高阶应用与落地篇·第7节】多任务联合训练(Multi-Task Learning):检测+分割+关键点三头并进!

🏆 本文收录于专栏 《YOLOv11实战:从入门到深度优化》。本专栏围绕 YOLOv11 的改进、训练、部署与工程优化 展开,系统梳理并复现当前主流的 YOLOv11 实战案例与优化方案,内容目前已覆盖 分类、检测、分割、追踪、关键点、OBB 检测 等多个方向。

**My Coding Family** 728

探索Win32系统之窗口类(Window Classes in Win32)

翻译说明: 以前一直没有很在意窗口类的使用,我近期在用vc做一些界面时遇到窗口类定义的概念,这次翻MSDN的时候看到了一篇文章,讲到窗口类的一些基本概念,匆匆看完,翻译出来当学习笔记,可能有一些细节上的谬误,请包涵。放在网上,如果大家觉得值得参考,就看看。 在MFC编程里,窗口类的概念接触的已经比较少了,在SDK编程的时候则至少还需要声明一个WNDCLASS(EX)类RegisterCl

1005

图形推理2-四大类六提示

图形推理笔记2

小y的学习笔记 6742

探索Win32系统之窗口类(Window Classes in Win32)(异域の蜗牛注:关于win32编程中的窗口类的探讨)

  作者:vcbear    翻译说明:以前一直没有很在意窗口类的使用,我近期在用vc做一些界面时遇到窗口类定义的概念,这次翻MSDN的时候看到了一篇文章,讲到窗口类的一些基本概念,匆匆看完,翻译出来当学习笔记,可能有一些细节上的谬误,请包涵。放在网上,如果大家觉得值得参考,就看看。 在MFC编程里,窗口类的概念接触的已经比较少了,在SDK编程的时候则至少还需要声明一个WNDC

异域の蜗牛's blog 1630

自助结账商品检测(Scanned Item Detection)——基于YOLOv8的RPC数据集实战

RPC数据集是由中国科学院自动化研究所发布的零售商品结账检测公开数据集,广泛用于自助结账和零售场景下的目标检测与识别。YOLOv8是YOLO系列最新版本,由Ultralytics推出,继承了YOLO家族的高效快速和高准确性,适用于实时检测场景。本文系统介绍了基于YOLOv8的RPC数据集自助结账商品检测方案,涵盖数据准备、训练、推理及UI界面设计。未来,可结合多模态感知、RFID融合技术,打造更加智能和稳定的自助结账系统。

YOLO 250

ZYNQ Petalinux编译系统启动文件实战指南

本文提出的混合编译加速方案实测可将编译时间从45分钟缩短至18分钟,QSPI双启动方案已在工业控制领域成功应用。Xilinx官方UG1144文档(最新v2023.1版)正点原子《ZYNQ嵌入式开发实战》开源项目Meta-Petalinux(GitHub趋势项目)未来展望:随着Versal平台的普及,Petalinux将支持更多AI加速器原生驱动,值得持续关注。

QQ_778132974的博客 812

Window Classes in Win32

探索Win32系统之窗口类(Window Classes in Win32) Kyle MarshMicrosoft Developer Network Technology GroupMSDN技术组 摘要 本文主要介绍win32系统里窗口类的运做和使用机制,探索一些细节问题,使win32窗口类的信息更加明朗化。 在本文中,"类","窗口类"这两个术语等同,都不是指C++类,而是指和窗口相...

weixin_30855099的博客 114

人形机器人开源资源大盘点(四):硬件开源平台

开源人形机器人平台推动技术民主化 本期聚焦四大开源人形机器人平台:斯坦福的ToddlerBot以6000美元低成本实现30自由度运动,支持仿真到现实的零样本迁移;法国Reachy2被HuggingFace收购,融合开源AI与硬件,适配医疗、工业等场景;国内OriginMan基于ROS2全开源,集成大模型能力,支持深度改造;OAN框架则为经典NAO机器人注入开源活力,扩展交互功能。这些平台通过不同路径降低研发门槛,推动人形机器人技术走向开放共享的未来。

Studying…… 370

Win32 SDK基础(5)—— 漫谈窗口类

一、引言         在上一文中,我们从零开始创建了一个窗口。其中很重要的一个步骤,就是注册窗口类,如下面的代码: //注册窗口类 BOOL Register(LPSTR lpClassName, WNDPROC wndProc) { WNDCLASSEX wce = { 0 }; wce.cbSize = sizeof(wce); wce.cbClsExtra =

Hyman的博客 2988

Arduino ESP8266通过 RF433数据收发实验

Arduino ESP8266通过 RF433射频模块实现数据收发实验 写这篇文章,折腾了2天,在没有成功之前,一直在摸索和采坑当中,不要问我黑暗和黎明之间有多长。开发很多时候只问结果,不问过程的,在这里分享来之不易的结果,希望后面的人不要采坑,有成功的案例先河,后面与之相关的应用开发只需要套用模板修改即可实现。 实物搭建 RF433模块 我使用的是这个:nodemcu 本案例开发所使用到的库:RadioHead:http://www.airspayce.com/mikem/

perseverance51博客 3808

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Window Class Registration(窗口类的注册)

This note describes the MFC routines that register the special WNDCLASSes needed by Microsoft Windows. Specific WNDCLASS attributes used by MFC and Windows are discussed.此章节讲述了一些MFC中的常规内容,涉及注册Micros

benny5609的专栏 4865

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

封装一个Win32弹出提示框的函数(用于Window控件 显示Tooltip)

原标题:封装一个Win32弹出提示框的函数(用于STATIC等控件显示Tooltip) HWND WINAPI CreateToolTip(HWND hwndOwner, LPCTSTR szTip) { INITCOMMONCONTRO

huangzhe10的专栏 1366

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

GCC编译器让调用Win32 API的C程序显示为系统风格的控件

问题描述 我用C语言调用Win32 API时发现,显示的窗口控件仍是 Win98 时代的按钮风格。 一开始我以为DLL调用都是这样的,我就用Python3调用了一下User32.dll下边的MessageBoxW函数结果却是系统样式的。看到这样的结果非常不解。 就决定去网上看看有什么办法可以解决,看到网上给出的最多的方法是添加一条#pragma 的预处理指令: #ifdef _UNICODE #if defined _M_IX86 #pragma comment(linker,"/manifestdepe

qq_58286297的博客 1651

mfc获取子窗口句柄_VC|Window Object句柄与MFC Object指针的相互关系和转换

MFC中最重要的封装是对Win32 API的封装,因此,理解Windows Object和MFC Object (C++对象,一个C++类的实例)之间的关系是理解MFC的关键之一。所谓Windows Object(Windows对象)是Win32下用句柄表示的Windows操作系统对象;所谓MFC Object (MFC对象)是C++对象,是一个C++类的实例,这里MFC Object是有特定含义...

weixin_39992462的博客 248
上一篇: 经典与现代的结合:在MFC中集成RAD .NET框架
下一篇: Hooking KiFastSystemCall
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值