インプロセスサーバーCOMにおけるインターフェースと実装の分離は、オブジェクトの詳細をクライアントから隠蔽することに成功しました。これによってある1つの疑問が生じます。クライアントはどのようにしてオブジェクトを作成すればよいかという点です。CLSIDで識別されるオブジェクトを作成できるようにしています。*ppv);rclsidは、作成するオブジェクトのCLSIDを指定します。pUnkOuterは、集約に使用するインターフェースを指定します。通常は集約を行わないため、NULLを指定することになります。dwClsContextは、CLSCTX型で定義される定数を指定します。アウトプロセスサーバーとして扱いたい場合はCLSCTX_LOCAL_SERVERを指定します。riidは、オブジェクトの操作に使用するインターフェースのIIDを指定します。オブジェクトは、このインターフェースを実装している必要があります。ppvは、作成されたオブジェクトのアドレスを受け取る変数のアドレスを指定します。これはどのような仕組みで実現されているのでしょうか。現状では次のようなイメージを持っておいてください。そのキーからCOMコンポーネントのパスを取得します。前者をインプロセスサーバー、後者をアウトプロセスサーバーと呼びます。ある特別の関数を呼び出されることになります。最終的にDLL自身がオブジェクトを作成し、そのアドレスがCoCreateInstanceの呼び出し側に返る仕組みとなっています。COMにおける多くの関数やメソッドの戻り値はHRESULT型になっています。FAILEDマクロに指定することで失敗を意味しているかどうかを確認することができます。その値をwinerror.hに定義されている定数と比較することになります。CoInitializeを呼び出していないことがエラーの原因であると分かります。ちなみに、SUCCEEDEDマクロで成功する値は、原則としてS_OK(0)とS_FALSE(1)のみです。関数内で行われた条件式の判定がFALSEであることを意味します。クライアントは、オブジェクトを操作するスレッドの数だけCoInitializeを呼び出す必要があります。この関数を呼び出すことにより、スレッドはアパートの中に入り、オブジェクトを操作することが許可されます。pvReserved);pvReservedは、予約されているためNULLを指定します。MTA(STAとは別のアパート)に入る場合はCoInitializeExを呼び出すことになります。アパートの詳細については、別の章で取り上げる予定です。CoUninitializeで開放することができます。CoUninitialize(void);この関数は、CoInitializeを呼び出した回数だけ呼び出す必要があります。COMクライアントのサンプルとして、CoCreateInstanceで既存のオブジェクトを作成してみましょう。このオブジェクトが持つダイアログを表示する機能を使用します。shobjidl.hのインクルードが必要です。0;}FileOpenDialogオブジェクトはIFileDialogで識別することになるため、これを型としたpFileDialogという変数を宣言しています。スレッドがCoCreateInstanceを呼び出すためには、最初にCoInitializeを呼び出しておく必要があります。今回はFileOpenDialogオブジェクトを識別するCLSID_FileOpenDialogを指定しています。関数が成功した場合はこのオブジェクトを実装するDLLがロードされることになります。第5引数にはオブジェクトを受け取る変数のアドレスを指定しなければなりません。第5引数について省略しているようにも思えます。この点について理解するために、まずは従来のCoCreateInstanceの呼び出し方を考察します。実際にはある1つの問題が入る余地を残しています。それは、第4引数に指定できるIIDが第5引数のインターフェースのIIDと異なっていてもコンパイルが成功するという点です。間違って別のIIDを指定してしまうこともないとは言い切れないわけです。よって、このような問題を回避するためにIID_PPV_ARGSというマクロが用意されています。IIDが変数の型と矛盾することは完全になくなります。CoCreateInstanceのようなIIDと変数のアドレスが連続した引数の関数には、問題なく指定することができます。古いSDKのヘッダファールには、IID_PPV_ARGSマクロが定義されていないことに注意してください。IFileDialog::Showを呼び出すと、ファイルを開く時に使われるダイアログが表示されます。少なくとも、クライアントがインターフェースを通じてオブジェクトに1つの命令を与えたということは実感できると思います。インターフェースが不要になった場合は、Releaseを呼び出すことでオブジェクトを破棄します。COMに関する一切の操作が不要になった場合は、CoUninitializeを呼び出します。