Shoeisha Technology Media

CodeZine(コードジン)

記事種別から探す

VBAでの関数ポインタの利用方法

cdecl呼び出し規約のDLL関数をVBAから利用する方法

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2012/10/05 14:00

 VBAやVB6では関数ポインタを利用することができません。また、declare functionを使ってdll内の関数を実行する際にもstdcall呼び出し規約で作られた関数しか呼び出すことができません。これらの制約は、DispCallFunc APIを利用することで回避することが可能です。本稿では、Excel VBAをはじめとするVBAやVB6.0において、DispCallFuncAPIを使って関数ポインタを実行する方法を紹介します。

目次

はじめに

 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

  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • 山城 章仁(ヤマシロ アキヒト)

    新入社員の頃、ホストコンピュータでのCOBOLプログラムの開発を行う部署に配属され、そのときの先輩社員の方に 「Excelのマクロはすごいぞ。あれを覚えたら、あれだけで食っていけるぞ」と言われたのをきっかけに、Excelのマクロに傾倒し、Excelのマクロでの不可能をなくすためにWindowsAP...

All contents copyright © 2005-2017 Shoeisha Co., Ltd. All rights reserved. ver.1.5