MFC API - FromHandle()函數

  一 FromHandle()

  MFC 實際上是對內核對象HANDLE(如CDC的m_hDC,CWnd的m_hWnd)封裝了這個句柄有關的所有操作,一個類生成一個新對象的時候這個句柄是無效的,要獲得這個句柄,可以有兩個方法,一個是Create來創建,另一個就是用Attach來與一個已有的句柄建立關聯,實際上也就是給類的句柄成員變量賦值。 而有些時候這個句柄不是由我們創建,但是我們要對它的封裝類進行操作,(mfc 框架)必需創建對應的封裝類包裝它

MFC 中對各種包含內核對象的封裝類都有FromHandle(HANDLE h)方法。FromHandle(HANDLE h) 先查找由用戶定義的內核對象的封裝類, 如果找到直接返回,沒有找到構造一個臨時對象返回.

 

二 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()的區別

FromHandlePermanent函數,它當且僅當hwnd已與某個CWnd對象關聯時才返回此對象的指針,否則返回NULL。這也是它爲什麼叫Permanent——區別於FromHandle會new一個臨時的CWnd對象。 這兩個函數都是在公共的 CMapHandle 中查找句柄對應的 CWnd 對象(通過一個CBT鉤子,CWnd 對象將創建時得到的句柄和自己的指針紀錄到 CMapHandle),區別是如果找不到相關的對象,FromHandle 在CMapHandle 的 temporarylist 中創建並返回一個臨時對象的指針 ,而 FromHandlePermanent 返回 NULL(此外 FromHandlePermanent 不使用 temporarylist ,所以不查找 temporarylist 下的句柄)。

 

四  使用注意

  大部分情況下,對任意句柄使用 FromHandle 是不錯的,因爲大多情況下只利用返回的 CWnd 指針調用的非虛函數,返回的即使是一個臨時對象,調用也是正確的(MFC 中較少用 FromHandlePermanent,除非確定句柄是由本線程創建的或不需要創建臨時對象)。

但是在某些情況下,比如從使用 MFC 的非 Extension DLL 中創建的窗口,這個機制會有問題,因爲窗口創建在其他的 MFC 模塊之下,在 EXE 中調用 FromHandle,由於該模塊的 CMapHandle 對象某有相關的紀錄,所以只能得到臨時對象,如果使用返回的指針調用 CWnd 的虛函數如 PreTranslateMessage,得到調用的是 CWnd::PreTranslateMessage,而不是 DLL 中的 CWnd 派生類重載過的 CWnd::PreTranslateMessage。


  對於GDI對象,以上的分析也是適用的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章