浅谈FromHandle

你的程序中必然对你的主窗口Attach(这是由Framework完成的),这样的话,假如你又得到了你程序的主窗口句柄hwndMain,你如果再调用FromHandle(hwndMain),它返回的将是你的App中的m_pMainWnd,原因就是FromHandle会维持一个内部的列表,纪录每个hwnd与CWnd的关联情况,如果一旦一个hwnd早已与某个CWnd对象相关连,它会返回该CWnd对象的指针。既然如此,FromHandle返回的便是m_pMainWnd,而此对象Framework会自动析构,因此你只是得到了该指针的一个副本,不能对其作析沟操作,否则会导致你的程序运行不正常。 
   考虑另外一种情况,就是一个hwnd与任何对象都没有关联(比如,你用API CreateWindow新建了一个窗口),此时的hwnd尚未与任何CWnd对象关联,如果你用FromHandle(hwnd),FromHandle便会临时new一个CWnd对象,并Attatch到此hwnd,然后返回给你。我刚才说了,FromHandle会维持一个hwnd与CWnd关联的列表,每当Framework OnIdle时,它便会检查此列表,一旦发现某个CWnd是FromHandle临时创建的对象,它便会首先Detach此对象,然后delete之。因此,你在程序中也不必delete从FromHandle得到的对象指针,但这种指针只在一次消息处理过程中有效。 
   另外还有FromHandlePermanent函数,它当且仅当hwnd已与某个CWnd对象关联时才返回此对象的指针,否则返回NULL。这也是它为什么叫Permanent——区别于FromHandle会new一个临时的CWnd对象。 
   对于GDI对象,以上的分析也是适用的。 

   另外,以上只是一种比较抽象的理解,具体MFC的实现,你看一下MFC的源代码,应该会有很大的帮助(MFC公开源代码,真是太好不过了)。

CBitmap::FromHandle

static CBitmap* PASCAL FromHandle( HBITMAP hBitmap );

返回值:调用成功时返回一个指向CBitmap对象的指针,否则返回NULL。

参数:

hBitmap 指定一个Windows GDI 位图的句柄。


说明:
本函数在调用时指定一个Windows GDI 位图的句柄,返回一个指向CBitmap对象的指针。如果该句柄上没有相联系的CBitmap对象,则为该句柄建立一个临时CBitmap对象。该临时CBitmap对象保持有效,直到应用在它的事件循环中出现空闲时间,此时Windows会删除所有的临时图形对象。换句话说,临时对象仅在一个Windows消息的处理过程中有效。

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
}



转自:http://tsing01.blog.163.com/blog/static/205957283201242454821675/

           http://blog.csdn.net/huys03/article/details/4549678  

你可能感兴趣的:(vc知识集锦)