C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト


(過去ログ 127 を表示中)
■75359 / )  Re[9]: VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ 魔界の仮面弁士 (245回)-(2015/03/18(Wed) 17:38:11)
2015/03/18(Wed) 17:50:38 編集(投稿者)

No75357 (とら さん) に返信
> 前述した通り、当方にはVC++に関する知識が殆ど御座いませんので、VC++のお勉強をして下さいというご指摘でしたら
> 大変申し上げ難いのですが、今回はあまり時間的な余裕が御座いませんのでまた別の機会にしたく考えております。

DLL の改修を行うのはとらさんでしょうか?
それとも専任者がいるのでしょうか?

セーフ配列を C 形式配列に置き換える作業を、
VC++の知識無しで行うのは無理があるかと…。



> 1つの構造体として受け取らせるという事なのですね。

C 配列なので、配列先頭要素のポインタを渡すというだけで。
1 つの構造体として渡す、という表現だと語弊があるかな…。


そもそも 1 つだけならば、 配列である必要性も無いので、
T_Struct* ではなく T_Struct でも渡せますしね。
(DLL 側で構造体の値を書き換える必要がある場合は別ですが)

VB6 の場合はユーザー定義型を値渡しできないため、Declare の段階で
構造体メンバーのスタックを展開して引数化する必要がありましたが、
VB2008 はそうした制限が無いので、そのまま ByVal x As T_Struct で渡せます。

WindowFromPoint API などがこれにあたります。
 HWND WindowFromPoint( POINT Point );
上記は、POINT 構造体(≠POINT 構造体のポインタ) を受け取るものですが、
VB6 では構造体を ByVal で渡せないため、「ByVal x As Long, ByVal y As Long」
と書き換える必要がありましたが、VB2008 では「ByVal x As POINT」と書けます。



話を戻して:

セーフ配列やマネージ配列の場合は、配列自体が要素数情報を保持していますが、
C 配列はただのポインタなので、サイズ情報がありません。
要素数が必要になるのはそのためです。
配列と共に、その配列の要素数を表す引数を併用する場合は、
MarshalAs 属性の SizeParamIndex で指定してください。

ただし、常に要素数が固定という仕様なのであれば、
配列要素数をわざわざ指定しなくても良いでしょう。


> VC++側は「構造体」と「構造体配列の要素数」を受け取ってから、
それだと、配列を受け取れませんよね。

VC++側は構造体ではなく、構造体のポインタを受け取るようにします。
VB2008 側は「<[In](), Out()> ByVal x() As 構造体, ByVal length As Integer」という感じですね。


> VB側は配列の先頭である「構造体配列(0)」と「構造体配列の要素数」を渡し、
「構造体配列(0)」ではなく、配列そのものを渡して下さい。

「構造体配列(0) のアドレスを値渡し」したり
「構造体配列(0) を参照渡し」する手法が通じるのは、
あくまでも VB6 の場合です。

VB2008 の場合、マネージ配列のメモリ位置が動的に変更される可能性があるため、
先頭要素だけ渡す方法は安全ではありません。もし、そのような渡し方をする必要が
あるのなら、GCHandle.AddrOfPinnedObject でピン止めする必要があります。


> なお、VC++側が構造体配列を受け取った後に次の関数へ渡していたのですが、その受け先はvoid型となっていました。
> TestSub_API int __stdcall FuncTestSub (void *Type1);
おぉ、ブラックボックス…!

DLL 側で、C 配列をセーフ配列に事前に詰め替えれば、上記を呼び出すことはできるでしょう。
問題は、上記が Type1 引数の情報を読み取るだけでなく、変更していた場合の書き戻し処理です。

構造体の値を書き換えるぐらいなら、さほど問題はありません。
呼び出し時に OutAttribute をつけておく程度で良いと思います。


問題は、配列サイズの変更がありえる場合です。

セーフ配列と異なり、C 配列だと DLL 側で配列サイズを
動的に増やすといったことはできないですから。


要素数を表す引数については、int length ではなく int* length に
するだけで良いと思いますが(この場合は、VB 側も ByRef Integer になる)、
問題は配列本体の方。
もしもサイズの動的変更がありえるのでれば、呼び出し元(VB2008 側)にて、
あらかじめ十分な要素数を確保しておき、その中でやりくりするような
DLL 実装に書き換えるなど、少々面倒な実装になりそうです。
返信 編集キー/


管理者用

- Child Tree -