Component Object Model - Microsoftが提唱する(していた)、ソフトウェア資産再利用のための技術。美しく厳格なオブジェクト指向の世界を追及していたようであるが、そのためにややこしくなって凡人はついていけなくなり、フェードアウトしつつある・・・という認識でいいのだろうか?
時代遅れなのかもしれないが、オートメーションはなんだかんだで便利だし、DirectXも大部分はCOMで実装されているみたいだし、後継の.NETもCOMベースの技術だそうなので、ちょっとやってみることにした。ヘルプや解説Webページを見るもわけがわからず、ムカつく日々を過ごしていたが、腰を据えて勉強してみると意味や意義がおぼろげに捉えられてきた。
クラスやインターフェース等の登録はレジストリに記録される(なんでCOM専用のデータベースが作られなかったのだろう?)。コンポーネントは登録や削除用の関数を備えなくてはならないのだそうだ。ローカルサーバ(実行ファイル)はコマンドラインオプションによって、プロセス内サーバ(DLL)の場合はregsvr32.exeによって、これらがコールされる。
実際にATLでプロセス内サーバを作ってやってみた。ビルドすると
HKCR\CLSID\(CLSID) \Interface\(interfaceのGUID) \(ProgID バージョンあるのとないの) HKLM\SOFTWARE\Classes\CLSID\(CLSID) \Interface\(interfaceのGUID) \(ProgID バージョンあるのとないの)
に登録されていた。regsvr32/u して登録解除しても、CLSIDを含むエントリは残っていた。でも勉強不足なのでこれが何を意味するかはわからん。
COM開発に役立つフレームワーク
リリースビルド時にこんなエラーが出るのはなぜか?perfectな記述がすぐに見つかった。
ビルド時、いかにも必須っぽいのにファイルが無いと怒られてしまった。MFCでも似たようなことがあったのだが、これはオプションメニューからインクルード、ライブラリのディレクトリをちゃんと指定(ATL、MFCのも)してやると消えた。
インターフェースを宣言するファイル。
COMプログラミングというページの記述通りなのだが一応メモ。
引数の宣言にoptionalを入れると、その引数は省略可能となった。私はDWORD値にoptionalを加えてみたが、省略するとゼロが入るようであり、上記ページと同様であった。
シンプルオブジェクトをウィザードから追加し、またそのメソッドもウィザードで追加した状況を考える。その後に引数の数や種類を変えたいと思った時にはどうすればよいか?
IDLの記述を変更し、当該オブジェクトのヘッダとソースの記述を変えればそれで良いようである。削除も同様にすればOK?
[out, retval]とすると、これがメソッドやプロパティの戻り値となる。これを引数リストのどこに持ってゆけばよいんだろう?
http://www.microsoft.com/japan/msdn/thisweek/combasics/combasics3.asp に、最後に記述している例があった。実際に最後でやってみたらうまくいった。
文字列の戻り値は
[out, retval] BSTR* ret_str
などとする。
IDispatchを備えるオブジェクトはスクリプトから簡単に操作することができる。特に、Windows2000以降はWSH(Windows Scripting Host)が標準で備わっているため、特別な準備をしなくともVBScript、JScriptが使える。
Wscript.sleep(1000) ' 1000[ms] 待つ WScript.Quit ' やめる msgbox("hello") ' メッセージボックスを表示 inputbox("type the param") ' パラメータ入力可能なダイアログ ' ループ Dim i For i = 1 To 10 ' any Next
BSTR、VARIANT、SAFEARRAYあたりが聞き慣れないがCOMによく登場する型
ATLにSAFEARRAYのラッパーは無い(MFCならCOleSafeArrayがある)。なんで、APIを直接使う。
_variant_t var = integer_values_are_here; SAFEARRAY* psa = var.parray; long lb, ub; SafeArrayGetLBound(psa, 1, &lb); SafeArrayGetUBound(psa, 1, &ub); long* val; SafeArrayAccessData(psa, (void**)&val); for(long i = lb; i <= ub; i++){ // val[i] holds the value } SafeArrayUnaccessData(psa);
などとするらしい。