読者です 読者をやめる 読者になる 読者になる

モノトーンの伝説日記

OBS Studio と Blackmagic Design が大好き。

COM 再入門 (1)

 どうも~www いえ~い。昨日からずっと書いてる楽しいテーマってこれだよwwww Windows 2000 から使える COM について書いていくよ! (新 COM 範囲は少し書き方が違うのでまずは旧来のものから)

 全体的に勉強不足なので誤りがあったら、訂正していただけるとありがたいです。

概要

  1. なぜ、今 COM なのか
  2. Factory と Object
  3. レジストリーに登録しなければならない、○か×か
  4. [実践編] 重要な interface を理解しよう!
  5. WinRT object
  6. まとめ

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

f:id:mntone:20131214201044p:plain

☆ペンタブと 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 でいろいろオブジェクトを生成するという考えなんだと思います。実はあまりよくわかってなくて、

  1. DllGetClassObject にて COM Server が生成した Factory を COM Client が受け取る。
  2. COM Client が受け取った Factory をもとに COM Server に Object を生成するように促し、Object を受け取る。
  3. 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 あたりに相当し、JScriptVB 向けというのがあったような感じととらえればよいだろう。

  • (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:もしやり方があるならコメントしていただきたい