091003置换DefWindowProc

注册窗口类除了提供窗口函数外,还指定该窗口的一些 外观,如是否有标题条,窗口缺省背景等等。在MFC框架中,有框窗、视图和控制条(CControlBar)等,它们除了操作行为不同外,外观等也不相 同,所以MFC注册了几种缺省的窗口类。在MFC中,有一个全局函数AfxEndDeferRegisterClass(LONG fToRegister),它用来注册MFC预定义的窗口类,包括同框窗、视图所对应的窗口类。由于它的代码占的篇幅很长,而且实现也很简单,所以就不列 出它的代码了,如果你有兴趣,可以在wincore.cpp中找到它的实现代码。

  挂接窗口函数

  如果你考察过AfxEndDeferRegisterClass()的实现代码,你会对一行代码感到迷惑,下面列出的是AfxEndDeferRegisterClass()的部分代码,带阴影部分的是那一行令人迷惑的代码:

  BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)

  {

   。。。。。。

   wndcls.lpfnWndProc = DefWindowProc;

   。。。。。。

  }

 

   MFC将所有预定义的窗口类的窗口函数都设置成DefWindowProc。大家都知道,DefWindowProcWindow下为一般窗口提供消 息缺省处理的API,它肯定不是应用程序所需要的窗口函数,所以,MFC肯定在某个地方置换了它,置换DefWindowProc的代码在哪里呢?

 

   前面说过,在MFC中创建窗口时是用CWnd的两个虚拟函数Create()CreateEx()Create()是通过调用CreateEx() 实现的,所以最终窗口的创建都要归结到CreateEx()函数上。因此,我们可以推断MFCCreateEx()中置换了 DefWindowProc。为了证实这一点,看看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)

  {

   // allow modification of several common create parameters

   CREATESTRUCT cs;

   cs.dwExStyle = dwExStyle;

   cs.lpszClass = lpszClassName;

   cs.lpszName = lpszWindowName;

   cs.style = dwStyle;

   cs.x = x;

   cs.y = y;

   cs.cx = nWidth;

   cs.cy = nHeight;

   cs.hwndParent = hWndParent;

   cs.hMenu = nIDorHMenu;

   cs.hInstance = AfxGetInstanceHandle();

   cs.lpCreateParams = lpParam;

   if (!PreCreateWindow(cs)){

    PostNcDestroy();

    return FALSE;

   }

   AfxHookWindowCreate(this);

   HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,

   cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,

   cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);

  if (!AfxUnhookWindowCreate()) PostNcDestroy(); // cleanup if CreateWindowEx fails too soon

   if (hWnd == NULL) return FALSE;

   ASSERT(hWnd == m_hWnd); // should have been set in send msg hook

   return TRUE;

  }

 

从上面的代码看不出任何显式的置换DefWindowProc的代码,其实,它隐藏在AfxHookWindowCreate(this)之中,顺藤摸瓜,再看看AfxHookWindowCreate()的代码:

  void AFXAPI AfxHookWindowCreate(CWnd* pWnd)

  {

   _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();

   if (pThreadState->m_pWndInit == pWnd)

   return;

   if (pThreadState->m_hHookOldCbtFilter == NULL)

   {

    pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT,

    _AfxCbtFilterHook, NULL, ::GetCurrentThreadId());

    if (pThreadState->m_hHookOldCbtFilter == NULL)

    AfxThrowMemoryException();

    }

   ASSERT(pThreadState->m_hHookOldCbtFilter != NULL);

   ASSERT(pWnd != NULL);

   ASSERT(pWnd->m_hWnd == NULL); // only do once

   ASSERT(pThreadState->m_pWndInit == NULL); // hook not already in progress

   pThreadState->m_pWndInit = pWnd;

  }

AfxHookWindowCreate ()设置了一个线程级的CBT Hook,该Hook的入口地址为_AfxCbtFilterHook_AfxCbtFilterHook是一个全局的MFC函数, _AfxCbtFilterHook通过调用SetWindowLong()AfxWndProc()的入口地址置换掉DefWindowProc

 

  小结:

  在MFC中,创建一个窗口的过程是:

    1、生成一个对应窗口类的对象

    2、调用该对象的Create()CreateEx()方法

    3、在CreateEx()中(Create()是调用CreateEx()实现的),先调用虚拟函数PreCreateWindow(),让应用程序有 一个改变窗口行为的机会,同时,在PreCreateWindow中,还作了一件很重要的事情,就是如果指向窗口类的字符串指针为NULL,就调用 AfxDeferRegisterClass()注册一个合适的窗口类,将该注册的窗口类作为创建窗口的类型参数。 AfxDeferRegisterClass()就是AfxEndDeferRegisterClass(),后者根据参数注册相应的窗口类,并将 DefWindowProc作为该窗口类的临时窗口函数。

 

    4CreateEx()在调用CreateWindowEx()创建真正的窗口对象之前,设置一个线程级的CBT Hook,该hook在窗口创建完成后被调用,MFChook函数中调用SetWindowLong()将该窗口的窗口函数置换成 AfxWndProc

 

  2、从Window的角度看,任何一个MFC应用程序都只有一个窗口函数AfxWndProc

 

   3AfxWndProc的作用是截获所有的发送给窗口消息,并将这些消息发送给相应的窗口对象的窗口函数WindowProc处理,所以它实质上是一 个窗口消息分发器,注意,非窗口消息不被AfxWndProc所分发,它们在AfxWndProc被调用之前就被CWinThread:: PreTranslateMessage()处理过了。

 

  4、同PreTranslateMessage()不同的地方在于,AfxWndProc()能够截获所有的来自于消息队列的和非消息队列的窗口消息(如调用SendMessage()发送的窗口消息)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值