• 【转载】MFC怎么封装CreateWindow


    原文:http://blog.csdn.net/weiwenhp/article/details/8796337

    我们知道Win32中创建一个窗口的流程就是先注册一个WNDCLASSEX(指定了窗口的回调函数),然后通过CreateWindow这函数正式创建一个窗口.然后就是一个while循环获取消息,分派消息.所有这些都是在一个main函数中完成.相当清晰明了.而MFC是封装了上面Win32的流程,变得极为复杂了.

    简单的创建Win32与MFC窗口见:http://blog.csdn.net/weiwenhp/article/details/7960243

    MFC的Main函数跑哪里了见:http://blog.csdn.net/weiwenhp/article/details/8455471

    现在主要来讲下MFC封装的具体细节

    1.怎么封装注册窗口, RegisterClass

    2.怎么封装指定回调函数.windowClass.lpfnWndProc

    3.怎么封装创建出来一个窗口的.CreateWindow

    CWnd封装了RegisterClass,CreateWindow,lpfnWndProc

    创建窗口的函数CreateWindow在MFC中被封装到了CWnd中,所以凡是继承自CWnd的类都可以生成窗口嘛.

    当然了准确的说应该是根据不同的类型调用不同的函数,CWnd也封装了CreateDialog和MessageBox.

    那么继承自CDialog的类最终调用的是CreateDialog

    以CFrameWnd为例说明怎么封装的(它继承自CWnd).

    (1) m_pMainWnd = new CMyFrameWnd;//实例化类CMyFrameWnd,调用它的构造函数

    (2) CMyFrameWnd::CMyFrameWnd(){

        Create(....); //该虚函数没被重写,所以调用父类CFrameWnd的Create函数

    }

    (3) BOOL CFrameWnd::Create(.....){  //见MFC源码winfrm.cpp

       //其他代码

       CreateEx(.....); //又是虚函数没改写,于是调用父类CWnd的CreateEx函数

    }

    (4) BOOL CWnd:CreateEx(.....){ //见MFC源码wincore.cpp

        CREATESTRUCT cs;

        //对cs的一系列初始化,这里的CREATESTRUCT跟Win32中的WNDCLASSEX起类似作用,最后它的值会与WNDCLASS的类关联起来的

        PreCreateWindow(cs);  //该虚函数就是作注册窗口的作用.它被CFrameWnd改定了.见第(5)步

       AfxHookWindowCreate(this); //钩子函数,跟窗口回调函数有关

       HWND hWnd = ::AfxCtxCreateWindowEx(.....); //正式创建窗口了,跟CreateWindow的作用一样.

    }

    查看AfxCtxCreateWindowEx的定义

    #define AfxCtxCreateWindowEx AfxCtxCreateWindowExW

    你再选中AfxCtxCreateWindowExW右击Go To Definition会跳转到这(至于是怎么跳过去的就不清楚了,可能编译器编译的时候就把两者关联起来的吧)

    AFX_ISOLATIONAWARE_STATICLINK_FUNC(HWND ,CreateWindowExW,(DWORD dwExStyle,LPCWSTR lpClassName,LPCWSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam),(dwExStyle,lpClassName,lpWindowName,dwStyle,X,Y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam),NULL)

    你终于看到个CreateWindowExW了吧,只比CreateWinow多了后面的ExW,这里的细微区别就不用管了.反正再通过些宏转来转去的结果.它们最终是同一个东东了.只是为了处理宽字符才做些这样的转换了.

    至此终于找着创建窗口CreateWindow怎么被封装了.

    不过还有两个问题没解决.一个是窗口怎么被注册,二个是回调函数怎么被指定的.

    (5)  BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT& cs){ //见MFC源码winfrm.cpp

          //实际上在里没帮太多事,主要是对cs添加些特性,比如style,lpszClass之类的

           AfxDeferRegisterClass(...); //最终调用第(6)步该函数的定义如下

          //#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)

          //而AfxEndDeferRegisterClass的定义见MFC源文件wincore.cpp

    }

    (6) BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister){  //MFC源文件wincore.cpp

        WNDCLASS wndcls; //很激动吧,终于看到跟Win32中相同的东东了吧,
        memset(&wndcls, 0, sizeof(WNDCLASS));   

        wndcls.lpfnWndProc = DefWindowProc; //这里就是默认的回调函数了.Win32中默认回调函数也叫这名了
        wndcls.hInstance = AfxGetInstanceHandle();

        //其他代码

        AfxRegisterClass(&wndcls); //这里就是注册窗口了

    }

    再看AfxRegisterClass的定义

    BOOL AFXAPI AfxRegisterClass(WNDCLASS* lpWndClass){

      AfxCtxRegisterClass(....);

    }

    AfxCtxRegisterClass定义如下

    #define AfxCtxRegisterClass   AfxCtxRegisterClassW

    与AfxCtxRegisterClassW关联的是

    AFX_ISOLATIONAWARE_STATICLINK_FUNC(ATOM ,RegisterClassW,(const WNDCLASSW*lpWndClass),(lpWndClass),0)

    至此注册窗口和回调函数的事也都搞明白了吧.

    不过还有一个问题,上面的回调函数只是默认回调函数.实际上我们代码中经常使用到的回调函数不是这样去用到的.那怎么实现的?跟前面的钩子函数有关.

  • 相关阅读:
    JAVA多线程2 锁
    IE8标准模式下VML不能显示问题
    JAVA多线程1
    JAVA判断32位还是64位,调用不同的DLL
    JNA调用DLL
    如何提高执行力
    httpClient多线程请求
    【NodeJS】安装
    [转载]一个项目涉及到的50个Sql语句(整理版)
    resultMap中的collection集合出现只能读取一条数据的解决方法
  • 原文地址:https://www.cnblogs.com/zhehan54/p/4772030.html
Copyright © 2020-2023  润新知