解析 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; 
}

 

posted @ 2013-11-05 23:07  xingrun  阅读(2009)  评论(0编辑  收藏  举报