アマプログラマーの独り言
VBのコールバック関数へ文字列を渡す方法 2002年03月31日 |
例えばVC++なんかでDLLファイルを作って、それをVBからAddressOfで関数ポインタを渡し、その関数、つまりコールバック関数へ文字列を渡す方法です。 ちなみにちょっと無理矢理っぽいです。 既に知ってたらごめんなさい。 ではコードです。 ----------------------------------------------------- VC++側 // 宣言とかは適当に合わせてください int CALLBACK CallBack(int *VB_Func) { int (*Func)(long, int); char *str = "ABCDEFG"; Func = (int(*)(long, int))VB_Func; Func((long)str, 8); return 0; } ----------------------------------------------------- VB側 ' ここも型とかは適当に合わせてください ' API宣言 ' VC++製 Private Declare Function CallBack Lib "xxx.dll" (ByVal VB_Func As Long) As Long ' MoveMemory(宣言はプロトタイプと異なってます) Private Declare Function MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As String, ByVal Source As Long, ByVal Length As Long) As Long ' メイン Public Sub Main() Call CallBack(AddressOf Func) End Sub ' コールバック関数 Public Function Func (ByVal p As Long, ByVal Length As Long) As Long Dim tmp As String tmp = String$(Length, vbNullChar) Call MoveMemory(tmp, p, Length) Debug.Print tmp End Function ----------------------------------------------------- 結果(イミディエイト) ABCDEFG ----------------------------------------------------- まずVC++側ではchar型へのポインタをlong型にキャストし、アドレスを直接渡します。 VB側では貰ったそのアドレスを、MoveMemoryへ渡します。 MoveMemory関数内ではそれを「ポインタ」だと処理し、VC++側で設定した「ABCDEFG」という文字列を参照してくれます。 コールバック2番目の引数は最終NULL文字を含めた長さです。直接数値を渡してますがstrlen()関数でもOKです。 では何故こんなメンドイやり方をしているかと言うと、それはVBの「String型」のせいです。 VBの文字列型の初期サイズは0バイトです。つまり領域が0なんです。 API関数を使う場合、必ず領域の確保を行わなければなりません。 当然引数にサイズを指定する事はできないので、もしString型で受け取ろうとすると「VB6が原因でxxx.dll内にエラーが起きました」という危なっかしいエラーと共にVBが落ちるでしょう。 Cなどでは「ポインタ」という便利なもの(しかし難しいもの)があるので、こういう問題はおきません。 他の言語は知りません。 |