zoukankan      html  css  js  c++  java
  • 窗口类(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上对应的内容,一般都会有描述的。

  • 相关阅读:
    OSCP Learning Notes Buffer Overflows(3)
    OSCP Learning Notes Buffer Overflows(5)
    OSCP Learning Notes Exploit(3)
    OSCP Learning Notes Exploit(4)
    OSCP Learning Notes Exploit(1)
    OSCP Learning Notes Netcat
    OSCP Learning Notes Buffer Overflows(4)
    OSCP Learning Notes Buffer Overflows(1)
    OSCP Learning Notes Exploit(2)
    C++格式化输出 Learner
  • 原文地址:https://www.cnblogs.com/tocy/p/About-Window-Class.html
Copyright © 2011-2022 走看看