- ベストアンサー
構造体配列を引数とするDLL作成し、VBで呼ぶには?
はじめまして。 VisualC++6.0でDLLを作り、VisualBasic6.0にて VisualC++の関数をコールし、構造体配列の値を 渡そうとしていますがうまくいきません。 どなたかよい知恵をお貸しください。 宜しくお願い致します。 下記に、VisualC++6.0とVisualBasic6.0のやりとり を記します。 *====Visual C++ 6.0側===== typedef struct _DLP_MSGDATA { int flg; char msg[504]; int tmp; } DLP_MSGDATA; _declspec(dllexport) int _stdcall SampSub(int data, DLP_MSGDATA *mdata) { return( 0 ); } *====Visual Basic 5.0側===== Declare Function SampSub Lib "test.dll" Alias "_SampSub@8" _ ( _ ByVal tlp_id As Long, _ ByRef mdata() As DLP_TLP_MSGDATA _ ) As Long Type DLP_TLP_MSGDATA flg As Long msg As String * 504 tmp As Long End Type Private Sub test() Dim mdata(0 To 130) As DLP_TLP_MSGDATA Dim aa As Long Call SampSub( aa, mdata ) End sub
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
(2)の方法で問題ないと思いますが.. '第2引数の型をAnyに変更 Declare Function SampSub Lib "test.dll" Alias "_SampSub@8" _ ( _ ByVal tlp_id As Long, _ mdata As Any _ ) As Long Declare Sub MoveMemory Lib "kernel32.dll" _ Alias "RtlMoveMemory" _ (Destination As Any, _ Source As Any, _ ByVal Length As Long) ReDim bdata(131 * Len(mdata(0))) As Byte '構造体の配列をbyte配列にコピー For i = 0 To 130 MoveMemory bdata(i * Len(mdata(0))), mdata(i), Len(mdata(0)) Next Call SampSub(1, bdata(0)) 'byte配列を構造体の配列にコピー For i = 0 To 130 MoveMemory mdata(i), bdata(i * Len(mdata(0))), Len(mdata(0)) Next
その他の回答 (5)
- taka_tetsu
- ベストアンサー率65% (1020/1553)
>構造体の配列でなければ、ちゃんと値の受け渡しができたのですが >配列になった途端、ダメでした。 >やはり、構造体配列を渡すのは、不可能なのでしょうか? あれ? 1.Declare文中のmdata()のカッコを削除する 2.Type中の固定長StringをByte型配列にする 3.Callで関数を呼ぶときに、(0)をつけて、構造体配列の先頭を参照渡し(ByRef)で呼ぶ で、いった実績があるんですけど。
お礼
回答ありがとうございました。 回答頂いた分でじゃないのですが、メモリブロックにコピーしてから渡す 方法でうまくいく事ができました。 いろいろ勉強になりました。
- hysteric5
- ベストアンサー率28% (4/14)
私も同じような事を現在していますが。VBのUDT構造体は各要素間で連続していないので戻り値をそのまま使うのには無理があると思います。方法としてはVBの隠し関数であるStrPtr(.netからはサポートされていません)を使用し構造体の先頭ポインタを取得しその後、RtlMoveMemory又はCopyMemoryのAPIを使用し取得したポインタより構造体の長さを切り取り取得していくのが妥当だと思います。
お礼
回答ありがとうございました。 RtlMoveMemoryを使用してうまくいきました。 ありがとうございました。
- taka_tetsu
- ベストアンサー率65% (1020/1553)
構造体のメンバに、固定長のStringを含まない場合は、次の方法で可能です。 Declare Function SampSub Lib "test.dll" Alias "_SampSub@8" _ ( _ ByVal tlp_id As Long, _ ByRef mdata As DLP_TLP_MSGDATA _ ) As Long Call SampSub( aa, mdata(0) ) 配列の先頭アドレスを渡してあげるのがポイントです。 しかし、今回のように、構造体に固定長の文字列を含めると、VBはUnicodeのため、構造体のサイズが変わってきてしまいます。そのため、配列で渡すことが出来ません。 対応方法としては、可変長文字列を使うか、下のようにByte型の配列にする必要があります。 Type DLP_TLP_MSGDATA flg As Long msg(0 To 503) As Byte tmp As Long End Type で、構造体の要素に格納するときは、StrConvでSJISに変換して格納し、取り出すときも同様にStrConvでUnicodeにしてあげます。
お礼
回答ありがとうございます。 構造体の配列でなければ、ちゃんと値の受け渡しができたのですが 配列になった途端、ダメでした。 やはり、構造体配列を渡すのは、不可能なのでしょうか?
- sha-girl
- ベストアンサー率52% (430/816)
答えではありませんが 以前、私もその問題に直面しました。 結論としてはできないのではないでしょうか? VBは文字列を内部ではunicodeで定義しているため 値渡しのときはANSIに変換された文字列のバッファのある ポインタを指しているらしいです。 つまりそれを渡そうとしてもメモリ上連続していないので無理なのでは ないかと思います。 構造体に渡す方法ですが 一度VB側でByte型にしてそれを渡してはどうでしょうか?
お礼
アドバイスありがとうございました。 回答No.5のtodo36さんの方法にてうまくいきました。 また何かの時に参考にしてみてください。
- todo36
- ベストアンサー率58% (728/1234)
構造体配列をそのままCのDLLに渡しては行けません。 次の4つの方法が考えられます。 (1)VC側でSafeArrayの面倒を見る http://www.microsoft.com/japan/support/kb/articles/J031/8/74.htm (2)VB側でメモリブロックにコピーしてから渡す redim bdata(131 * len(mdata(0))) as byte for i=0 to 130 MoveMemory mdata(i),bdata(i * len(mdata(0))) len(mdata(i)) next (3)VB側で構造体配列を一つの構造体として渡す Type DLP_TLP_MSGDATA_ARRAY mdata(0 To 130) As DLP_TLP_MSGDATA End Type (4)バイナリーファイルで渡す
お礼
早速の回答ありがとうございます。 (2)、(3)について試してみたのですが、うまくいきませんでした。 (2)については、値がうまく渡らず、(3)については、変数が64KB以上 を超えるということでコンパイルエラーとなってしまいました。 今、現状では、文字列だけでなくflgの整数値もまともに渡らない 状況です。これは、VCで作成するDLLに問題があるのでしょうか?
お礼
何度も回答ありがとうございました。 おかげさまで無事構造体配列の受け渡しができるようになりました。 第2引数の型をAnyに変更してなかったのが、問題でした。 ほんとうにありがとうございました。 とても助かりました。