COM スマートポインタの基本
C++、COM、_com_ptr_t
本記事の前提条件は以下の通りです。
- 初心者向け
- とは言っても、何らかのプログラムはそれなりに書けるけど、C とか C++ はちょっと、という人向け
- ざっくり概要しか説明しないので細かいことは気にしないでいただきたい
- Visual Studio 2013 くらい~
- Windowsプログラム (CUI, GUI)
- コードの検証
- 開発環境: Visual Studio 2022, x64, Release ビルド
- 実行環境: Windows 10
- 本記事は上から順番に読む前提となっている
- 「Visual Studio 2013 くらい~」と書いてあるが、本記事の内容だと現在過去未来のどのバージョンでもほぼ同じ
COM スマートポインタを使う
_com_ptr_tを使うわけだが、そのまま使おうとすると、
#include <comdef.h>
_com_ptr_t<_com_IIID<IPlayback, &__uuidof(IPlayback)>> pPlayback;
pPlayback.CreateInstance(...);
と、ややこしいので、素直に .tlh
にある _COM_SMARTPTR_TYPEDEF
マクロを利用する。
_COM_SMARTPTR_TYPEDEF
マクロは、インターフェースが IPlayback
であれば、IPlaybackPtr
というスマートポインタを定義してくれるので、以下のように書けるようになる。
#include <comdef.h>
IPlaybackPtr pPlayback;
pPlayback.CreateInstance(CLSID_MusicPlayer, NULL, CLSCTX_INPROC_SERVER);
pPlayback->Play();
pPlayback->Stop();
メリット
RAII によるリソース管理
Release
の呼び出しは COM スマートポインタが RAII に基づいて処理してくれるので不要になる。
#include <comdef.h>
IPlaybackPtr pPlayback;
pPlayback.CreateInstance(CLSID_MusicPlayer, NULL, CLSCTX_INPROC_SERVER);
pPlayback->Play();
pPlayback->Stop();
// pPlaybackがスコープを抜ける時に自動的にReleaseされる
//pPlayback->Release();
不要になるというか、明示的に呼び出すと参照カウントが異常になるので、注意が必要。
キャストによる COM インターフェース取得
COM スマートポインタのキャスト(コピーコンストラクタ、コピー代入演算子、型変換演算子)はすべて QueryInterface
の呼び出しによる COM インターフェースの取得処理となる。
すべて、と言っても、あくまでも、COM スマートポインタから 別の型の COM スマートポインタにキャストする場合。
したがって、COM スマートポインタを使わない場合に下記のように書いていたものが、
IPlayback* pPlayback;
CoCreateInstance(CLSID_MusicPlayer,
NULL,
CLSCTX_INPROC_SERVER,
IID_IPlayback,
(void**)&pPlayback);
pPlayback->Play();
pPlayback->Stop();
IVolumeControl* pVolumeControl;
pPlayback->QueryInterface(IID_IVolumeControl, (void**)&pVolumeControl);
pVolumeControl->Up();
pVolumeControl->Down();
pVolumeControl->Release();
pPlayback->Release();
次のように書けることになる。
IPlaybackPtr pPlayback;
pPlayback.CreateInstance(CLSID_MusicPlayer,
NULL,
CLSCTX_INPROC_SERVER);
pPlayback->Play();
pPlayback->Stop();
IVolumeControlPtr pVolumeControl{ pPlayback };
pVolumeControl->Up();
pVolumeControl->Down();
便利である。
便利ではあるが、QueryInterface
を考えればすぐわかるが、いつキャストが失敗するかわからない、ということと、_com_ptr_t
自体がテンプレートクラスであり、コンパイル時、いかなる COM インターフェース間のキャストであっても呼び出しを解決してコンパイル出来てしまう、というところに注意が必要である。
以上。