環境:XPSP3/VS2005
COM の言語:VC++
COM:インプロセスサーバ/デュアルインターフェイス
コンポーネント名:TestComp
インターフェイス名:TestIF
メソッド名:TestMethod
クライアントでの COM の初期化等
VC++ クライアント
#import "progid:TestComp.TestIF" no_namespace named_guids
...
CoInitialize(NULL);
CComPtr<ITestIF> pIF;
pIF.CoCreateInstance(CLSID_TestIF);
...
// 終了時
CoUninitialize();
VB クライアント
Dim obj As Object = CreateObject("TestComp.TestIF")
VC# クライアント
using System.Reflection;
...
Type t = Type.GetTypeFromProgID("TestComp.TestIF");
object target = t.InvokeMember(null, BindingFlags.CreateInstance, null, null, null);
BYTE 型 その1
クライアントからデータを渡す
COM サーバ
IDL メソッド宣言
[id(1), helpstring("メソッド TestMethod")] HRESULT TestMethod([in] BYTE prm);
クラスメンバ宣言
STDMETHOD(TestMethod)(BYTE prm);
メンバ関数実装
STDMETHODIMP CTestIF::TestMethod(BYTE prm)
{
TCHAR str[16];
_stprintf_s(str, _T("%d"), prm);
::MessageBox(NULL, (LPCWSTR)str, _T(""), MB_OK);
return S_OK;
}
VC++ クライアント
HRESULT hr;
BYTE var = 0;
hr = pIF->TestMethod(var);
if (FAILED(hr)) {
// エラー
}
VB クライアント
Dim var As Byte = 0
obj.TestMethod(var)
VC# クライアント
byte var = 0;
object[] args = { var }; // ボックス化
t.InvokeMember("TestMethod", BindingFlags.InvokeMethod, null, target, args);
BYTE 型 その2
サーバからデータをポインタ渡し
COM サーバ
IDL メソッド宣言
[id(1), helpstring("メソッド TestMethod")] HRESULT TestMethod([out] BYTE* prm);
クラスメンバ宣言
STDMETHOD(TestMethod)(BYTE* prm);
メンバ関数実装
STDMETHODIMP CTestIF::TestMethod(BYTE* prm)
{
*prm = 123;
return S_OK;
}
VC++ クライアント
HRESULT hr;
BYTE var = 0;
hr = pIF->TestMethod(&var);
if (FAILED(hr)) {
// エラー
}
_tprintf_s(_T("%d\n"), var);
VB クライアント
Dim var As Byte
obj.TestMethod(var)
Console.WriteLine(var)
VC# クライアント
byte var = 0;
object[] args = { var }; // ボックス化
ParameterModifier p = new ParameterModifier(1);
p[0] = true; // 1番目のパラメータの変更許可
ParameterModifier[] mods = { p };
t.InvokeMember("TestMethod", BindingFlags.InvokeMethod, null, target, args, mods, null, null);
var = (byte)args[0]; // ボックス化解除
Console.WriteLine(var);
BYTE 型 その3
サーバからデータを戻り値として返す
COM サーバ
IDL メソッド宣言
[id(1), helpstring("メソッド TestMethod")] HRESULT TestMethod([out,retval] BYTE* prm);
クラスメンバ宣言
STDMETHOD(TestMethod)(BYTE* prm);
メンバ関数実装
STDMETHODIMP CTestIF::TestMethod(BYTE* prm)
{
*prm = 123;
return S_OK;
}
VC++ クライアント
BYTE var = pIF->TestMethod();
_tprintf_s(_T("%d\n"), var);
VB クライアント
Dim var As Byte = obj.TestMethod()
Console.WriteLine(var)
VC# クライアント
byte var = 0;
var = (byte)t.InvokeMember("TestMethod", BindingFlags.InvokeMethod, null, target, null);
Console.WriteLine(var);
BSTR 型 その1
クライアントからデータを渡す
COM サーバ
IDL メソッド宣言
[id(1), helpstring("メソッド TestMethod")] HRESULT TestMethod([in] BSTR prm);
クラスメンバ宣言
STDMETHOD(TestMethod)(BYTE prm);
メンバ関数実装
#include "comutil.h" // _bstr_t
#pragma comment(lib, "comsuppw.lib") // _bstr_t
STDMETHODIMP CTestIF::TestMethod(BSTR prm)
{
_bstr_t str(prm);
::MessageBox(NULL, (LPCTSTR)str, _T(""), MB_OK);
return S_OK;
}
VC++ クライアント
HRESULT hr;
_bstr_t str = _T("test message");
BSTR bstr = str;
hr = pIF->TestMethod(bstr);
if (FAILED(hr)) {
//エラー
}
VB クライアント
Dim str As String = "test message"
obj.TestMethod(str)
VC# クライアント
string str = "test message";
object[] args = { str }; // ボックス化
t.InvokeMember("TestMethod", BindingFlags.InvokeMethod, null, target, args);
BSTR 型 その2
サーバからデータをポインタ渡し
COM サーバ
IDL メソッド宣言
[id(1), helpstring("メソッド TestMethod")] HRESULT TestMethod([out] BSTR* prm);
クラスメンバ宣言
STDMETHOD(TestMethod)(BSTR* prm);
メンバ関数実装
STDMETHODIMP CTestIF::TestMethod(BSTR* prm)
{
CComBSTR bstr(L"test message");
*prm = bstr;
return S_OK;
}
VC++ クライアント
HRESULT hr;
BSTR bstr;
hr = pIF->TestMethod(&bstr);
if (FAILED(hr)) {
// エラー
}
_bstr_t str(bstr);
_tprintf_s(_T("%s\n"), (LPCTSTR)str);
VB クライアント
Dim str As String = ""
obj.TestMethod(str)
Console.WriteLine(str)
VC# クライアント
string str = "";
object[] args = { str }; // ボックス化
ParameterModifier p = new ParameterModifier(1);
p[0] = true; // 1番目のパラメータの変更許可
ParameterModifier[] mods = { p };
t.InvokeMember("TestMethod", BindingFlags.InvokeMethod, null, target, args, mods, null, null);
str = (string)args[0]; // ボックス化解除
Console.WriteLine(str);
BSTR 型 その3
サーバからデータを戻り値として返す
COM サーバ
IDL メソッド宣言
[id(1), helpstring("メソッド TestMethod")] HRESULT TestMethod([out,retval] BSTR* prm);
クラスメンバ宣言
STDMETHOD(TestMethod)(BSTR* prm);
メンバ関数実装
STDMETHODIMP CTestIF::TestMethod(BSTR* prm)
{
CComBSTR bstr(L"test message");
*prm = bstr;
return S_OK;
}
VC++ クライアント
BSTR bstr = pIF->TestMethod();
_bstr_t str(bstr);
_tprintf_s(_T("%s\n"), (LPCTSTR)str);
VB クライアント
Dim str As String = obj.TestMethod()
Console.WriteLine(str)
VC# クライアント
string str = (string)t.InvokeMember("TestMethod", BindingFlags.InvokeMethod, null, target, null);
Console.WriteLine(str);
配列のやり取り その1
クライアントからデータを渡す
SAFEARRAY で 1 バイトサイズの配列を構築したものを VARIANT 型にラップしてパラメータとする。
(VARIANT(SAFEARRAY(BYTE[x])) な感じ)
COM サーバ
IDL メソッド宣言
[id(1), helpstring("メソッド TestMethod")] HRESULT TestMethod([in] VARIANT prm);
クラスメンバ宣言
STDMETHOD(TestMethod)(VARIANT prm);
メンバ関数実装 その1
CComSafeArray 型を使う
#include "atlsafe.h"
STDMETHODIMP CTestIF::TestMethod(VARIANT prm)
{
HRESULT hr;
CComSafeArray<BYTE> sa;
if ((V_VT(prm) & (VT_ARRAY | VT_UI1)) != (VT_ARRAY | VT_UI1)) {
// BYTE型配列ではないのでエラー
}
// SAFEARRAY アタッチ
if (V_VT(&prm) & VT_BYREF) {
hr = sa.Attach(*V_ARRAYREF(&prm));
if (FAILED(hr)) {
// Attach エラー
}
} else {
hr = sa.Attach(V_ARRAY(&prm));
if (FAILED(hr)) {
// Attach エラー
}
}
// 配列にアクセスする処理
// 例えば…
ULONG size = sa.GetCount();
BYTE *pbuf = (BYTE*)CoTaskMemAlloc(size);
if (pbuf == NULL) {
// CoTaskMemAlloc エラー
}
// コピーとか…
for (ULONG i=0; i<size; i++) {
*(pbuf+i) = sa.GetAt(i);
}
// メモリ解放
CoTaskMemFree(pbuf);
// SAFEARRAY デタッチ
sa.Detach();
return S_OK;
}
メンバ関数実装 その2
SAFEARRAY 型を使う
STDMETHODIMP CTestIF::TestMethod(VARIANT prm)
{
HRESULT hr;
SAFEARRAY *psa;
BYTE *p;
if ((V_VT(prm) & (VT_ARRAY | VT_UI1)) != (VT_ARRAY | VT_UI1)) {
// BYTE型配列ではないのでエラー
}
if (V_VT(&prm) & VT_BYREF) {
psa = *V_ARRAYREF(&prm);
} else {
psa = V_ARRAY(&prm);
}
// ロック処理
hr = SafeArrayAccessData(psa, (void**)&p);
if (FAILED(hr)) {
// SafeArrayAccessData エラー
}
// 配列にアクセスする処理
// 例えば…
LONG minidx, maxidx, size;
BYTE *pbuf;
// 配列のサイズを取得
hr = SafeArrayGetLBound(psa, 1, &minidx);
if (FAILED(hr)) {
// SafeArrayGetLBound エラー
}
hr = SafeArrayGetUBound(psa, 1, &maxidx);
if (FAILED(hr)) {
// SafeArrayGetUBound エラー
}
size = maxidx - minidx + 1;
pbuf = (BYTE*)CoTaskMemAlloc(size);
if (pbuf == NULL) {
// CoTaskMemAlloc エラー
}
// コピーとか…
memcpy(pbuf, p, idx+1);
// アンロック処理
hr = SafeArrayUnaccessData(psa);
if (FAILED(hr)) {
// SafeArrayUnaccessData エラー
}
// メモリ解放
CoTaskMemFree(pbuf);
return S_OK;
}
VC++ クライアント その1
CComVariant, CComSafeArray を使う
#include "atlsafe.h"
...
HRESULT hr;
BYTE buf[5] = {1, 2, 3, 4, 5}; // サーバに渡すデータ内容
CComSafeArray<BYTE> sa(sizeof(buf));
CComVariant var;
// CComSafeArray 準備
for (int i=0; i<sizeof(buf); i++) {
hr = sa.SetAt(i, buf[i]);
if (FAILED(hr)) {
// SetAt error.
}
}
// CComVariant 準備
V_VT(&var) = VT_UI1 | VT_ARRAY | VT_BYREF;
V_ARRAYREF(&var) = sa.GetSafeArrayPtr();
// メソッドコール
pIF->TestMethod(var);
VC++ クライアント その2
VARIANT, SAFEARRAY 型を使う
HRESULT hr;
BYTE buf[5] = {1, 2, 3, 4, 5}; // サーバに渡すデータ内容
SAFEARRAYBOUND bnd;
SAFEARRAY *psa;
VARIANT var;
BYTE *p;
// SAFEARRAY 準備
bnd.lLbound = 0; // 配列のインデックスは 0 オリジン
bnd.cElements = sizeof(buf); // 要素数
psa = SafeArrayCreate(VT_UI1, 1, &bnd);
if (psa == NULL) {
// SafeArrayCreate エラー
}
// ロック処理
hr = SafeArrayAccessData(psa, (void**)&p);
if (FAILED(hr)) {
// SafeArrayAccessData エラー
}
// 配列にアクセスする処理
memcpy(p, buf, sizeof(buf));
// アンロック処理
hr = SafeArrayUnaccessData(psa);
if (FAILED(hr)) {
// SafeArrayUnaccessData エラー
}
// VARIANT 準備
VariantInit(&var);
V_VT(&var) = VT_UI1 | VT_ARRAY | VT_BYREF;
V_ARRAYREF(&var) = &psa; // SAFEARREY を突っ込む
// メソッドコール
pIF->TestMethod(var);
// SAFEARRAY 解放
hr = SafeArrayDestroy(psa);
if (FAILED(hr)) {
// SafeArrayDestroy エラー
}
VB クライアント
Dim buf() As Byte = {1, 2, 3, 4, 5}
obj.TestMethod(buf) ' そのまま突っ込む
VC# クライアント
byte[] buf = {1, 2, 3, 4, 5};
object[] args = { buf }; // ボックス化
t.InvokeMember("TestMethod", BindingFlags.InvokeMethod, null, target, args);
配列のやり取り その2
サーバからデータをポインタ渡し
SAFEARRAY で 1 バイトサイズの配列を構築したものを VARIANT 型にラップしてパラメータとする。
(VARIANT(SAFEARRAY(BYTE[x])) な感じ)
COM サーバ
IDL メソッド宣言
[id(1), helpstring("メソッド TestMethod")] HRESULT TestMethod([out] VARIANT* prm);
クラスメンバ宣言
STDMETHOD(TestMethod)(VARIANT* prm);
メンバ関数実装 その1
CComSafeArray 型を使う
STDMETHODIMP CTestIF::TestMethod(VARIANT* prm)
{
HRESULT hr;
BYTE buf[5] = {6, 7, 8, 9, 10}; // クライアントに渡すデータ内容
CComSafeArray<BYTE> sa(sizeof(buf));
if ((V_VT(prm) & (VT_ARRAY | VT_UI1)) != (VT_ARRAY | VT_UI1)) {
// BYTE型配列ではないのでエラー
}
// CComSafeArray 準備
for (int i=0; i<sizeof(buf); i++) {
hr = sa.SetAt(i, buf[i]);
if (FAILED(hr)) {
// SetAt エラー
}
}
// クライアントに渡す
if (V_VT(prm) & VT_BYREF) {
hr = sa.CopyTo(V_ARRAYREF(prm));
if (FAILED(hr)) {
// CopyTo エラー
}
} else {
hr = sa.CopyTo(&V_ARRAY(prm)); // "&V_ARRAY(prm)" で良いのか不明
if (FAILED(hr)) {
// CopyTo エラー
}
}
return S_OK;
}
メンバ関数実装 その2
SAFEARRAY 型を使う
STDMETHODIMP CTestIF::TestMethod(VARIANT* prm)
{
HRESULT hr;
BYTE buf[5] = {6, 7, 8, 9, 10}; // クライアントに渡すデータ内容
SAFEARRAYBOUND bnd;
SAFEARRAY *psa;
BYTE *p;
if ((V_VT(prm) & (VT_ARRAY | VT_UI1)) != (VT_ARRAY | VT_UI1)) {
// BYTE型配列ではないのでエラー
}
// SAFEARRAY 準備
bnd.lLbound = 0; // 配列のインデックスは 0 オリジン
bnd.cElements = sizeof(buf); // 要素数
psa = SafeArrayCreate(VT_UI1, 1, &bnd);
if (psa == NULL) {
// SafeArrayCreate エラー
}
// ロック処理
hr = SafeArrayAccessData(psa, (void**)&p);
if (FAILED(hr)) {
// SafeArrayAccessData エラー
}
// 配列にアクセスする処理
memcpy(p, buf, sizeof(buf));
// アンロック処理
hr = SafeArrayUnaccessData(psa);
if (FAILED(hr)) {
// SafeArrayUnaccessData エラー
}
// クライアントに渡す
if (V_VT(prm) & VT_BYREF) {
hr = SafeArrayCopy(psa, V_ARRAYREF(prm));
if (FAILED(hr)) {
// SafeArrayCopy エラー
}
} else {
hr = SafeArrayCopy(psa, &V_ARRAY(prm)); // "&V_ARRAY(prm)" で良いのか不明
if (FAILED(hr)) {
// SafeArrayCopy エラー
}
}
// SAFEARRAY 解放
hr = SafeArrayDestroy(psa);
if (FAILED(hr)) {
// SafeArrayDestroy エラー
}
return S_OK;
}
VC++ クライアント その1
CComVariant, CComSafeArray を使う
#include "atlsafe.h"
...
HRESULT hr;
CComSafeArray<BYTE> sa;
CComVariant var;
// CComVariant 準備
V_VT(&var) = VT_UI1 | VT_ARRAY | VT_BYREF;
V_ARRAYREF(&var) = sa.GetSafeArrayPtr();
// メソッドコール
pIF->TestMethod(&var);
// データ確認
for (ULONG i=0, i<sa.GetCount(); i++) {
_tprintf_s(_T("%d "), sa.GetAt(i));
}
_tprintf_s(_T("\n"));
// SAFEARRAY デタッチ
sa.Detach();
VC++ クライアント その2
VARIANT, SAFEARRAY 型を使う
HRESULT hr;
SAFEARRAYBOUND bnd;
SAFEARRAY *psa;
VARIANT var;
BYTE *p;
// SAFEARRAY 準備
bnd.lLbound = 0; // 配列のインデックスは 0 オリジン
bnd.cElements = 0; // 要素数(空)
psa = SafeArrayCreate(VT_UI1, 1, &bnd);
if (psa == NULL) {
// SafeArrayCreate エラー
}
// VARIANT 準備
VariantInit(&var);
V_VT(&var) = VT_UI1 | VT_ARRAY | VT_BYREF;
V_ARRAYREF(&var) = &psa; // SAFEARREY を突っ込む
// メソッドコール
pIF->TestMethod(&var);
// ロック処理
hr = SafeArrayAccessData(psa, (void**)&p);
if (FAILED(hr)) {
// SafeArrayAccessData エラー
}
// 配列にアクセスする処理
// 例えば…
LONG minidx, maxidx, size;
// 配列のサイズを取得
hr = SafeArrayGetLBound(psa, 1, &minidx);
if (FAILED(hr)) {
// SafeArrayGetLBound エラー
}
hr = SafeArrayGetUBound(psa, 1, &maxidx);
if (FAILED(hr)) {
// SafeArrayGetUBound エラー
}
size = maxidx - minidx + 1;
// データ確認
for (LONG i=0; i<size; i++) {
_tprintf_s(_T("%d "), *(p+i));
}
_tprintf_s(_T("\n"));
// アンロック処理
hr = SafeArrayUnaccessData(psa);
if (FAILED(hr)) {
// SafeArrayUnaccessData エラー
}
// SAFEARRAY 解放
hr = SafeArrayDestroy(psa);
if (FAILED(hr)) {
// SafeArrayDestroy エラー
}
VB クライアント
Dim buf(0) As Byte
obj.TestMethod(buf) ' そのまま突っ込む
Console.WriteLine("{0} {1} {2} {3} {4}", buf(0), buf(1), buf(2), buf(3), buf(4))
VC# クライアント
byte[] buf = { };
object[] args = { buf }; // ボックス化
ParameterModifier p = new ParameterModifier(1);
p[0] = true; // 1番目のパラメータの変更許可
ParameterModifier[] mods = { p };
t.InvokeMember("TestMethod", BindingFlags.InvokeMethod, null, target, args, mods, null, null);
buf = (byte[])args[0]; // ボックス化解除
Console.WriteLine("{0} {1} {2} {3} {4}", buf[0], buf[1], buf[2], buf[3], buf[4]);
最終更新:2012年03月19日 10:17