COMとはプログラムを部品化し再利用するための技術で、これに基づいて作成された部品をCOMコンポーネントと呼びます。
すべてのCOMインターフェイスが継承するインターフェイスであり、他のインターフェイスへのポインタを取得したり、オブジェクトの実体を管理したりできます。IUnknown (unknwn.h) | Microsoft Learn
メソッド | 機能 |
---|---|
AddRef() | オブジェクトのインターフェイスの、参照カウントを増加させる。このメソッドは、オブジェクトのインターフェイスの新しいコピーごとに呼ばねばならない |
Release() | オブジェクトのインターフェイスの、参照カウントを減少させる。 |
QueryInterface(REFIID riid, void **ppvObject) | オブジェクトでサポートされているインターフェイスへの、ポインタを取得できる。 |
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;
ULONG AddRef();IUnknown::AddRef - Win32 apps | Microsoft Learn
新しい参照カウントが返されます。
ULONG Release();IUnknown::Release - Win32 apps | Microsoft Learn
新しい参照カウントが返されます。
オブジェクトでサポートされているインターフェイスへのポインタを取得できます。
HRESULT QueryInterface( REFIID riid, // 対象のインターフェイスの、インターフェイス識別子 (interface identifier / IID) への参照 void **ppvObject // riidで指定されたIIDがあるインターフェイスへのポインタのアドレス );IUnknown::QueryInterface(REFIID,void) (unknwn.h) | Microsoft Learn
riidとppvObjectは、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 |
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* __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()でアクセス違反となります。
BSTR __stdcall ConvertStringToBSTR( const char* pSrc )ConvertStringToBSTR | MSDN
呼び出し元のスレッドで使用できるように、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. |
HRESULT result = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
同時実行モデルは、設定後に変更できません。変更しようとするとRPC_E_CHANGED_MODE (スレッド モードを設定してから変更することはできません。) が返されます。
以前のCoInitialize()では同時実行モデルは指定できず、既定でSTA (Single-Threaded Apartments) となります。CoInitialize function (objbase.h) - Win32 apps | Microsoft Learn
現在のスレッドのCOMライブラリを閉じられます。同時にスレッドによって読み込まれたすべてのDLLがアンロードされ、スレッドが維持する他のリソースが解放され、スレッドのRPC接続が強制的に閉じられます。
void CoUninitialize();CoUninitialize function (combaseapi.h) - Win32 apps | Microsoft Learn
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_INPROC_SERVER | 0x01 | このクラスのオブジェクトを作成と管理するコードは、クラス コンテキストを指定する関数の呼び出し元と同じプロセスで実行されるDLL |
CLSCTX_INPROC_HANDLER | 0x02 | このクラスのオブジェクトを管理するコードは、インプロセス ハンドラー。これはクライアント プロセスで実行されるDLLで、クラスのインスタンスがリモートからアクセスされるときに、このクラスのクライアント側の構造体を実装する |
CLSCTX_LOCAL_SERVER | 0x04 | このクラスのオブジェクトを作成と管理するEXEコードは、同じマシンで実行されるが、分離したプロセスに読み込まれる |
CLSCTX_REMOTE_SERVER | 0x10 | リモート コンテキスト |
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()を呼びます。
アパートメントとは、コンテナ (クライアント) ごとに用意されるCOMコンポーネントを管理するグループです。The Apartment and the COM Threading Architecture - Processes, Threads, and Apartments - Win32 apps | Microsoft Learn
ActiveXとは、ネットワークを通じて異なるコンピュータを連携させたり、データやプログラム部品をやり取りするための技術です。ActiveXとは - IT用語辞典 e-Words
ActiveXコントロールとは、Webサーバからソフトウェア部品を受信し実行できる、Internet Explorerのコンポーネント技術です。これはCOMのインプロセス サーバ (DLL) として実現されています。
COMの改良版です。