テクニカル ノート 3: Windows ハンドルとオブジェクト間のマップ
ここでは、C++ オブジェクトへの Windows オブジェクト ハンドルのマッピングをサポートする MFC ルーチンについて説明します。
問題
通常、Windows オブジェクトはさまざまな HANDLE オブジェクトによって表されます。MFC クラスは、C++ オブジェクトで Windows オブジェクト ハンドルをラップします。 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 に特定のラッパー オブジェクトが存在しない場合、一時的な CWnd
が作成されて hWnd がラップされます。 これにより、任意のハンドルから有効な 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++ ラッパー オブジェクトを 1 つのスレッドから別のスレッドに渡す場合、予期しない結果が生じる可能性があります。