Skip to content
nishi_74322014 edited this page Aug 21, 2026 · 2 revisions

COM

概要

  • COM (Component Object Model) は、

    • Microsoft が作り出した、プログラムや部品の呼び出しを共通的に行える仕組み。
    • COM をベースに、COM コンポーネント、ActiveX コントロールなどの部品が
      作られてきた。
  • COM に関しては、下のページも参考ください。

補足(COM の要点): COM の本質は
バイナリ レベルでのインターフェイス規約」である。

  • 言語もコンパイラも問わない(C++ / VB / C# / VBS から同じ部品を使える)。
  • すべてのインターフェイスは IUnknown を継承し、
    QueryInterface / AddRef / Release の 3 メソッドを必ず持つ。
  • オブジェクトの寿命は参照カウントで管理される(GC ではない)。

この「参照カウント」が、後述のCOM のメモリ・リーク
直接の原因になる。

詳細

利用

COM を利用する際は、ProgID を使用して、
COM 部品のオブジェクトを得ます。

  • VBSの例(作成する場合)

    set fso = CreateObject("Scripting.FileSystemObject")
  • VBSの例(作成済みのオブジェクトを取得する場合)

    set word = GetObject("c:\temp\word.doc", "Word.Document")

Scripting.FileSystemObjectWord.Document は ProgID の例です。
ProgID は、レジストリの HKEY_CLASSES_ROOT に書かれています。

インターフェイス

プロジェクト互換

  • インターフェイス変更が認められている。
  • インターフェイスが変更されると CLSID, IID などのIDも変更される。

バイナリ互換

  • インターフェイス変更はメソッド追加だけが認められている。
  • 仮想関数メカニズムを利用し、継承したインターフェイスにメソッドを追加する。
  • このため、既存の CLSID, IID は変更されず、
    新しいインターフェイスの IID ダケが追加される。

補足(なぜバイナリ互換が重要か): COM の呼び出しは
vtable(仮想関数テーブル)のオフセットで解決される。
既存メソッドの間に新しいメソッドを挿入すると、
再コンパイルしていない呼び出し側が別のメソッドを呼んでしまう
だから「末尾への追加のみ許可」という制約になっている。

VB 6.0 の「バイナリ互換」設定はこれを担保するための機能で、
保守で誤って「プロジェクト互換」に戻すと、
配布済みクライアントが動かなくなるという典型的な事故が起きる。

ID

プログラムID(ProgID)

  • プロジェクト名.クラス名
  • 前述の CreateObject の引数に使用される。

クラスID(CLSID)

  • GUID
  • COM オブジェクトを識別する
  • CoCreateInstance の引数として渡される。

インターフェイスID(IID)

  • GUID
  • インターフェイスを識別する
  • CoCreateInstance や、QueryInterface の引数として渡される。

レジストリ

HKEY_CLASSES_ROOT には、大きく分けて、

  • 拡張子
  • ProgID
  • GUID
    • CLSID
    • IID

の3種類の情報があります。

  • レジストリで、ProgID をたどると、サブキーに GUID がある場合があります。
  • その場合は、さらにその GUID キーをたどると、COM 部品の情報があります。

COM部品の実体

COM 部品の実体は、レジストリの GUID の下、

  • InprocServer32 の値を確認すると、どの dll ファイルが提供しているか分かります。
  • InprocServer32 ではなく LocalServer32 の値に書かれている場合もあります。

InprocServer32、LocalServer32

  • InprocServer32 に書かれている場合
    COM 部品を呼び出したプロセスと同じプロセスの中で動作する COM 部品。

  • LocalServer32 に書かれている場合
    COM 部品を呼び出したのとは別のプロセス内で動作し、
    呼び出し元とはプロセス間通信して動作する COM 部品。

どちらも、COM ですが、使用方法としては同じです。
(デバッグやトラブルシュートでは、この違いは重要になってきますが)

補足(32bit / 64bit の落とし穴): レジストリの COM 登録は
32bit と 64bit で別の場所に書かれる。

プロセス 参照されるキー
64bit HKEY_CLASSES_ROOT\CLSID
32bit(WOW64) HKEY_CLASSES_ROOT\Wow6432Node\CLSID

regsvr32 したのに CreateObject
80040154 (REGDB_E_CLASSNOTREG) で失敗する」というトラブルの多くは、
登録側と呼び出し側のビット数が食い違っていることが原因である。
C:\Windows\System32\regsvr32.exe(64bit)と
C:\Windows\SysWOW64\regsvr32.exe(32bit)を使い分ける必要がある
(紛らわしいが、SysWOW64 の方が 32bit である)。

DCOM

DCOM(Distributed COM)については、RPCを参照。

参考

内部リンク

.NET からの利用

.NET からは COM 相互運用(COM Interop) で利用する。

方向 仕組み
.NET → COM RCW(Runtime Callable Wrapper)。Marshal.ReleaseComObject で明示解放できる
COM → .NET CCW(COM Callable Wrapper)。ComVisible 属性で公開

EternalWindows

kekyoの丼


Tags: 移行, Windows, プログラミング, .NET開発

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally