Out of Memory

本ブログは更新を停止しました。Aerieをよろしくお願いいたします。

目次

Blog 利用状況

ニュース

2009年3月31日
更新を停止しました。引き続きAerieを御愛顧くださいませ。
2009年2月3日
原則としてコメント受付を停止しました。コメントはAerieまでお願いいたします。
詳細は2月3日のエントリをご覧ください。
2008年7月1日
Microsoft MVP for Developer Tools - Visual C++ を再受賞しました。
2008年2月某日
MVPアワードがVisual C++に変更になりました。
2007年10月23日
blogタイトルを変更しました。
2007年7月1日
Microsoft MVP for Windows - SDKを受賞しました!
2007年6月20日
スキル「ニュース欄ハック」を覚えた!
2006年12月14日
記念すべき初エントリ
2006年12月3日
わんくま同盟に加盟しました。

カレンダー

中の人

αετο? / aetos / あえとす

シャノン? 誰それ。

顔写真

埼玉を馬鹿にする奴は俺が許さん。

基本的に知ったかぶり。興味を持った技術に手を出して、ちょっと齧りはするものの、それを応用して何か形にするまでは及ばずに飽きて放り出す人。

書庫

日記カテゴリ

2007年12月17日 #

MIDLが吐き出すファイル

たまにはCOMしましょうかね…(遠い目)。

IDLファイル書きました。こんなの。

import "oaidl.idl";
import "ocidl.idl";
[
 object,
 uuid( 9874C279-FE45-43a1-9ED6-ED667E5BA089 )
]
interface IHoge : IUnknown
{
 HRESULT Hoge();
}

こいつをMIDLでコンパイると、(元のファイル名がHoge.idlだとして)以下の4つのファイルができます。

  • Hoge_h.h
  • Hoge_i.c
  • Hoge_p.c
  • dlldata.c

Hoge_h.hは、このインターフェイスの定義をC++風に書き直したものです。
こいつを、このインターフェイスを使うクライアントに提供します。
この中には、IID_IHogeの宣言も含まれています。

Hoge_i.cは、GUIDの定義ファイルです。
今回の例の場合、この中にIID_IHogeの定義が含まれます。

Hoge_p.cとdlldata.cは、このインターフェイスのプロキシとスタブを生成するためのソースファイルです。
ここでは割愛。

さて、これでコンポーネント側はできたとして(実装は小人さんが手伝ってくれました)、次はこれを利用するアプリ側を作りましょう。

ここで問題です。
アプリ側ではCoCreateInstanceを使うために、CLSID_HogeとIID_IHogeの定義が必要です。
しかし、CLSID_Hogeなんてものはどこにも定義してありません。
それから、ユーザに渡したHoge_h.hには、IID_IHogeの宣言しか入っていません。
さぁどうしましょう?

MicrosoftがWindows SDKで提供しているインターフェイスは、そのCLSIDやIIDの定義がスタティックライブラリに入っているものがあります。
しかし、COMは本来、インポートライブラリ不要のアーキテクチャです。
ヘッダファイルにでも入れて提供してあげれば済むことなので、このためにHoge.libなんて作りたくありません。

IIDの定義は、Hoge_i.cに入っています。
このファイルをユーザーに提供すればいいんでしょうか?
できれば、ユーザーに渡すのはヘッダファイルだけにしたいところです。
それとも、実体の定義を伴うヘッダファイルなんて邪道でしょうかね?

CLSIDはどこで定義しましょう?
IDLファイル中でも、こんな風にすればできます。

import "oaidl.idl";
import "ocidl.idl";
[
 object,
 uuid( 9874C279-FE45-43a1-9ED6-ED667E5BA089 )
]
interface IHoge : IUnknown
{
 HRESULT Hoge();
}
[ uuid( 56BFECD7-0642-4594-9CA8-6C1B77DE0C95 ) ]
coclass Hoge
{
 [ default ] interface IHoge;
}

これは、IHogeを実装するクラスHogeの定義です。
こう定義してやると、Hoge_h.hにCLSID_Hogeの宣言が、Hoge_i.cに定義が、それぞれ生成されます。

しかし、同時に、Hoge_h.hにHogeクラスの先行宣言が加わります。
このHogeクラスとは何者でしょうか?

これはCOMクラスですから、そんなクラスを宣言されたところで、new Hoge; でインスタンスを生成することはできません。
先行宣言によって可能になるのは、その型のポインタ型を定義することくらいですが、メソッドの宣言が含まれないため、そのポインタを利用してメソッドを呼び出すことができません。
第一、C++でCOMを扱うときに利用するのはインターフェイスポインタであって、CLSID以外でクラスの存在を意識することはないのです。クラスポインタなんて必要ありません。
まったく役立たずです。

IDLファイルにcoclassだけでなくタイプライブラリの定義も加えてやれば、VBや.NETからの呼び出しが可能になり、そこではnew Hoge;でのインスタンス生成が可能になります。
しかし、そのためにHoge_h.hでHogeクラスが宣言されている必要はゼロです。VBや.NETは、C++のヘッダファイルを必要としないのですから。

というわけで、

  • ユーザにHoge_i.cは提供したくない
  • IDLでcoclassは定義したくない

ということになりました。

IDLでcoclassを定義しない以上、CLSIDの定義をMIDLに頼ることはできません。
ならば、自分でヘッダファイルでも作って、そこに書いてやるしかないでしょう。
せっかくファイルを作るのならば、IIDの定義もそっちでやってしまいましょう。
特定のマクロが定義されているときは定義に、そうでないときは宣言になるようにスイッチしてあげればいいでしょう。
事実、Windows SDKに含まれるDEFINE_GUIDはそうなっていますし、guidgen.exeはほとんどコピペで使えるDEFINE_GUID形式の表記を生成してくれますから、これを使えばいいでしょう。

ふーむ…これで最適解になりましたかね?
MIDLが若干気に食わないものの、こうするのが定石、なのかな?

posted @ 15:38 | Feedback (259)