Out of Memory

ごめん、忘れてた。

目次

Blog 利用状況

ニュース

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

顔写真

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

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

Microsoft MVP for Windows SDK July 2007 - February 2008, Microsoft MVP for Visual C++ February 2008 - June 2009
Microsoft MVP for Windows SDK
July 2007 - February 2008
Microsoft MVP for Visual C++
February 2008 - June 2009

アクセサリ

あわせて読みたい

e-Words

アフィリエイト

記事カテゴリ

書庫

日記カテゴリ

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が若干気に食わないものの、こうするのが定石、なのかな?

投稿日時 : 2007年12月17日 15:38

Feedback

# re: MIDLが吐き出すファイル 2007/12/17 16:07 とっちゃん

おいらは、idl に coclass まで入れてますね。
けど、クライアント用に hoge_i.* 類は提供しませんね。
idl が生成するこれらのファイル類は、コンポーネントの実装用のスタブヘッダーなのでw

クライアントには、hoge.tlb を渡します。
こっちのほうが融通聞くしw
.NET でも、Native C/C++ でも好きに使えるものw

# re: MIDLが吐き出すファイル 2007/12/17 16:19 シャノン

ファイル名こそ*_h.hではないものの、MSはそれに相当する(MIDLが吐いた)ヘッダファイルをSDKに含めていますね。
定義は前述の通り、*.libに入っちゃってますけど。

タイプライブラリは表現力が貧弱らしいのでねぇ…
.NETから使うにはタイプライブラリを経由するしかないので、そこでどう制限が出るかは調べる必要がありますね。

# re: MIDLが吐き出すファイル 2007/12/17 16:39 とっちゃん

tlb は貧弱ですが、フォローしてないのは、実態位置(レジストリに書かれてる部分)とかですね。

tlb がメタデータとして貧弱というレッテル貼られてるのは、VBがフォローしてないものが多いからにすぎないかとw

実際、unsigned な整数型は、VBが読み書きできないから使うなと言われてただけだしねw

構造体の定義が面倒というのはあるけど、それも定義可能だし、C で表現できるものはほとんど全部表現できたはずですよ。
#そうじゃなきゃ、RPC のマーシャルかけないものw

# re: MIDLが吐き出すファイル 2007/12/17 16:47 シャノン

いやほら、wire_marshalとかcall_asとかさw

# re: MIDLが吐き出すファイル 2007/12/17 16:59 とっちゃん

うはw
その辺持ってくるか...
確かにtlbにはその辺入ってない気がするなぁ...

automation の世界でそのあたりは使わないもんなぁ...ふつうはw

# re: MIDLが吐き出すファイル 2007/12/17 18:14 melt

タイプライブラリはセキュリティの面で気になります...。

# re: MIDLが吐き出すファイル 2007/12/17 18:16 シャノン

kwsk

# re: MIDLが吐き出すファイル 2007/12/17 18:29 melt

管理者権限が必要で汎用的な処理を書いているサービスアプリケーションがあったのですが、そのタイプライブラリが公開されているので、管理者権限の必要な処理が簡単に任意のアプリケーションから呼べてしまうという問題があって、その対策に右往左往しました(主に自分以外が)。
とりあえずタイプライブラリを公開しなければ良いという対策で終わりましたが、本当は暗号化なり何なりしておくべきかもとか思ったりもしています。

そういうことがあったのでタイプライブラリは公開しないでおこうと心に誓ったのですが、.NET は必須なんですか...orz

# re: MIDLが吐き出すファイル 2007/12/17 22:22 ちゃっぴ

> 管理者権限が必要で汎用的な処理を書いているサービスアプリケーションがあったのですが、そのタイプライブラリが公開されているので、管理者権限の必要な処理が簡単に任意のアプリケーションから呼べてしまうという問題があって、その対策に右往左往しました(主に自分以外が)。

ってゆうか type library と全く関係がないと思いますが。
Type libarary があろうと無かろうと結局として呼び出せることには違いないので。

User 単位で制限を課したいのであれば、service の ACL で制限すればいいですし。

もしかして、COM+ ?。そちらにも ACL ありますし、roll base で制限かけられたかと。

# re: MIDLが吐き出すファイル 2007/12/17 22:51 Atata!!

> MIDLが若干気に食わないものの、こうするのが定石、なのかな?

私はcoclassを定義したヘッダファイルを提供することが多いです。
CLSIDは __uuidof(Hoge) としてもらう規約にしています。

# gccとかは放置で・・・。


> いやほら、wire_marshalとかcall_asとかさw

ちなみにSAFEARRAY以外の配列型はタイプライブラリには含まれません。
以下のような属性が該当するかと
・first_is
・last_is
・length_is
・max_is
・size_is

# これ以外にも出力されない属性が多いので、
# automation 互換型で統一しない限りタイプライブラリは
# 出力しなくてもいいかなとか思ってます。


> そういうことがあったのでタイプライブラリは公開しないでおこうと心に誓ったのですが、
> .NET は必須なんですか...orz

RCWが作成できれば基本的に不要です。
で、そのためにPIAを作成して配布するものだと私は認識しています。

# タイプライブラリマーシャリングが必要ならば話は別ですが・・・

# re: MIDLが吐き出すファイル 2007/12/17 23:34 シャノン

博士キター。

> 以下のような属性が該当するかと

おぉ、結構メジャーな属性が当てはまるじゃないですか。

> RCWが作成できれば基本的に不要です。
> で、そのためにPIAを作成して配布するものだと私は認識しています。

タイプライブラリを使わずにPIAを作る方法がよくわかってませんw

# re: MIDLが吐き出すファイル 2007/12/18 2:32 Atata!!

> 事実、Windows SDKに含まれるDEFINE_GUIDは...

MIDLで出力したプロキシ/スタブソースは MinGW でもコンパイル/リンクが可能で、
開発環境に MinGW を選択した時は、私も DEFINE_GUID を使っていました。

# と言うか使わざるを得ませんでした。


> タイプライブラリを使わずにPIAを作る方法がよくわかってませんw

すごい誤解する書き方になってしまいましたが、通常PIAはタイプライブラリから作成します。
で、PIAはタイプライブラリの作成者がタイプライブラリの代わりに
コンポーネントの利用者に配布するものだと言うことが言いたかったわけです。

# re: MIDLが吐き出すファイル 2007/12/18 9:43 シャノン

あぁ、確かにそういう意味では、.NETでタイプライブラリは必須ではありませんね。
俺は、製作者がPIAを用意するにしろ、利用者側でtlbimpするにしろ、タイプライブラリが無いといけないということで必須と認識してました。
が、どうやらタイプライブラリ無しでもPIAは作れるようです。
ただ、タイプライブラリが保持できない属性が、カスタムで作ったときに保持できるのかどうかはわかりませんが。

# re: MIDLが吐き出すファイル 2007/12/21 18:54 シャノン

Hoge_i.cもクライアントに渡す方向で検討。

タイトル  
名前  
Url
コメント