ComWrapper
方法
Fooのラッパを作る。(以下、C++を前提とする)
元のクラス
class Foo { public: void doFoo(); char* getChars(); void setChars(char* p); }
IDL
[ object, uuid( /** GUIDGENで生成したGUIDを埋める **/ ), pointer_default(unique) ] interface IFoo : IUnknown { HRESULT doFoo(); HRESULT getChars([out, string]char** ppResult); /* outの長さ属性にstringが書けるかちょっと自信ない。*/ HRESULT getCharsWithLength([out]short* length, [out, size_is(,*length)] char** ppResult); /* 別解 バイナリデータ用 */ HRESULT setChars([in, string]char* chars); };
実装
APIはうろ覚えなので、間違えている可能性がある。
#include "idlgen.h" // IDLが生成したヘッダのIFooを参照 public class FooWrapper : IFoo { Foo* foo; int refCount; FooWrapper(Foo* initFoo) { foo = initFoo; refCount = 1; // 生成されたら1 } ~FooWrapper() // 常識的にはvirtual宣言すべきだが、派生は考えないのでこれで良いことにする { delete foo; } HRESULT STDCALLTYPE QueryInterface(const IID& riid, void** ppv) { if (IsEqualIID(riid, GUID_IUnknown) || IsEqualIID(riid, GUID_IFoo)) { refCount++; *ppv = this; return S_OK; } return E_NOINTERFACE; } ULONG AddRef() { return ++refCount; } ULONG Release() { ULONG ret = --refCount; if (!ret) { delete this; } return ret; } HRESULT doFoo() { try { foo->doFoo(); } catch { // C++の例外の書き方忘れた return E_EXCEPTION; } return S_OK; } HRESULT getChars(unsigned char** out) // 確かmidlがcharをunsigned charに変換すると記憶している { if (!out) return E_POINTER; // ヒープかどうかのチェックもすべき char* result =foo->getChars(); int size = strlen(result); *out = CoTaskMemAlloc(size + 1); if (!*out) return E_NOMEMORY; strcpy(reinterpret_cast<char*>(*out), result); return S_OK; } HRESULT getCharsWithLength(short* length, unsigned char** out) { if (!length || !out) return E_POINTER; char* result =foo->getChars(); *length = reinterpret_cast<short>(strlen(result)); *out = CoTaskMemAlloc(*length); if (!*out) return E_NOMEMORY; memcpy(*out, result, *length); return S_OK; } HRESULT setChars(unsigned char* p) { foo->setChars(reinterpret_cast<char*>(p)); return S_OK; } }
返す側
HRESULT getFoo(IFoo** pp) { if (pp == NULL) return E_POINTER; *pp = new FooWrapper(new Foo()); // refcount == 1 return S_OK; }
使う側
IFoo* p; if (Supplier->getFoo(&p) == S_OK) { p->doFoo(); ... unsigned char* mem = p->getChars(); ... CoTaskMemFree(mem); ... p->Release(); // refcount == 0 -> deleteされる }
Keyword(s):
References: