COM (Component Object Model)

COMとはプログラムを部品化し再利用するための技術で、これに基づいて作成された部品をCOMコンポーネントと呼びます。

  • コンテナ (クライアント) … データを要求するアプリケーション
  • サーバ … データを提供するアプリケーション
COMとは|Component Object Model - IT用語辞典 e-Words

インターフェイス

IUnknownインターフェイス

すべてのCOMインターフェイスが継承するインターフェイスであり、他のインターフェイスへのポインタを取得したり、オブジェクトの実体を管理したりできます。IUnknown (unknwn.h) | Microsoft Learn

メソッド 機能
AddRef() オブジェクトのインターフェイスの、参照カウントを増加させる。このメソッドは、オブジェクトのインターフェイスの新しいコピーごとに呼ばねばならない
Release() オブジェクトのインターフェイスの、参照カウントを減少させる。
QueryInterface(REFIID riid, void **ppvObject) オブジェクトでサポートされているインターフェイスへの、ポインタを取得できる。
Methods - IUnknown (unknwn.h) | Microsoft Learn

IUnknownを実装したときに、「error C2695: '***::QueryInterface': オーバーライドする仮想関数と 'IUnknown::QueryInterface' は呼び出し規約のみ異なっています。」としてエラーとなるときには、その基底クラスと同様にSTDMETHODCALLTYPEを指定します。c++ - What does overriding virtual function differs only by calling convention mean? - Stack Overflow

virtual HRESULT STDMETHODCALLTYPE QueryInterface(
    /* [in] */ REFIID riid,
    /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject) = 0;

AddRef()

ULONG AddRef();
IUnknown::AddRef - Win32 apps | Microsoft Learn

新しい参照カウントが返されます。

Release()

ULONG Release();
IUnknown::Release - Win32 apps | Microsoft Learn

新しい参照カウントが返されます。

QueryInterface()

オブジェクトでサポートされているインターフェイスへのポインタを取得できます。

HRESULT QueryInterface(
  REFIID riid,       // 対象のインターフェイスの、インターフェイス識別子 (interface identifier / IID) への参照
  void   **ppvObject // riidで指定されたIIDがあるインターフェイスへのポインタのアドレス
);
IUnknown::QueryInterface(REFIID,void) (unknwn.h) | Microsoft Learn

riidppvObjectは、IID_PPV_ARGSマクロで取得できます。ただしそのインターフェイスにGUIDが指定されていないと「__uuidof のオペランドには __declspec(uuid('...')) が指定されているクラス型または列挙型を使用する必要があります」としてエラーが報告され、「'***': このオブジェクトに関連付けられた GUID はありません。」としてC2787となります。

#define IID_PPV_ARGS(ppType) __uuidof(**(ppType)), IID_PPV_ARGS_Helper(ppType)
IID_PPV_ARGS macro (combaseapi.h) | Microsoft Learn

たとえばinterface1へポインタを取得しinterface2へ代入するには、次のようにします。

HRESULT hr = interface1->QueryInterface(IID_PPV_ARGS(interface2));

戻り値は下表の意味となります。

戻り値 意味
S_OK インターフェイスが、サポートされている
E_NOINTERFACE インターフェイスが、サポートされていない
E_POINTER ppvObjectがNULL

データ型

BSTR (Basic STRing or binary string)

typedef OLECHAR *BSTR;

typedef WCHAR OLECHAR;

typedef wchar_t WCHAR;
String Manipulation Functions [Automation] | MSDN

文字列を作成するにはSysAllocString()を呼びます。

BSTR SysAllocString(const OLECHAR *sz);
SysAllocString Function | MSDN

そしてそれを解放するにはSysFreeString()を用います。

VOID SysFreeString(BSTR bstr);
SysFreeString Function | MSDN

char*との相互変換

BSTR → char*
char* __stdcall ConvertBSTRToString(
   BSTR pSrc
);
ConvertBSTRToString | MSDN

omsuppw.libまたはcomsuppwd.libを依存ファイルに追加します。

BSTR bstrText = ::SysAllocString(L"Test");
char* charText = _com_util::ConvertBSTRToString(bstrText);

// ...

SysFreeString(bstrText);
delete[] charText;

ConvertBSTRToString()から返されたポインタを移動してはなりません。移動するとSysFreeString()でアクセス違反となります。

char* → BSTR
BSTR __stdcall ConvertStringToBSTR(
   const char* pSrc
)
ConvertStringToBSTR | MSDN

初期化と終了処理

CoInitializeEx()

呼び出し元のスレッドで使用できるように、COMライブラリを初期化できます。同時にスレッドの同時実行モデル (concurrency model) が設定され、必要ならばスレッドの新しいアパートメントが作成されます。

HRESULT CoInitializeEx(
  [in, optional] LPVOID pvReserved, // つねにNULL
  [in]           DWORD  dwCoInit // スレッド用の同時実行モデルと初期化オプション
);
CoInitializeEx function (combaseapi.h) - Win32 apps | Microsoft Learn

dwCoInitには、COINIT列挙型の値を指定します。

列挙子 説明
COINIT_APARTMENTTHREADED Initializes the thread for apartment-threaded object concurrency

オブジェクトは、それを作成したスレッドで実行することが要求される

COINIT_MULTITHREADED Initializes the thread for multithreaded object concurrency

オブジェクトは、任意のスレッドで実行できる

COINIT_DISABLE_OLE1DDE Disables DDE for OLE1 support.
COINIT_SPEED_OVER_MEMORY Increase memory usage in an attempt to increase performance.
COINIT (objbase.h) - Win32 apps | Microsoft Learn
HRESULT result = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

同時実行モデルは、設定後に変更できません。変更しようとするとRPC_E_CHANGED_MODE (スレッド モードを設定してから変更することはできません。) が返されます。

以前のCoInitialize()では同時実行モデルは指定できず、既定でSTA (Single-Threaded Apartments) となります。CoInitialize function (objbase.h) - Win32 apps | Microsoft Learn

CoUninitialize()

現在のスレッドのCOMライブラリを閉じられます。同時にスレッドによって読み込まれたすべてのDLLがアンロードされ、スレッドが維持する他のリソースが解放され、スレッドのRPC接続が強制的に閉じられます。

void CoUninitialize();
CoUninitialize function (combaseapi.h) - Win32 apps | Microsoft Learn

オブジェクトの作成

CoCreateInstance()

HRESULT CoCreateInstance(
  [in]  REFCLSID  rclsid,
  [in]  LPUNKNOWN pUnkOuter,
  [in]  DWORD     dwClsContext, // 新しく作成したオブジェクトを管理するコードが、実行される状況 (コンテキスト/context)
  [in]  REFIID    riid,
  [out] LPVOID    *ppv
);
CoCreateInstance function (combaseapi.h) - Win32 apps | Microsoft Learn

rclsidが「error LNK2001: 外部シンボル "CLSID_***" は未解決です。」として見つからないならば、__uuidof(***)のように指定します。

dwClsContextには、CLSCTX列挙型から指定します。CLSCTX_ALLを指定した場合は、環境にもよりますがCLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVERと同義となります。

CLSCTX列挙型
列挙子 内容
CLSCTX_INPROC_SERVER 0x01 このクラスのオブジェクトを作成と管理するコードは、クラス コンテキストを指定する関数の呼び出し元と同じプロセスで実行されるDLL
CLSCTX_INPROC_HANDLER 0x02 このクラスのオブジェクトを管理するコードは、インプロセス ハンドラー。これはクライアント プロセスで実行されるDLLで、クラスのインスタンスがリモートからアクセスされるときに、このクラスのクライアント側の構造体を実装する
CLSCTX_LOCAL_SERVER 0x04 このクラスのオブジェクトを作成と管理するEXEコードは、同じマシンで実行されるが、分離したプロセスに読み込まれる
CLSCTX_REMOTE_SERVER 0x10 リモート コンテキスト
     
CLSCTX (wtypesbase.h) - Win32 apps | Microsoft Learn

同期

CoWaitForMultipleHandles()

HRESULT CoWaitForMultipleHandles(
  [in]  DWORD    dwFlags,
  [in]  DWORD    dwTimeout,
  [in]  ULONG    cHandles,
  [in]  LPHANDLE pHandles,
  [out] LPDWORD  lpdwindex
);
CoWaitForMultipleHandles function (combaseapi.h) - Win32 apps | Microsoft Learn

呼び出しスレッドがMTAに属するならば、この関数はWaitForMultipleObjectsEx()を呼びます。

アパートメント (Apartments)

アパートメントとは、コンテナ (クライアント) ごとに用意されるCOMコンポーネントを管理するグループです。The Apartment and the COM Threading Architecture - Processes, Threads, and Apartments - Win32 apps | Microsoft Learn

関連技術

ActiveX

ActiveXとは、ネットワークを通じて異なるコンピュータを連携させたり、データやプログラム部品をやり取りするための技術です。ActiveXとは - IT用語辞典 e-Words

  • OLE (Object Linking and Embedding) … アプリケーションソフトウェア間でデータを転送、共有するための仕組み。複合ドキュメント (compound documents)
    • COM (Component Object Model) … プログラムを部品化し、再利用するためのコンポーネント技術
      • ActiveX … インターネット関連技術の総称。インターネット対応コンポーネント (Internet-enabled components)
        • ActiveXコントロール … ActiveX仕様のソフトウェア コンポーネント。OLEコントロールを、インターネット対応に拡張したもの

ActiveXコントロール (ActiveX Control)

ActiveXコントロールとは、Webサーバからソフトウェア部品を受信し実行できる、Internet Explorerのコンポーネント技術です。これはCOMのインプロセス サーバ (DLL) として実現されています。

COM+

COMの改良版です。

複数の技術系サイトから、まとめて検索