MFC六大机制之二:窗口创建机制

我们也通过一个简单的MFC程序进行研究

1.建一个win32简单应用程序,(因为是不是MFC程序取决于调没调MFC函数)

2. 删除入口函数,只留下#include "stdafx.h"
3.将stdafx.h中的头文件 <windows.h> 更改为 <afxwin.h>。
4.Project-->Settings菜单项中设置使用MFC库。 

5.编写代码

// MFCCreate.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
class CMyFrameWnd: public CFrameWnd
{
public:
	virtual LRESULT WindowProc(UINT message,WPARAM wParam,LPARAM lParam);
};

LRESULT CMyFrameWnd::WindowProc(UINT message,WPARAM wParam,LPARAM lParam)
{
	switch(message)
	{
	case WM_CREATE:
		AfxMessageBox("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,"MFCCreate");
	m_pMainWnd = pFrame;
	pFrame->ShowWindow(SW_SHOW);
	pFrame->UpdateWindow();
	return TRUE;
}
是怎么运行起来的???我们来通过加断点跟进微软内部函数来分析

在pFrame->Create(NULL,"MFCCreate");这行加断点,f11进入到create函数,写出伪代码

_AFX_THREAD_STATE ccc;//全局变量(当前程序线程信息)

CMyFrameWnd *pFrame = new CMyFrameWnd;
pFrame->Create( NULL, "MFCCreate" )
 //函数内部this为 pFrame(自己new的框架类对象地址)
{
  加载菜单资源
  CreateEx(..,NULL...)//函数内部this为 pFrame
  {
    CREATESTRUCT cs;
    .....
    cs.lpszClass = NULL;//这么赋值肯定有问题,但下面会更改
    cs.hInstance = AfxGetInstanceHandle();//全局函数,可以获取winmain函数的第一个参数即实例

句柄
    .....
    PreCreateWindow(cs)//注册窗口类 和 更改 cs为NULL的成员lpszClass
    {
       AfxDeferRegisterClass(...)
       {
         WNDCLASS wndcls;//和CreateWindowEx的12个参数一一对应
         wndcls.lpfnWndProc = DefWindowProc;//缺省函数作为窗口处理函数,这么做,自己就不能

处理消息了,而且退不出消息循环,所以用它不行,但下面钩子处理函数中修改
         .....
         _AfxRegisterWithIcon(&wndcls,"AfxFrameOrView42sd" )
         {
           &wndcls->lpszClassName = "AfxFrameOrView42sd";
           AfxRegisterClass(&wndcls)
           {
             ::RegisterClass(&wndcls);
               //注册窗口类 类名称"AfxFrameOrView42sd"。
           }
         }
       }
       cs.lpszClass = "AfxFrameOrView42sd"; //lpszClass在这行被修改
    }
    AfxHookWindowCreate(pFrame)//参数为自己new的框架类对象地址
    {
      _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
            //获取全局变量 &ccc
      ::SetWindowsHookEx( WH_CBT...);
            //利用WIN32 API 函数在程序中埋下一个类型为
            //WH_CBT钩子
      pThreadState->m_pWndInit = pFrame;
       //将自己new的框架类对象地址(pFrame)保存到 ccc中
    }
    ::CreateWindowEx(..);//创建窗口,只要此函数一旦执行成功,WM_CREATE消息立即被钩子勾到钩

子处理函数中。
  }  
}

**********************************************************
钩子处理函数
_AfxCbtFilterHook(...,wParam,..)
{
  _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
       //获取全局变量 &ccc
  CWnd* pWndInit = pThreadState->m_pWndInit;
       //重新获取自己new的框架类对象地址pFrame<=>pWndInit
  HWND hWnd = (HWND)wParam;
       //获取刚刚创建成功 窗口句柄
  pWndInit->Attach(hWnd)//函数内部this为pFrame<==>pWndInit
  {
    CHandleMap* pMap = afxMapHWND(TRUE)
    {
      AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
           //获取全局变量 &bbb
      pState->m_pmapHWND = new CHandleMap(...);
           //将new出来的映射类对象地址保存全局变量 bbb中
      return pState->m_pmapHWND;
    }
    pMap->SetPermanent(m_hWnd = hWndNew, pFrame)
     //函数内部this为pMap(映射类对象地址)
    {
      m_permanentMap[hWndNew] = pFrame;
    }
  }
  WNDPROC afxWndProc = AfxGetAfxWndProc();
     //获取 AfxWndProc函数的地址
  ::SetWindowLong(hWnd, GWL_WNDPROC,(DWORD)afxWndProc);
     //利用WIN32 API 函数将hWnd的处理函数更改为
     // AfxWndProc(真正的窗口处理函数)
}

总结上边的伪代码我们可以得到窗口创建机制的原理:

1 加载菜单
2 调用CreateEx成员函数,注册窗口类/创建窗口
2.1 调用PreCreateWindow成员函数 设计并注册窗口类
         调用AfxDeferRegisterClass全局函数设计窗口类:
         调用 AfxRegisterClass全局函数,在这个函中调用WIN32 API 函数::RegisterClass注册
     2.2 调用AfxHookWindowCreate函数
         利用::SetWindowsHookEx在程序中埋下一个类型WH_CBT的钩子。
         将自己new的框架类对象地址(pFrame)保存到当前程序线程信息中。
     2.3 调用WIN32 API 函数 ::CreateWindowEx创建窗口。  此函数一旦执行成功,马上执行钩子处理函数。
3 钩子处理函数
     3.1 将 窗口句柄 和 框架类对象 建立一对一绑定关系
     3.2 将 窗口处理函数 更改为  AfxWndProc(真正的窗口处理函数)


思考:

1.AfxGetInstanceHandle()全局函数,可以获取winmain函数的第一个参数即实例句柄。

2.上边的出的结论AfxWndProc才是真正的窗口处理函数,为什么我们写的WindowProc它处理消息???

答:因为我们自己写的WindowProc最终会被AfxWndProc调用。

分析:通过断点调试,现在case WM_CREATE:这行加断点,用调用堆栈的方法进入AfxCallWndProc函数中,写出伪代码

AfxWndProc(...)
{
  CWnd* pWnd = CWnd::FromHandlePermanent(hWnd)
  {
    CHandleMap* pMap = afxMapHWND()
    {
      AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
           //获取全局变量 &bbb
      return pState->m_pmapHWND;
           //返回 保存在bbb中的上面new的 映射类对象地址
    }
    CWnd *pWnd = (CWnd*)pMap->LookupPermanent(hWnd)
           //函数this指针为pMap(映射类对象地址)
    {
      return m_permanentMap[hWnd];
    }
    return pWnd;
  }
  AfxCallWndProc(pWnd..)//参数的pWnd<==>pFrame
  {
    pWnd->WindowProc(...)
    {
       //回到自己代码
    }
  }
}
事实上 AfxWndProc(窗口处理函数)处理消息的执行过程就是:

   1 利用消息所属窗口句柄,找到和它绑定在一起框架类对象地址(pFrame)。

   2 利用框架类对象地址(pFrame)调用框架类的成员虚函数(WindowProc),完成消息的处理。




  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值