zoukankan      html  css  js  c++  java
  • 消息映射的转变

    转载自:http://www.yesky.com/20010202/157454.shtml

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

      BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)

      {

       。。。。。。

       wndcls.lpfnWndProc = DefWindowProc;

       。。。。。。

      }

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

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

      小结

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

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

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

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

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

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

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

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

  • 相关阅读:
    【BZOJ】2729: [HNOI2012]排队
    【BZOJ】2734: [HNOI2012]集合选数
    【BZOJ】3573: [Hnoi2014]米特运输
    【BZOJ】4008: [HNOI2015]亚瑟王
    【BZOJ】[HNOI2015]菜肴制作
    数论六·模线性方程组
    数论五·欧拉函数
    黄金矿工
    数论四·扩展欧几里德
    数论三·约瑟夫问题
  • 原文地址:https://www.cnblogs.com/wang-can/p/3310873.html
Copyright © 2011-2022 走看看