このメモでは、Windows オブジェクト ハンドルから C++ オブジェクトへのマッピングをサポートする MFC ルーチンについて説明します。
問題
Windows オブジェクトは、通常、さまざまな HANDLE オブジェクトによって表されます。MFC クラスは、Windows オブジェクト ハンドルを C++ オブジェクトでラップします。 MFC クラス ライブラリのハンドル ラッピング関数を使用すると、特定のハンドルを持つ Windows オブジェクトをラップしている C++ オブジェクトを見つけることができます。 ただし、オブジェクトに C++ ラッパー オブジェクトがない場合があり、これらの場合、システムは C++ ラッパーとして機能する一時オブジェクトを作成します。
ハンドル マップを使用する Windows オブジェクトは次のとおりです。
HWND (CWnd および
CWnd
派生クラス)HDC (CDC および
CDC
派生クラス)HMENU (CMenu)
HPEN (CGdiObject)
HBRUSH (
CGdiObject
)HFONT (
CGdiObject
)HBITMAP (
CGdiObject
)HPALETTE (
CGdiObject
)HRGN (
CGdiObject
)HIMAGELIST (CImageList)
SOCKET (CSocket)
これらのオブジェクトのいずれかにハンドルがある場合は、静的メソッド FromHandle
を呼び出すことによって、ハンドルをラップする MFC オブジェクトを見つけることができます。 たとえば、hWnd という HWND を指定すると、次の行は hWnd をラップするCWnd
へのポインターを返します。
CWnd::FromHandle(hWnd)
hWnd に特定のラッパー オブジェクトがない場合は、hWnd をラップするために一時的なCWnd
が作成されます。 これにより、任意のハンドルから有効な C++ オブジェクトを取得できます。
ラッパー オブジェクトを作成したら、ラッパー クラスのパブリック メンバー変数からそのハンドルを取得できます。
CWnd
の場合、m_hWndにはそのオブジェクトの HWND が含まれます。
MFC オブジェクトへのハンドルのアタッチ
新しく作成されたハンドル ラッパー オブジェクトと Windows オブジェクトへのハンドルを指定すると、次の例のように Attach
関数を呼び出すことによって、2 つを関連付けることができます。
CWnd myWnd;
myWnd.Attach(hWnd);
これにより、 myWnd と hWnd を関連付け、永続的なマップにエントリが作成 されます。
CWnd::FromHandle(hWnd)
を呼び出すと、myWnd へのポインターが返されるようになりました。
myWnd が削除されると、デストラクターは Windows DestroyWindow 関数を呼び出すことによって hWnd を自動的に破棄します。 これが望ましくない場合は、 myWnd が破棄される前に hWnd を myWnd からデタッチする必要があります (通常、 myWnd が定義されたスコープを離れる場合)。
Detach
メソッドはこれを行います。
myWnd.Detach();
一時オブジェクトの詳細
一時オブジェクトは、まだラッパー オブジェクトを持たないハンドル FromHandle
が与えられるたびに作成されます。 これらの一時オブジェクトはハンドルからデタッチされ、 DeleteTempMap
関数によって削除されます。 既定では 、CWinThread::OnIdle は 、一時ハンドル マップをサポートするクラスごとに DeleteTempMap
を自動的に呼び出します。 つまり、一時オブジェクトへのポインターが、ポインターが取得された関数の終了時点を超えて有効であると想定することはできません。
ラッパー オブジェクトと複数のスレッド
一時的なオブジェクトと永続的なオブジェクトの両方がスレッドごとに保持されます。 つまり、あるスレッドが一時的か永続的かに関係なく、別のスレッドの C++ ラッパー オブジェクトにアクセスすることはできません。
これらのオブジェクトをスレッド間で渡すには、常にネイティブ HANDLE
型として送信します。 あるスレッドから別のスレッドに C++ ラッパー オブジェクトを渡すと、多くの場合、予期しない結果が発生します。