ゆとりーなの日記

日記的な事を書いて行くと思はれる

_com_ptr_tとかいうのがあった

 COMを扱うときのスマートポインタとしてはCComPtrが個人的には勝手に有名だと思っていたのですが、VC++のExpressにはいない子なので使えない子とか思っていたら_com_ptr_tなるものがあることが判明しました。こんな感じに使えるようです。型の宣言が元と違って面倒くさいです。

#include <comip.h>

typedef _com_ptr_t<_com_IIID<ID2D1Factory, &__uuidof(ID2D1Factory)>> d2d1_factory_ptr;

void hoge() {
  d2d1_factory_ptr factory;
  if (FAILED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &factory))) {
    throw std::runtime_error("D2D1ファクトリ作成に失敗しました。");
  }
}

 スマポなのでCOMに付き物のReleaseとかは不要です。初期化の際も&演算子オーバーロードされており、保持しているポインタのアドレスを返すようになっているので初期化も簡単といえば簡単です。
 で、当然ながらこの&演算子を使って書き換えようとした場合スマポとしての体裁を保つためにもともと持っていたものはReleaseされます。本来であれば書き換えが発生する場合のみにReleaseしたいところなのでしょうが、そんな贅沢を実現するのは夢物語なので&演算子を使った瞬間にReleaseされます。
 というわけでちょっとスマポのアドレスでも取ってみるかと(オーバーロードされているので取れませんが、この場合はboost::addressofとかを使うのが正解ですかね。)安易に&factoryとかやると保持していたCOMがReleaseされ、以降保持していた(はずの)COMインターフェイスにアクセスしようとすると残当するわけです。まぁこれは間違った使い方なので仕方ないですがこういうあまり直感的ではないものに演算子オーバーロードを使うのはどうなのかとか思うわけですよ。まぁ覚えてしまえば便利なんですけどね。まぁ実質スマポのアドレスが欲しい時とか殆どありませんし。
 あとはCOM生ポを直接突っ込むと参照カウントが一つ増えるという罠があるので既にあるCOMポインタの管理を任せたい時とかはAttachメソッドを使うという感じですね。

void hoge() {
  // リソースリークする罠達
  _com_ptr_t<_com_IIID<IDirect3D9, &__uuidof(IDirect3D9)>> direct3d9(Direct3DCreate9(D3D_SDK_VERSION));
  direct3d9 = Direct3DCreate9(D3D_SDK_VERSION);
  
  // こっちが正解
  _com_ptr_t<_com_IIID<IDirect3D9, &__uuidof(IDirect3D9)>> direct3d9;
  direct3d9.Attach(Direct3DCreate9(D3D_SDK_VERSION));
}

追記:comsuppw.libかcomsuppwd.libのリンクが必要なようです。