C++ Windows プログラミング④ 書いて覚えるための初心者自己中記事
COMオブジェクトの作成
COMオブジェクトを作成する方法は2つある。
- オブジェクトを実装するモジュールによって、そのオブジェクトのインスタンスを作成するために設計された関数を提供する。
- COM によって CoCreateInstance という汎用作成関数を提供する。
1つ目の日本語が頭に入ってこない。
なんか、COMの話に入ってからずっとそうなんだけど、視点がどこにあるのかわからない。
なるほど、
// 実際の Windows 関数ではない HRESULT CreateShape(IDrawable** ppShape);
この関数に基づき、新しい Shape オブジェクトを以下のように作成できます。
IDrawable *pShape; HRESULT hr = CreateShape(&pShape); if (SUCCEEDED(hr)) { // Shape オブジェクトを使用する } else { // エラーが発生する }
IDrawable型のポインタをCreateShape関数に渡すときに、ポインタのアドレスを渡してポインタの参照先を書き換えるのか。なぜならCreateShape関数の戻り値はすでにHRESULTで使われているから。
これが一番目の方法なのか。
二番目の方法。CoCreateInstance関数。
一般的なオブジェクト作成方法と書いてある。こっちが一般的に使われるのかな。
えー、2つのCOMオブジェクトが同じインターフェイスを実装出来て、
1つのオブジェクトが複数のインターフェイスを実装できる。というのが重要。
CoCreateInstance関数に必要な情報は
作成するオブジェクト
オブジェクトから取得するインターフェイス
これらの情報を指定するための知識。
COMではオブジェクト・インターフェイスはグローバル一意識別子(GUID)と呼ばれる128ビットの値を割り当てることによって識別される。
GUIDは汎用一意識別子(UUID)と呼ばれることもある。
shapeのライブラリではこのようにGUID定数を宣言できる。
extern const GUID CLSID_Shape; extern const GUID IID_IDrawable;
IDrawable *pShape; hr = CoCreateInstance(CLSID_Shape, NULL, CLSCTX_INPROC_SERVER, IID_Drawable, reinterpret_cast<void**>(&pShape));
CoCreateInstance関数の第一、第四引数はクラス識別子、インターフェイス識別子。
shapeオブジェクトを作成し、IDrawableインターフェイスへのポインターを返す。
第二引数はNULL
第三引数はフラグのセット オブジェクトの実行コンテキストを指定する
フラグ | 説明 |
---|---|
CLSCTX_INPROC_SERVER | 同じプロセス |
CLSCTX_LOCAL_SERVER | 異なるプロセス、同じコンピューター |
CLSCTX_REMOTE_SERVER | 異なるコンピューター |
CLSCTX_ALL | オブジェクトがサポートする最も効率的なオプションを使用 (効率性が高い順に並べると、インプロセス、アウトオブプロセス、別コンピューターになります) |
まだよくわからない。
次が実際のコードの例らしいから、そこで理解できるように頑張ろう。
つぎ、ファイルを開くダイアログボックス。
ファイルを開くダイアログボックスは
Cmmon Item DialogオブジェクトというCOMを使用できる。
Cmmon Item DialogはShobjidl.h で宣言されるIFileOpenDialogという名前のインターフェイスを実装する。
おし、動くプログラムが出てきた。これを理解しよう。
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);//COMライブラリの初期化 if (SUCCEEDED(hr)) { IFileOpenDialog *pFileOpen;//Shobjidl.hで宣言されているCommon Item Dialog オブジェクトのインターフェイスIFileOpenDialogへのポインタ // FileOpenDialog オブジェクトを作成する //第一引数・クラス識別子(プレフィックスCLSID_) 第四引数・インターフェイス識別子(プレフィックスIID_) //第三引数・実行コンテキストのフラグセット 第五引数・インターフェイスへのポインター受け取り(void*) hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,IID_IFileOpenDialog, reinterpret_cast<void**>(&pFileOpen)); if (SUCCEEDED(hr)) { // [ファイルを開く] ダイアログ ボックスを表示する hr = pFileOpen->Show(NULL);//Showメソッド・ユーザーにダイアログボックスを表示する // ダイアログ ボックスからファイル名を取得する if (SUCCEEDED(hr)) { IShellItem *pItem;//ShellItemオブジェクトへのポインター用意 hr = pFileOpen->GetResult(&pItem);//GetResultメソッドでユーザーによって選択されたファイルがShellItemオブジェクトへのポインターとして引数を変更する if (SUCCEEDED(hr)) { PWSTR pszFilePath;//PWSTR(wchar_t*)を用意 hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);//ShellItemオブジェクトのメソッド・GetDisplayNameがファイルパスを文字列で取得 // ユーザーにファイル名を表示する if (SUCCEEDED(hr)) { MessageBox(NULL, pszFilePath, L"File Path", MB_OK);//ファイルパスを文字列で取得したpszFilePathをMessageBoxで表示 CoTaskMemFree(pszFilePath);//CoTskMemFree関数でメモリ解放 } pItem->Release();//何をリリースするんだろう? } } pFileOpen->Release();//何をリリースするんだろう? } CoUninitialize();//COMライブラリ初期化解除 }
ざっくりコメントつけてみた。
オブジェクトとかインターフェイスとか
オブジェクトを識別するGUIDをクラス識別子って言ったり、ややこしい。
半分理解してない。
ちょいちょいオブジェクトを作っている、って説明があるけど混乱してる。
この例には、汎用の CoCreateInstance 関数と、Common Item Dialog オブジェクトに固有のメソッド (GetResult) という 2 種類のオブジェクト作成方法が示されています
CoCreateInstance関数でオブジェクト作成、という表現をしている。オブジェクトを作成とはインスタンスを作成と同じ意味だよね?
実体化されたということだよね?
つまりあれか?CoCreateInstance関数を呼び出すと向こう側(どこだ?)でCommon Item Dialogオブジェクトの実体が作られるのか?
だけど向こう側に実体があってもこちらからは使えないから中継係が必要で、それがインターフェイスなのか?
オブジェクトとインターフェイスで
ShellItemオブジェクト
IShellItemインターフェイス
これはIが付くからわかる
CommonItemDialogオブジェクト
IFileOpenDialogインターフェイス
これはなんで名前がこんなに違うの?
分からない。俺が混乱している原因の1つだ。
あとは、メソッドが別のオブジェクトの実態を作るということか?
GetResultメソッドを呼び出して引数にIShellItem型?へのインターフェイスポインタを渡すとShellItemオブジェクトのインターフェイスIshellItemへのポインターに書き換えてくれる。これはGetRsultメソッドを呼んだらShellItemオブジェクトが実体化したということでいいのか?
・・それ以前にShellItemオブジェクトは実体化していたのかもしれないのか?
保留。
また、長くなってきたからいったん止める。
ここまで。