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

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

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

Re[2]: VB.NETから構造体配列をLPSAFEARRY*で受け取る


(過去ログ 110 を表示中)

[トピック内 3 記事 (1 - 3 表示)]  << 0 >>

■65509 / inTopicNo.1)  VB.NETから構造体配列をLPSAFEARRY*で受け取る
  
□投稿者/ 竹人 (1回)-(2013/03/04(Mon) 22:29:30)

分類:[VB.NET/VB2005 以降] 

[環境]
・Windows7(32bit)
・Visual Studio 2008
・.NET Framework 3.5(2.0でも同様の結果でした)

お世話になります。
VB.NETからC++で作成したDLLをコールしたいのですが
構造体配列の受け渡しが意図した動作になりません。

目的
(1)VB.NETからC++DLL関数をコールし、構造体配列をVB.NETからC++へ渡す
(2)VB.NETからC++DLL関数をコールし、C++で確保した構造体配列をVB.NETへ返す

(2)はうまくできたのですが、(1)が動作しません。


[C++DLL関数のインタフェース]
extern "C" _declspec (dllexport) long __stdcall Input1(
long cnt,
LPSAFEARRY* data
);

第1引数は、構造体配列の要素数です。
第2引数は、構造体配列をセーフアレイのポインタのポインタで受け取ります。

[VB.NET側のDeclare宣言]
Public Declare Function Input1 Lib "xxx.dll" ( _
ByVal cnt as Integer, _
<MarshalAs(UnmanagedType.SafeArray)> _
ByRef data() as Struct1 _
) as Boolean

[VB.NET側の構造体]
<StructLayout(LayoutKind.Sequential, Pack:=4)>
Public Structure Struct1
Public num as Integer
<MarshalAs(UnmanagedType.BStr)> _
Public str as String
End Structure

[VB.NETの処理部]
Dim cnt as Integer = 2
Dim st(1) as Struct1
' 構造体配列の要素にデータを設定
Input1(cnt, st) ←ここでE_INVALIDARG発生

[C++DLL側の構造体]
typedef struct struct_Struct1{
long num;
BSTR str;
} Struct1;

前提として「C++DLLは変更したくない」という要件があります。
C++DLLのインタフェースを、セーフアレイのポインタのポインタではなく、
C++構造体のポインタにした場合、構造体配列をVB.NETからC++へ渡すことはできました。


このコードでVB.NETからC++DLL関数をコールすると、E_INVALIDARGが発生します。
画面上には「パラメータが間違っています。」と表示されます。
(DLL内の処理は一切動作しません。)

SafeArraySubTypeにVT_RECORD、VT_USERDEFINEDを設定してみましたが、
同様のエラーとなりました。

また、VB.NETのDeclare宣言における"MarshalAs〜"の記述を省略すると、
関数をコールするとC++DLLが動作するのですが、DLL内のSafeArrayAccessDataが
うまく動作しません。(S_OKを返却するが、変なアドレスを見ている)

Declare宣言が間違っていると思い、資料を参照して
試行錯誤しているのですが(InAttribute, OutAttributeの付与など)
うまく動作しません。
Declareではなく、<DllImport>での記述も試しましたが、同じ結果でした。

文字コードを明示的に指定しても同じ結果でした。

似たようなインタフェースの(2)はうまく動作しているので、
DLLの設置ミスや、構造体の定義不備ではないと考えています。

何が問題なのか、全く分かっていない状況です。
どのような記述がただしいのでしょうか。
また、記述以外(プロジェクトの設定等)にも留意点などがあるでしょうか。

ご教授のほどよろしくお願いいたします。
引用返信 編集キー/
■65514 / inTopicNo.2)  Re[1]: VB.NETから構造体配列をLPSAFEARRY*で受け取る
□投稿者/ オショウ (65回)-(2013/03/05(Tue) 10:19:20)
> 前提として「C++DLLは変更したくない」という要件があります。
> C++DLLのインタフェースを、セーフアレイのポインタのポインタではなく、
> C++構造体のポインタにした場合、構造体配列をVB.NETからC++へ渡すことはできました。

  それで時間つぶすようなら・・・
  VB.NET と、C++ DLL の間にラッパーDLL を、C++ CLI で作って構造体配列の
  橋渡しを作ってやれば、一挙解決・・・と思いますが。

  VB.NET からは、.NETモジュールとして参照設定でラッパーDLLを扱えるので
  至極楽。

※ C++の経験が無いなら、余計難易度が上がってしまうので、無理かナ〜

以上。参考まで
引用返信 編集キー/
■65526 / inTopicNo.3)  Re[2]: VB.NETから構造体配列をLPSAFEARRY*で受け取る
□投稿者/ 竹人 (2回)-(2013/03/05(Tue) 19:36:10)
No65514 (オショウ さん) に返信

ご回答ありがとうございます。
確かに、ラッパーDLLを作成することは解決策の一つだと思います。
今のままの造りでは実現不能であった場合、ラッパーDLLを作成して
対応したいと思います。


気になったのは、エラーの内容が「パラメータが間違っています。」であり、
パラメータが正しければ、ラッパーDLLがなくても呼べるんじゃないかな…、ということです。
ただ、自分ではパラメータがどう誤っているのかまでは、分かりませんでした。

もう少し勉強してきます。
ありがとうございました。
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -