• 解析 MFC 中的 FromHandle


    MFC 对 Windows API 进行了封装,在很多方面都会提供便利。用 FromHandle 返回零时对象的指针,就可以调用各种类的方法。临时对象会在 OnIdle 中销毁。这里对 FromHandle 的实现原理从源码上进行解析。

    // 
    // 1 
    // 
    CWnd* PASCAL CWnd::FromHandle(HWND hWnd) 
    { 
        CHandleMap* pMap = afxMapHWND(TRUE); //create map if not exist 
        ASSERT(pMap != NULL); 
        CWnd* pWnd = (CWnd*)pMap->FromHandle(hWnd); 
    #ifndef _AFX_NO_OCC_SUPPORT 
        pWnd->AttachControlSite(pMap); 
    #endif 
        ASSERT(pWnd == NULL || pWnd->m_hWnd == hWnd); 
        return pWnd; 
    }
    这是 CWnd 的 FromHandle 方法,大致的意思为从 CHandleMap 中获取临时 CWnd 对象的指针。
    // 
    // 2 
    // 
    CHandleMap* PASCAL afxMapHWND(BOOL bCreate) 
    { 
        AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState(); 
        if (pState->m_pmapHWND == NULL && bCreate) 
        { 
            BOOL bEnable = AfxEnableMemoryTracking(FALSE); 
    #ifndef _AFX_PORTABLE 
            _PNH pnhOldHandler = AfxSetNewHandler(&AfxCriticalNewHandler); 
    #endif
    
            pState->m_pmapHWND = new CHandleMap(RUNTIME_CLASS(CTempWnd), 
                offsetof(CWnd, m_hWnd)); 
    #ifndef _AFX_PORTABLE 
            AfxSetNewHandler(pnhOldHandler); 
    #endif 
            AfxEnableMemoryTracking(bEnable); 
        } 
        return pState->m_pmapHWND; 
    }
    再看
    #define offsetof(s,m)   (size_t)&(((s *)0)->m)
    继续
    // 
    // 3 
    // 
    CObject* CHandleMap::FromHandle(HANDLE h) 
    { 
        ASSERT(m_pClass != NULL); 
        ASSERT(m_nHandles == 1 || m_nHandles == 2);
        if (h == NULL) 
            return NULL;
        CObject* pObject = LookupPermanent(h); 
        if (pObject != NULL) 
            return pObject;   // return permanent one 
        else if ((pObject = LookupTemporary(h)) != NULL) 
        { 
            HANDLE* ph = (HANDLE*)((BYTE*)pObject + m_nOffset); 
            ASSERT(ph[0] == h || ph[0] == NULL); 
            ph[0] = h; 
            if (m_nHandles == 2) 
            { 
                ASSERT(ph[1] == h || ph[1] == NULL); 
                ph[1] = h; 
            } 
            return pObject;   // return current temporary one 
        }
        // This handle wasn't created by us, so we must create a temporary 
        // C++ object to wrap it.  We don't want the user to see this memory 
        // allocation, so we turn tracing off.
        BOOL bEnable = AfxEnableMemoryTracking(FALSE); 
    #ifndef _AFX_PORTABLE 
        _PNH pnhOldHandler = AfxSetNewHandler(&AfxCriticalNewHandler); 
    #endif
        CObject* pTemp = NULL; 
        TRY 
        { 
            pTemp = m_pClass->CreateObject(); 
            if (pTemp == NULL) 
                AfxThrowMemoryException();
            m_temporaryMap.SetAt((LPVOID)h, pTemp); 
        } 
        CATCH_ALL(e) 
        { 
    #ifndef _AFX_PORTABLE 
            AfxSetNewHandler(pnhOldHandler); 
    #endif 
            AfxEnableMemoryTracking(bEnable); 
            THROW_LAST(); 
        } 
        END_CATCH_ALL
    #ifndef _AFX_PORTABLE 
        AfxSetNewHandler(pnhOldHandler); 
    #endif 
        AfxEnableMemoryTracking(bEnable);
        // now set the handle in the object 
        HANDLE* ph = (HANDLE*)((BYTE*)pTemp + m_nOffset);  // after CObject 
        ph[0] = h; 
        if (m_nHandles == 2) 
            ph[1] = h;
        return pTemp; 
    }
  • 相关阅读:
    12个Web开发者应该掌握的Firebug技巧
    sql语句修改表结构
    从数据库中查询数据
    收发短信API
    日志12.03
    监听短信数据库变化
    漫谈C语言及如何学习C语言(转)
    阅读短信
    在src文件中寻找短信数据库表
    拦截短信示例1
  • 原文地址:https://www.cnblogs.com/xingrun/p/3409541.html
Copyright © 2020-2023  润新知