zoukankan      html  css  js  c++  java
  • 2.MFC基础(二)窗口创建

    一、窗口的创建

     1.加载菜单

     2.调用CreateEx函数,设计并注册窗口类,创建窗口

      (1)调用PreCreateWindow函数,设计窗口并调用win32API函数::RegisterClass注册窗口类

      (2)调用AfxHookWindowCreate函数

         利用win32API函数GetWindowHookEx在程序中埋下一个类型为WH_CBT的钩子

         将自己new的框架类对象地址(pFrame)保存到当前程序线程信息中

      (3)调用win32API函数::CreateWindowEx创建窗口,此函数一旦执行成功立即执行钩子处理函数

     3.钩子处理函数

      (1)将窗口句柄和自己new的框架类对象(pFrame)建立一对一的绑定关系

          pFrame->m_hWnd = hWnd

          pMap->m_permanentMap[hWnd] = pFrame ;

      (2)利用win32API函数SetWindowLong将窗口处理函数更改为AfxWndProc(正真的窗口处理函数)

    二、消息处理

     1.当消息产生后进入AfxWndProc函数处理

     2.找到和窗口句柄(hWnd)绑定在一起的框架类对象地址(pFrame)

     3.利用pFrame调用框架类的成员虚函数WindowProc完成消息处理

     补充://埋钩子

        HHOOK SetWindowsHookEx( int               idHook,           //钩子类型(WH_CBT)

                                                         HOOKPROC   lpfn,               //钩子处理函数

                                                         HINSTANCE   hMod,            //应用程序实例句柄,为NULL,所有进程都钩

                                                         DWORD        dwThreadId);  //线程ID,为0,所有线程都钩

        //钩子处理函数

        LRESULT  CALLBACK  CBTProc( int            nCode,    //钩子码(HCBT_CREATEWND)

                                                             WPARAM   wParam,  //附带信息(刚创建成功的窗口句柄)

                                                             LPARAM     lParam);  //附带信息

        //更改窗口处理函数

        LONG  SetWindowLong( HWND  hWnd,           //窗口句柄

                                                   int       nIndex,          //GWL_WNDPROC

                                                   LONG   dwNewLong);  //新的窗口处理函数

      伪代码:

        CMyFrameWnd  *pFrame  =  new  CMyFrameWnd;
        pFrame->Create( NULL, L"MFCCreate" )  //函数内部this为pFrame

        {

          //先加载菜单

          //创建窗口

          CreateEx( ..., NULL, ... )  //函数内部this为pFrame

          {      

            CREATESTRUCT cs;  //cs中就是CreateWindowEx中的12个参数
            ......
            cs.lpszClass = NULL;   //窗口类怎么可能为NULL????????

            ......

            cs.hInstance = AfxGetInstanceHandle();  //拿到WinMain的第一个参数

            ......

            PreCreateWindow( cs )

            {

              if  ( cs.lpszClass  ==  NULL )

              {            

                AfxDeferRegisterClass( ... ) 

                {

                  WNDCLASS  wndcls;
                  ......            
                  wndcls.lpfnWndProc  =  DefWindowProc;  //我们怎么处理消息????? 
                  ......

                  _AfxRegisterWithIcon( &wndcls, L"AfxFrameOrView120sud", ... )

                  {

                    &wndcls->lpszClassName = L"AfxFrameOrView120sud";

                    ......

                    AfxRegisterClass( &wndcls )

                    {

                      RegisterClass( &wndcls );  //注册窗口类

                    }

                  }

                }
                cs.lpszClass  =  _afxWndFrameOrView;  // L"AfxFrameOrView120sud"

              }

            }

            AfxHookWindowCreate( pFrame ) 

            {      

              _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData( );  //获取全局变量(当前程序线程信息)的地址

              //利用win32API函数在程序中埋下一个类型为WH_CBT的钩子

              ::SetWindowsHookEx( WH_CBT, _AfxCbtFilterHook, NULL, ::GetCurrentThreadId( ) );

              pThreadState->m_pWndInit = pFrame;  //将pFrame(自己new的框架类对象地址)保存到全局变量中

            }

            ::CreateWindowEx( ... );  //此函数一旦执行完成,WM_CREATE消息立即被钩子钩走(钩到钩子处理函数中,_AfxCbtFilterHook)

          }

        }

      *************************************************************************************************************

      //钩子处理函数

      LRESULT  CALLBACK  _AfxCbtFilterHook( int  code, WPARAM  wParam, LPARAM  lParam )

      {

        _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData( );  //获取全局变量(当前程序线程信息)的地址

        CWnd* pWndInit = pThreadState->m_pWndInit;  //从当前程序线程信息重新获取pFrame

        HWND hWnd = (HWND)wParam;  //获取刚创建的窗口句柄

        pWndInit->Attach( hWnd )  //函数内部this为pFrame

        {

          CHandleMap* pMap = afxMapHWND( TRUE )

          {

            AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState( );  //获取全局变量的地址

            pState->m_pmapHWND = new CHandleMap( ... );  //new了一个映射类对象,并将对象地址全局变量的成员中

            return pState->m_pmapHWND;

          }

          pMap->SetPermanent( pFrame->m_hWnd = hWnd, pFrame )  

          {

            //函数内部this指针为pMap(映射类对象地址)

            pMap->m_permanentMap[hWnd] = pFrame ;       

          }

        }  

        WNDPROC afxWndProc = AfxGetAfxWndProc( );  //获取AfxWndProc函数地址

        //利用win32API函数将窗口处理函数更改为AfxWndProc(真正的窗口处理函数)
        oldWndProc = (WNDPROC)SetWindowLongPtr( hWnd, GWLP_WNDPROC, (DWORD_PTR)afxWndProc ); 

      }

      *************************************************************************************************************

      //以WM_CREATE消息为例,查看消息的处理流程

      AfxWndProc( ... )

      {

        CWnd*  pWnd  =  CWnd::FromHandlePermanent( hWnd )   //获取pFrame

        {

          CHandleMap*  pMap  =  afxMapHWND( )  //映射类对象

          {

            AFX_MODULE_THREAD_STATE*  pState =  AfxGetModuleThreadState( );  //获取管局变量

            return  pState->m_pmapHWND;  //返回全局变量的成员(保存了映射类对象)

          }

          pWnd  =  (CWnd*)pMap->LookupPermanent( hWnd )  //函数内部this为映射类对象地址

          {

            return  (CObject*)m_permanentMap.GetValueAt( (LPVOID)hWnd ); //获取下标为窗口句柄的值,即pFrame

          }

          return  pWnd;  //返回pFrame

        }

        return  AfxCallWndProc( pWnd,  hWnd,  nMsg,  wParam,  lParam )  //参数的pWnd即为pFrame

        {

          lResult  =  pWnd->WindowProc( nMsg,  wParam,  lParam );  //调用虚函数,回到自己的代码

        }

      }

      相关代码:

    #include "stdafx.h"
    #include "T09_MFCCreate.h"
    
    class CMyFrameWnd : public CFrameWnd 
    {
    public:
        virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
    };
    
    //AfxWndProc(真正的窗口处理函数)会调用WindowProc
    LRESULT CMyFrameWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
    {
        //此函数的this为pFram    
        PAINTSTRUCT ps = { 0 };
        HDC hdc;
        switch (message)
        {
        case WM_PAINT:        
            hdc = ::BeginPaint((HWND)this->m_hWnd, &ps);
            ::TextOut(hdc, 100, 100, L"hello", 5);
            ::EndPaint((HWND)m_hWnd, &ps);
            break;
        case WM_CREATE:
            AfxMessageBox(L"WM_CREATE");
            break;
        }
        return CFrameWnd::WindowProc(message, wParam, lParam);
    }
    
    class CMyWinApp : public CWinApp
    {
    public:
        virtual BOOL InitInstance();
    };
    
    CMyWinApp theApp;
    
    BOOL CMyWinApp::InitInstance()
    {
        CMyFrameWnd *pFrame = new CMyFrameWnd;
        pFrame->Create(NULL, L"MFCCreate");
        m_pMainWnd = pFrame;
        pFrame->ShowWindow(SW_SHOW);
        pFrame->UpdateWindow();
        return TRUE;
    }

      运行结果:

      

  • 相关阅读:
    elasticsearch配置文件
    elk+filebeat源码安装
    logstash配置文件
    kibana配置文件
    filebeat配置文件
    老年人和棒子(李敖)
    Linux下傻瓜式安装配置V_2_r_a_y
    【有关学习Q国的自动化工具的学习思路】
    有关在使用aireplay-ng处理5Ghz频段的wifi时出现“No such Bssid available”的解决方法
    springboot整合日志logback
  • 原文地址:https://www.cnblogs.com/csqtech/p/5678504.html
Copyright © 2011-2022 走看看