はじめに
VB6ではIEの履歴を消す際に、DispCallFuncが広く利用されています。DispCallFuncはIUnknownインターフェースを呼び出すためのAPIとして知られていますが、実は第1引数にNULLを渡すことで、COM以外の関数も実行することができます。ただ、第6引数と第7引数の使い方にとてもくせがあり、その説明が世の中にあまりなかったので、今回、まとめてみます。
なお、本稿は作者が自身のホームページに作成した記事を再編集したものです。
対象読者
- Excel VBAなどのOffice VBA言語でC言語モジュールとの連携をお考えの方
必要な環境
- Windows OS
- Microsoft Office(32ビット版に限る)
VBAでのDispCallFuncAPIを利用した関数ポインタの実行方法
DispCallFuncAPIの引数
DispCallFuncの引数は、MSDNによれば次のとおりです。
HRESULT DispCallFunc( void *pvInstance, ULONG_PTR oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals, VARTYPE *prgvt, VARIANTARG **prgpvarg, VARIANT *pvargResult );
第1引数:pvInstance
今回は、COM以外の関数を呼び出すので、常に0を設定します。
第2引数:oVft
関数のアドレスを渡します。
第3引数:cc
関数の呼び出し規約を渡します。CALLCONVは、OAIdl.hに以下の値が定義されています。
enum tagCALLCONV { CC_FASTCALL = 0, CC_CDECL = 1, CC_MSCPASCAL = CC_CDECL + 1, CC_PASCAL = CC_MSCPASCAL, CC_MACPASCAL = CC_PASCAL + 1, CC_STDCALL = CC_MACPASCAL + 1, CC_FPFASTCALL = CC_STDCALL + 1, CC_SYSCALL = CC_FPFASTCALL + 1, CC_MPWCDECL = CC_SYSCALL + 1, CC_MPWPASCAL = CC_MPWCDECL + 1, CC_MAX = CC_MPWPASCAL + 1 } CALLCONV;
一般的なWIN32API関数にはCC_STDCALL(=4)を用います。C言語専用に作られた関数にはCC_CDECL(=1)を用います。
第4引数:vtReturn
関数の戻り値の型を示すVbVarType列挙型の値を設定します。関数が戻り値を返さない(VBでいうSubプロシージャの)場合は、vbEmptyを設定します。VARTYPEは、WTypes.hに以下のように定義されています。
typedef unsigned short VARTYPE;
符号の有無を無視すれば、VBのInteger型に相当します。
第5引数:cActuals
関数の引数の個数を設定します。
第6引数:prgvt
関数の引数の型を示すVbVarType列挙型の値をInteger型の配列に格納して、配列の先頭アドレスを渡します。ただし、引数の個数が0個の場合は、0を渡します。
第7引数:prgpvarg
関数の引数をそれぞれいったんVariant型に格納し直し、別途用意したLong型の配列にその各Variant変数のアドレスを格納して、配列の先頭アドレスを渡します。ただし、引数の個数が0個の場合は、0を渡します。
第8引数:pvargResult
関数の戻り値を格納するための空のVariant型変数を用意し、そのアドレスを渡します。そして、DispCallFunc APIの戻り値はLong型で、関数の呼び出しに成功するとS_OKが返ってきます。
DispCallFuncのAPI宣言
VBのAPI宣言と列挙体の宣言は、一例として次のようになります。
Private Declare Function DispCallFunc Lib "OleAut32.dll" _ (ByVal pvInstance As Long, _ ByVal oVft As Long, _ ByVal cc As Long, _ ByVal vtReturn As Integer, _ ByVal cActuals As Long, _ ByVal prgvt As Long, _ ByVal prgpvarg As Long, _ ByVal pvargResult As Long) As Long Enum tagCALLCONV CC_FASTCALL = 0 CC_CDECL = 1 CC_MSCPASCAL = CC_CDECL + 1 CC_PASCAL = CC_MSCPASCAL CC_MACPASCAL = CC_PASCAL + 1 CC_STDCALL = CC_MACPASCAL + 1 CC_FPFASTCALL = CC_STDCALL + 1 CC_SYSCALL = CC_FPFASTCALL + 1 CC_MPWCDECL = CC_SYSCALL + 1 CC_MPWPASCAL = CC_MPWCDECL + 1 CC_MAX = CC_MPWPASCAL End Enum