zoukankan      html  css  js  c++  java
  • MFC学习笔记2——MFC和Win32

    1.MFC Object和Windows Object的关系

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

    MFC Object 和Windows Object是不一样的,但两者紧密联系。以窗口对象为例:

    一个MFC窗口对象是一个C++ CWnd类(或派生类)的实例,是程序直接创建的。在程序执行中它随着窗口类构造函数的调用而生成,随着析构函数的调用而消失。而Windows窗口则是Windows系统的一个内部数据结构的实例,由一个“窗口句柄”标识,Windows系统创建它并给它分配系统资源。Windows窗口在MFC窗口对象创建之后,由CWnd类的Create成员函数创建,“窗口句柄”保存在窗口对象的m_hWnd成员变量中。Windows窗口可以被一个程序销毁,也可以被用户的动作销毁

    (1)从数据结构上比较

    MFC Object是相应C++类的实例,这些类是MFC或者程序员定义的;

    Windows Object是Windows系统的内部结构,通过一个句柄来引用;

    MFC给这些类定义了一个成员变量来保存MFC Object对应的Windows Object的句柄。对于设备描述表CDC类,将保存两个HDC句柄。

    (2)从层次上比较

    MFC Object是高层的,Windows Object是低层的;

    MFC Object封装了Windows Object的大部分或全部功能,MFC Object的使用者不需要直接应用Windows Object的HANDLE(句柄)使用Win32 API,代替它的是引用相应的MFC Object的成员函数

    (3)从创建上比较

    MFC Object通过构造函数由程序直接创建;Windows Object由相应的SDK函数创建。

    MFC中,使用这些MFC Object,一般分两步:首先,创建一个MFC Object,或者在STACK中创建,或者在HEAP中创建,这时,MFC Object的句柄实例变量为空,或者说不是一个有效的句柄。然后,调用MFC Object的成员函数创建相应的Windows Object,MFC的句柄变量存储一个有效句柄。

    CDC(设备描述表类)的创建有所不同

    当然,可以在MFC Object的构造函数中创建相应的Windows对象,MFC的GDI类就是如此实现的,但从实质上讲,MFC Object的创建和Windows Object的创建是两回事。

    (4)从转换上比较

    可以从一个MFC Object得到对应的Windows Object的句柄;一般使用MFC Object的成员函数GetSafeHandle得到对应的句柄。

    可以从一个已存在的Windows Object创建一个对应的MFC Object; 一般使用MFC Object的成员函数Attach或者FromHandle来创建,前者得到一个永久性对象,后者得到的可能是一个临时对象。

    (5)从使用范围上比较

    MFC Object对系统的其他进程来说是不可见、不可用的;而Windows Object一旦创建,其句柄是整个Windows系统全局的。一些句柄可以被其他进程使用。典型地,一个进程可以获得另一进程的窗口句柄,并给该窗口发送消息。

    对同一个进程的线程来说,只可以使用本线程创建的MFC Object,不能使用其他线程的MFC Object。

    (6)从销毁上比较

    MFC Object随着析构函数的调用而消失;但Windows Object必须由相应的Windows系统函数销毁

    设备描述表CDC类的对象有所不同,它对应的HDC句柄对象可能不是被销毁,而是被释放。

    当然,可以在MFC Object的析构函数中完成Windows Object的销毁,MFC Object的GDI类等就是如此实现的,但是,应该看到:两者的销毁是不同的。

    每类Windows Object都有对应的MFC Object,下面用表格的形式列出它们之间的对应关系,如下表所示:

    描述

    Windows句柄 MFC Object

    窗口

    HWND CWnd and CWnd-derived classes
    设备上下文

    HDC

    CDC and CDC-derived classes
    菜单

    HMENU

    CMenu

    HPEN

    CGdiObject类,CPen和CPen-derived classes
    刷子

    HBRUSH

    CGdiObject类,CBrush和CBrush-derived classes
    字体

    HFONT

    CGdiObject类,CFont和CFont-derived classes
    位图

    HBITMAP

    CGdiObject类,CBitmap和CBitmap-derived classes
    调色板

    HPALETTE

    CGdiObject类,CPalette和CPalette-derived classes
    区域 HRGN

    CGdiObject类,CRgn和CRgn-derived classes

    图像列表 HimageLIST

    CimageList和CimageList-derived classes

    套接字 SOCKET

    CSocket,CAsynSocket及其派生类

    从广义上来看,文档对象和文件可以看作一对MFC Object和Windows Object,分别用CDocument类和文件句柄描述。

    Windows Object:用SDK的Win32 API编写各种Windows应用程序,有其共同的规律首先是编写WinMain函数,编写处理消息和事件的窗口过程WndProc,在WinMain里头注册窗口(Register Window),创建窗口,然后开始应用程序的消息循环。

    MFC应用程序也不例外,因为MFC是一个建立在SDK API基础上的编程框架。对程序员来说所不同的是:一般情况下,MFC框架自动完成了Windows登记、创建等工作。

    2.MFC 窗口对Windows 窗口的封装

    (1)Windows的注册

    一个应用程序在创建某个类型的窗口前,必须首先注册该“窗口类”(Windows Class)。注意,这里不是C++类的类。Register Window把窗口过程、窗口类型以及其他类型信息和要登记的窗口类关联起来

    “窗口类”的数据结构

    “窗口类”是Windows系统的数据结构,可以把它理解为Windows系统的类型定义,而Windows窗口则是相应“窗口类”的实例。Windows使用一个结构来描述“窗口类”,其定义如下:

    typedef struct _WNDCLASSEX {

      UINT cbSize; //该结构的字节数

      UINT style; //窗口类的风格

      WNDPROC lpfnWndProc; //窗口过程

      int cbClsExtra;

      int cbWndExtra;

      HANDLE hInstance; //该窗口类的窗口过程所属的应用实例

      HICON hIcon; //该窗口类所用的像标

      HCURSOR hCursor; //该窗口类所用的光标

      HBRUSH hbrBackground; //该窗口类所用的背景刷

      LPCTSTR lpszMenuName; //该窗口类所用的菜单资源

      LPCTSTR lpszClassName; //该窗口类的名称

      HICON hIconSm; //该窗口类所用的小像标

      } WNDCLASSEX;

    从“窗口类”的定义可以看出,它包含了一个窗口的重要信息,如窗口风格、窗口过程、显示和绘制窗口所需要的信息,等等。关于窗口过程,将在后面消息映射等有关章节作详细论述。Windows系统在初始化时,会注册(Register)一些全局的“窗口类”,例如通用控制窗口类。应用程序在创建自己的窗口时,首先必须注册自己的窗口类。在MFC环境下,有几种方法可以用来注册“窗口类”,下面分别予以讨论。

    ①调用AfxRegisterClass注册

    AfxRegisterClass函数是MFC全局函数。AfxRegisterClass的函数原型:

    BOOL AFXAPI AfxRegisterClass(WNDCLASS *lpWndClass);

    参数lpWndClass是指向WNDCLASS结构的指针,表示一个“窗口类”。

    首先,AfxRegisterClass检查希望注册的“窗口类”是否已经注册,如果是则表示已注册,返回TRUE,否则,继续处理。

    接着,调用::RegisterClass(lpWndClass)注册窗口类;

    然后,如果当前模块是DLL模块,则把注册“窗口类”的名字加入到模块状态的域m_szUnregisterList中。该域是一个固定长度的缓冲区,依次存放模块注册的“窗口类”的名字(每个名字是以“ ”结尾的字符串)。之所以这样做,是为了DLL退出时能自动取消(Unregister)它注册的窗口类。

    最后,返回TRUE表示成功注册。

    ②调用AfxRegisterWndClass注册

    AfxRegisterWndClass函数也是MFC全局函数。AfxRegisterWndClass的函数原型:

    LPCTSTR AFXAPI AfxRegisterWndClass(UINT nClassStyle,HCURSOR hCursor, HBRUSH hbrBackground, HICON hIcon);

    参数1指定窗口类风格;参数2、3、4分别指定该窗口类使用的光标、背景刷、像标的句柄,缺省值是0。

    此函数根据窗口类属性动态地产生窗口类的名字,然后,判断是否该类已经注册,是则返回窗口类名;否则用指定窗口类的属性(窗口过程指定为缺省窗口过程),调用AfxRegisterCalss注册窗口类,返回类名。

    ③调用::RegisterWndClass注册

    直接调用Win32的窗口注册函数::RegisterWndClass注册“窗口类”,这样做有一个缺点:如果是DLL模块,这样注册的“窗口类”在程序退出时不会自动的被取消注册(Unregister)。所以必须记得在DLL模块退出时取消它所注册的窗口类。

    子类化   子类化(Subclass)一个“窗口类”,可自动地得到它的“窗口类”属性。

    (2)MFC窗口类CWnd

    在Windows系统里,一个窗口的属性分两个地方存放:一部分放在“窗口类”里头,如上所述的在注册窗口时指定;另一部分放在Windows Object本身,如:窗口的尺寸,窗口的位置(X,Y轴),窗口的Z轴顺序,窗口的状态(ACTIVE,MINIMIZED,MAXMIZED,RESTORED…),和其他窗口的关系(父窗口,子窗口…),窗口是否可以接收键盘或鼠标消息,等等。

    为了表达所有这些窗口的共性,MFC设计了一个窗口基类CWnd。有一点非常重要,那就是CWnd提供了一个标准而通用的MFC窗口过程,MFC下所有的窗口都使用这个窗口过程。至于通用的窗口过程却能为各个窗口实现不同的操作,那就是MFC消息映射机制的奥秘和作用了。

    CWnd提供了一系列成员函数,或者是对Win32相关函数的封装,或者是CWnd新设计的一些函数。这些函数大致如下。

    窗口创建函数

    这里主要讨论函数Create和CreateEx。它们封装了Win32窗口创建函数::CreateWindowEx。Create的原型如下:

    BOOL CWnd::Create(LPCTSTR lpszClassName,

      LPCTSTR lpszWindowName, DWORD dwStyle,

      const RECT& rect,

      CWnd* pParentWnd, UINT nID,

      CCreateContext* pContext)

    Create是一个虚拟函数,用来创建子窗口(不能创建桌面窗口和POP UP窗口)。CWnd的基类可以覆盖该函数,例如边框窗口类等覆盖了该函数以实现边框窗口的创建,视类则使用它来创建视窗口。

    Create调用了成员函数CreateEx。CWnd::CreateEx的原型如下

    BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,

      LPCTSTR lpszWindowName, DWORD dwStyle,

      int x, int y, int nWidth, int nHeight,

      HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)

    CreateEx有11个参数,它将调用::CreateWindowEx完成窗口的创建,这11个参数对应地传递给::CreateWindowEx。参数指定了窗口扩展风格、“窗口类”、窗口名、窗口大小和位置、父窗口句柄、窗口菜单和窗口创建参数。

    窗口创建时发送WM_CREATE消息,消息参数lParam指向一个CreateStruct结构的变量,该结构有11个域,Windows使用和CreateEx参数一样的内容填充该变量。

    窗口销毁函数

    DestroyWindow函数, 销毁窗口     

    PostNcDestroy( ),销毁窗口后调用,虚拟函数

    用于设定、获取、改变窗口属性的函数

    SetWindowText(CString tiltle) 设置窗口标题

    GetWindowText() 得到窗口标题

    SetIcon(HICON hIcon, BOOL bBigIcon);设置窗口像标

    GetIcon( BOOL bBigIcon ) ;得到窗口像标

    GetDlgItem( int nID);得到窗口类指定ID的控制子窗口

    GetDC(); 得到窗口的设备上下文

    SetMenu(CMenu *pMenu); 设置窗口菜单

    GetMenu();得到窗口菜单

    。。。

    用于完成窗口动作的函数,用于更新窗口,滚动窗口,等等。一部分成员函数设计成或可重载(Overloaded)函数,或虚拟(Overridden)函数,或MFC消息处理函数。这些函数或者实现了一部分功能,或者仅仅是一个空函数。如:

    有关消息发送的函数

    SendMessage( UINT message,WPARAM wParam = 0, LPARAM lParam = 0 );给窗口发送发送消息,立即调用方式

    PostMessage(( UINT message,WPARAM wParam = 0, LPARAM lParam = 0 );给窗口发送消息,放进消息队列

    有关改变窗口状态的函数:

    MoveWindow( LPCRECT lpRect, BOOL bRepaint = TRUE );移动窗口到指定位置

    ShowWindow(BOOL );显示窗口,使之可见或不可见

    实现MFC消息处理机制的函数:

    virtual LRESULT WindowProc( UINT message, WPARAM wParam, LPARAM lParam ); 窗口过程,虚拟函数

    virtual BOOL OnCommand( WPARAM wParam, LPARAM lParam );处理命令消息

    消息处理函数:

    OnCreate( LPCREATESTRUCT lpCreateStruct );MFC窗口消息处理函数,窗口创建时由MFC框架调用

    OnClose();MFC窗口消息处理函数,窗口创建时由MFC框架调用

    CWnd的导出类是类型更具体、功能更完善的窗口类,它们继承了CWnd的属性和方法,并提供了新的成员函数(消息处理函数、虚拟函数、等等)

    3.在MFC下创建一个窗口对象

    MFC下创建一个窗口对象分两步,首先创建MFC窗口对象,然后创建对应的Windows窗口。在内存使用上,MFC窗口对象可以在栈或者堆(使用new创建)中创建。具体表述如下:

    创建MFC窗口对象。通过定义一个CWnd或其派生类的实例变量或者动态创建一个MFC窗口的实例,前者在栈空间创建一个MFC窗口对象,后者在堆空间创建一个MFC窗口对象。

    在MFC中,还提供了一种动态创建技术。动态创建的过程实际上也如上所述分两步,只不过MFC使用这个技术是由框架自动地完成整个过程的。通常框架窗口、文档框架窗口、视使用了动态创建。

    在Windows窗口的创建过程中,将发送一些消息,如:

    在创建了窗口的非客户区(Nonclient area)之后,发送消息WM_NCCREATE;

    在创建了窗口的客户区(client area)之后,发送消息WM_CREATE;

    窗口的窗口过程在窗口显示之前收到这两个消息。

    如果是子窗口,在发送了上述两个消息之后,还给父窗口发送WM_PARENATNOTIFY消息。其他类或风格的窗口可能发送更多的消息,具体参见SDK开发文档。

    4.MFC窗口的使用

    MFC提供了大量的窗口类,其功能和用途各异。程序员应该选择哪些类来使用,以及怎么使用他们呢?

    直接使用MFC提供的窗口类或者先从MFC窗口类派生一个新的C++类然后使用它,这些在通常情况下都不需要程序员提供窗口注册的代码。是否需要派生新的C++类,视MFC已有的窗口类是否能满足使用要求而定。派生的C++类继承了基类的特性并改变或扩展了它的功能,例如增加或者改变对消息、事件的特殊处理等。

    主要使用或继承以下一些MFC窗口类:

      框架类CFrameWnd,CMdiFrameWnd;

      文档框架CMdiChildWnd;

      视图CView和CView派生的有特殊功能的视图如:列表CListView,编辑CEditView,树形列表CTreeView,支持RTF的CRichEditView,基于对话框的视CFormView等等。

  • 相关阅读:
    openfire 介绍安装使用
    android rabbitMQ
    转:socket编程在windows和linux下的区别
    socklen_t在windows和linux平台下的头文件定义
    libevent入门教程
    libevent安装
    《RabbitMQ in action》
    RabbitMQ安装和配置
    node.js模块之http模块
    node.js模块之Buffer模块
  • 原文地址:https://www.cnblogs.com/Romi/p/2353296.html
Copyright © 2011-2022 走看看