VC++によるVBの為のCOMサーバー実装方法

 

前書き
引数のメモリ割り当て義務はどちらにあるか
戻り値のあるメソッド
参照渡し引数
可変個引数

 

 

前書き

ここでは、VBから利用可能なVC++(ATL)のCOMサーバーを作るための実装方法を事例別に紹介します。
内容は初歩的ではあるけれども、多少なりとも役に立つのではないかと思う。

 

 

引数のメモリ割り当て義務はどちらにあるか

in, outのそれぞれ、もしくはそれらを組み合わせた属性を持つ引数は、基本的にクライアントが受け持つことになる。従って以下のような定義があった場合、

MIDL

interface IClass : IDispatch{
	[ id(1) ]HRESULT Method( [in]long Targ, [out, retval]long* RetVal );

}

out属性の引数であるRetValには既に引数の領域が割り当てられているため、データ領域の確保は必要ない。

COMサーバー(C++)

STDMETHODIMP CClass::Method(long Targ, long* RetVal){
	*RetVal = Targ + 1;

	return S_OK;	
}

COMクライアント(VB/VBA/VBS)

Dim obj
Set obj = CreateObject("Component.Class")

Dim num As Long
num = 1
obj.Method num
MsgBox num	' 2と表示される

 

 

戻り値のあるメソッド

戻り値は、out, retval属性を適用した引数をメソッドの引数に用意することによって定義する。
引数はポインタでなければならない。

MIDL

interface IClass : IDispatch{
	[ id(1) ]HRESULT Method( [in]long Targ, [out, retval]long* RetVal );

}

COMサーバー(C++)

STDMETHODIMP CClass::Method(long Targ, long* RetVal){
	*RetVal = Targ + 1;

	return S_OK;	
}

COMクライアント(VB/VBA/VBS)

Dim obj
Set obj = CreateObject("Component.Class")

MsgBox obj.Method(99)	' 100と表示される

 

 

参照渡し引数

参照渡しという言葉が、COMの用語にあるかどうかは別として、同等の機能をCOMサーバに織り込むには、in, out属性によるインターフェース定義と、ポインタ引数による実装を必要とする。

MIDL

interface IClass : IDispatch{
	[ id(1) ]HRESULT Method( [in, out]long* Targ);

}

COMサーバー(C++)

STDMETHODIMP CClass::Method(long* Targ){
	*Targ = *Targ + 1;

	return S_OK;	
}

COMクライアント(VB/VBA/VBS)

Dim obj
Set obj = CreateObject("Component.Class")

Dim inc
inc = 99
obj.Method inc
MsgBox inc	' 100と表示される

 

 

可変個引数の受け渡し

可変個引数を表現する場合には、vararg 属性と、SAFEARRAY(VARIANT)データ型を併用する。
ただし、SAFEARRAY(...)というデータ型は、(少なくともVS6までの)VisualStudioのメソッド追加ダイアログでは指定できないので、ソースコードを直にいじる必要がある。 ※1

MIDL

interface IClass : IDispatch{
	[ id(1), vararg ]HRESULT Method( [in]SAFEARRAY(VARIANT) Args, [out, retval]BSTR* RetVal );

}

COMサーバー(C++)

STDMETHODIMP CClass::Method(SAFEARRAY* Array){


	〜Array を使った処理〜


	return S_OK;	
}

COMクライアント(VB/VBA/VBS)

Dim obj
Set obj = CreateObject("Component.Class")


MsgBox obj.Method(100, 200, 300)
MsgBox obj.Method("A","B","C","D")

補足

※1:
とはいっても、全てを手で書くのは面倒くさいし、よほどCOM/ATLを知っていなければ出来ない作業なので、まずは、ダミーとして「SAFEARRAY arg」というような引数を指定しておいて、置換で必要な部分だけ直すとかいう方法をとったほうが、いいかもしれない。