本記事では、WindowsのCOMライブラリを扱いやすくしてくれるcom_ptr_tクラスを紹介したいと思います。
com_ptr_tは、IUnknownインターフェースのQueryInterface、AddRef、Releaseメンバ関数周りを隠蔽してくれるテンプレートクラスで、いわゆるスマートポインタの一種です。
_com_ptr_tは、単体でもそれなりに便利ですが、これがVisual C++の色々な機能と結びついてさらに便利になっています。
例えばMSXML3を使ってXMLファイルを読み込むコードが、_com_ptr_tを使ってどのように簡単になるのかを見てみましょう。
#import "msxml3.dll" named_guids int main(int argc, char* argv[]) { // COMライブラリ初期化 ::CoInitialize(NULL); try { MSXML2::IXMLDOMDocument2Ptr pDoc; pDoc.CreateInstance(MSXML2::CLSID_DOMDocument); pDoc->async = false; if (pDoc->load(L"test.xml")) { // Root要素名を表示する printf("RootNodeName: %s\n",static_cast<const char*>(pDoc->documentElement->nodeName)); // Root要素の子要素一覧 MSXML2::IXMLDOMNodeListPtr pList = pDoc->documentElement->childNodes; for (long i = 0, n = pList->length; i < n; ++i) { MSXML2::IXMLDOMElementPtr pElement = pList->Getitem(i); if (pElement) { // 子ノードが要素の場合のみ処理する printf("ChildNodeName: %s\n",static_cast<const char*>(pElement->nodeName)); } } } }catch (_com_error& e) { // 例外ハンドラ printf("Error: %s\n", e.ErrorMessage()); } // COMライブラリ終了 ::CoUninitialize(); return 0; }
面倒なQueryInterface、AddRef、Releaseが綺麗に消えていることが分かると思います。VBScriptに近いお手軽さです。
ところで、上記コードには、_com_ptr_tという文字列は存在しないということに注意して下さい。
_com_ptr_tが使われているのは、上記#importによって自動生成されるmsxml3.tlhというヘッダファイルの中です。ここに、
typedef _com_ptr_t<IXMLDOMDocument2, &__uuidof(IXMLDOMDocument2)> IXMLDOMDocument2Ptr; typedef _com_ptr_t<IXMLDOMElement, &__uuidof(IXMLDOMElement)> IXMLDOMDocument2Ptr;
というような感じの定義があるのです。
何か不都合があると、_com_error例外を投げてくれるのもありがたいところです。例外処理がシンプルになります。
一度COM周りのコードを書いた人なら分かると思いますが、_com_ptr_tを使わずに上記のコードを書いてみると、相当大変です。_com_ptr_t万歳。
一応最後に書いておきますが、_com_ptr_tは、MSXML3に限らず、他のCOMインターフェースに対しても使えます。例えば、CreateStreamOnHGlobalで取得したIStreamをIStreamPtrに代入して・・・ということもできますし、DirectX9周りで活用することもできます。色々と試してみて下さい。
但し、_com_ptr_tは、Visual C++の独自機能を相当使っているはずです。移植性が必要な場合は、使わない方が良いでしょう。