どうも~www いえ~い。昨日からずっと書いてる楽しいテーマってこれだよwwww Windows 2000 から使える COM について書いていくよ! (新 COM 範囲は少し書き方が違うのでまずは旧来のものから)
全体的に勉強不足なので誤りがあったら、訂正していただけるとありがたいです。
概要
- なぜ、今 COM なのか
- Factory と Object
- レジストリーに登録しなければならない、○か×か
- [実践編] 重要な interface を理解しよう!
- WinRT object
- まとめ
1. なぜ、今 COM なのか
なぜ今更 “Component Object Model” なのか。
1.1. Windows Runtime 基盤となっている COM
Windows Runtime は COM の仕組みそのものです。したがって、COM の制約を受けています。しかし、COM には 1 つの魅力があります。それは、「どのような言語であれ COM を扱える仕組みさえがあれば、その言語で実装することを可能にしてくれるのです。」 言い換えれば、「あらゆる言語で書ける可能性が広がる」ということです。
皆さんは思うでしょう、「こんな簡単なプログラムのために新しい言語なんて覚えたくない、」と。しかし、COM はその制約を取っ払う大きなものとして使えるわけです。今現状、Windows Runtime にてデフォルトで使える言語は、C++/CX、C#、VB しかありません。しかし、COM 自体なら取り扱える言語がたくさんあります。
1.2. COM って多言語のために作られたの?
どちらかといえば、「コンポーネントの再利用」や「スレッド管理を容易にする」ために作られたほうが強いと思います。そのあたりは wikipedia とか参照してもらったほうが正確だと思います。私は、Windows と密接に絡んだプログラミングを始めたのは高 3、つまり 4 年前ぐらいですので。
ただ、一つ言えることは、「今でも通用する根本である」ということです。タブレット時代だからこそ、いろいろな言語で使えたほうがいいのです。重たい処理は native に落とし込めます。軽い処理は managed でちゃら~っと書けばいいでしょう。そこが今の時代とマッチするというのが今の場合、重要な要素でしょう。
1.3. 今からでも遅くない COM
今から学んでも遅くないです。将来、Win32 が滅んでも、COM という基盤は変わらないはずです。むしろ Win32 を抜いた純粋 COM OS ができるかもしれません。COM はそれだけ今、Windows に欠かせない技術になっており、そしてこの仕組みが成熟したからこそ、今の WinRT があるといっても過言ではないでしょう。
2. Factory と Object
☆ペンタブと Photoshop を使って簡単に書いた図です。これはイメージです。
Factory と Object が存在します。Factory と Object の両方とも coclass と呼びます。coclass は interface を継承し、interface 以上のことは実装できません。interface を用いて coclass の method にアクセスすることになります。
WinRT の C++/CX ではコンストラクターに引数を持ったものを定義すると __I~Factory という interface ができると思います。この中に、普通とは違う CreateInstanceN (N: 整数) というものができているでしょう。
2.1. 通常 1 DLL に対し 1 つの Factory
これはなぜかというと、1 つの Factory でいろいろオブジェクトを生成するという考えなんだと思います。実はあまりよくわかってなくて、
- DllGetClassObject にて COM Server が生成した Factory を COM Client が受け取る。
- COM Client が受け取った Factory をもとに COM Server に Object を生成するように促し、Object を受け取る。
- Object を操作する。
という流れはわかっているのですが、どうしてこういう経緯になったのかはイマイチ判りません。 また、.NET 系では stdcall な関数が公開できないので、DllGetClassObject の関数を公開できない (?)*1。
3. レジストリーに登録しなければならない、○か×か
正解は×です。
レジストリーに登録しなくても、DLL を直接読み込んでごりごりすることができるので、少しコードを書けば、レジストリーを汚さず COM の仕組みを使えます (オイシイ)。サンプルコードの Client 呼び出しはこの方法で実現しています。
4. [実践編] 重要な interface を理解しよう!
4.1. IUnknown
COM における最小の interface。すべての coclass は必ず IUnknown が継承されている。
- QueryInterface
- AddRef
- Release
(順同)
4.2. IInspectable
WinRT 時代の COM 基本単位。WinRT の coclass は必ず継承されている。普段は WinRT object という形で隠れているため見えない (C++/CX)。ただし、これは JavaScript をサポートするために用いられる。C++ では QueryInterface を使う。旧時代 COM だと IDispatch あたりに相当し、JScript や VB 向けというのがあったような感じととらえればよいだろう。
- (IUnknown)
- GetIids
- GetRuntimeClassName
- GetTrustLevel
5. WinRT object
今回の範疇で十分理解できる、WinRT object について最後に語ろう。
上記を見てもらったらわかるが、COM は GC (ガーベージコレクション) ではない。単なる参照カウントオブジェクトなのだ。使うときに AddRef し、終わったときに Release を行う。C++/CX ではこういう作業を行っているのだが、ユーザーには隠ぺいされている。また、通常は HRESULT が戻り値なのが、C++/CX 上では WinRT 例外としてみえ、WinRT 例外は実際には HRESULT の戻り値という形で表現されている。
今回のお話を通して、WinRT object が何なのか、を理解できたら、それはこの記事の意味もあるのであろう。
6. まとめ
今回はたったこれだけですが、連載予定となっています。今回この記事を書くのにあたっていろいろな言語における COM Server のサンプルコードを書きました。このサンプルコードを以下のほうにおいておきます。
ComProject - GitHub
https://github.com/mntone/ComProject
今回の実装は、DllGetClassObject を用いた実装のため、C# などの .NET では今回の形式の Server にはなれないと思います (できるならオシエテー)。次回のサンプル未定。
次回の内容は、未定です (笑)。まあ、C++ における COM 実装の話はありかな~って思ってます。おわり。
*1:もしやり方があるならコメントしていただきたい