The Backyard - ComWrapper Diff
- Added parts are displayed like this.
- Deleted parts are displayed
like this.
!目的
C++のクラスFooをCOMのインターフェイスを使って異なるオブジェクト間でやりとりしたい。
!! 注意
IDLの書式やマクロ、APIがそのままコンパイル可能かどうかは未検証(多分、間違いを含む)
!方法
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される
}
!更新履歴
* 2007/02/02 midlが生成するヘッダではcharがunsigned charになる(と思った)を反映
* 2007/02/02 メモリーアロケーションのバグを修正
* 2007/02/02 長さパラメータ付きメソッドを追加
C++のクラスFooをCOMのインターフェイスを使って異なるオブジェクト間でやりとりしたい。
!! 注意
IDLの書式やマクロ、APIがそのままコンパイル可能かどうかは未検証(多分、間違いを含む)
!方法
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される
}
!更新履歴
* 2007/02/02 midlが生成するヘッダではcharがunsigned charになる(と思った)を反映
* 2007/02/02 メモリーアロケーションのバグを修正
* 2007/02/02 長さパラメータ付きメソッドを追加