Windows對象、句柄與MFC對象

Windows對象是以句柄來標識的,對應的MFC類就是這些句柄的C++包裝。內存中的Windows對象一定有唯一的句柄來標識,但不一定有對應的MFC類對象在內存中。當需要獲取Windows對象的對應MFC類對象而內存中又沒有此對象時,系統會創建一個臨時MFC類對象返回給用戶,並在之後某個空閒時刻進行回收。

  Windows對象句柄及其對應的MFC類如下表所示:

HWND

CWnd及派生類

HDC

CDC及派生類

HMENU

CMenu

HPENHBRUSHHFONTHBITMAPHPALETTEHRGN

CGdiObject

HIMAGELIST

CImageList

SOCKET

CSocket


  如果你擁有上面的任何一個Windows對象句柄,你可以調用對應類的靜態成員函數FromHandle來查找對應的MFC對象(系統爲每個線程維護了一個從Windows對象句柄到MFC對象的映射,一個持久的map和一個臨時的map);如果你擁有上面的MFC對象,你也可以通過MFC類的公有成員變量來獲取對應的Windows對象句柄。
  例如,給定一個HWND類型的句柄hWnd,可以通過

CWnd::FromHandle(hWnd)

來獲得CWnd對象的指針。如果hWnd沒有對應的CWnd對象,則系統會產生一個臨時CWnd對象與hWnd關聯,並返回該對象的指針。在獲得CWnd對象後,你可以通過CWnd的公有成員m_hWnd獲得窗口對象的句柄。
  如果在調用FromHandle時產生臨時MFC對象,句柄和MFC對象之間的映射被保存在系統的臨時map中。默認情況下,CWinThread::OnIdle自動爲那些支持臨時句柄映射的MFC類調用DeleteTempMap函數。在DeleteTempMap函數中,這些臨時對象將被取消與句柄的關聯,然後被銷燬。
  如果你擁有一個Windows對象句柄,那麼你可以創建一個對應的MFC對象,然後把該MFC對象與該Windows對象句柄進行關聯。此時,該MFC對象與Windows對象相互建立起映射關係。
  例如,對於如下代碼:

CWnd myWnd;

myWnd.Attach(hWnd);

將建立起hWnd到myWnd的映射。此後,你調用CWnd::FromHandle(hWnd)將返回myWnd對象的指針。如果myWnd對象被銷燬,它的析構函數將自動通過調用DestroyWindow來銷燬該hWnd所指Windows對象。如果該行爲不是所期望的,則需要在myWnd銷燬之前調用Detach成員函數解除兩者之間的關聯(映射),如 myWnd.Detach()。
  所有臨時MFC對象和持久(permanent)MFC對象都是以線程爲單位進行維護管理的。也就是說,一個線程不能夠訪問另一個線程的MFC包裝類對象,不管它是臨時的還是持久的。
  爲了在不同的線程間傳遞這些Windows對象,總是應該通過HANDLE類型傳遞。從一個線程向另一個線程傳遞MFC包裝對象將可能引起不可預料的結果。
  由於MFC包裝類對象是以線程爲單位進行管理的,因此,在程序中的不同線程中可能有多個MFC對象與同一個句柄對應。
  存在的疑問:如果同一線程中有多個MFC對象Attach同一句柄,那麼對該句柄調用FromHandle將返回哪個MFC對象呢?未定義行爲?
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章