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

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

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

Re[7]: C#からVBで作成したDLLへの構造体渡し


(過去ログ 104 を表示中)

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

■62389 / inTopicNo.1)  C#からVBで作成したDLLへの構造体渡し
  
□投稿者/ コバピー (1回)-(2011/10/06(Thu) 17:22:05)

分類:[C#] 

プログラム初心者です。
C#(VS2010)で作成したプログラムから、VB(6.0)で作成したDLLのメソッドに
構造体を渡したいと考え、試してみましたが引数の型を合わせられません。
お手数ですが、詳しい方がいらっしゃいましたらお教え頂けませんでしょうか。
よろしくお願い致します。

VB側DLLでの定義(DLL:VBDLL,クラスモジュール:clsVBDLL)
Public Type Type_Data
aaa as double
bbb as double
ccc as integer
End Type

VB側メソッド
public Function xxxx(ByRef dData() as Type_Data)

C#側
objVBDll = New VBDLL.clsVBDLL();
((System.ComponentModel.ISupportInitialize)(objVBDll)).BeginInit();

VBDLL.Type_Data[] DTTbl = New VBDLL.Type_Data[10];
以下の行を実行しますと「パラメータが間違っています」になります。
objVBDll.xxxx(DTTbl);

引用返信 編集キー/
■62392 / inTopicNo.2)  Re[1]: C#からVBで作成したDLLへの構造体渡し
□投稿者/ 魔界の仮面弁士 (2384回)-(2011/10/06(Thu) 21:32:13)
No62389 (コバピー さん) に返信
> public Function xxxx(ByRef dData() as Type_Data)
戻り値の型は?

> 以下の行を実行しますと「パラメータが間違っています」になります。
> objVBDll.xxxx(DTTbl);
ByVal 引数ではなく ByRef 引数なので、
objVBDll.xxxx(ref DTTbl);
にしてみては如何でしょう。
引用返信 編集キー/
■62399 / inTopicNo.3)  Re[2]: C#からVBで作成したDLLへの構造体渡し
□投稿者/ Azulean (852回)-(2011/10/07(Fri) 11:45:17)
No62392 (魔界の仮面弁士 さん) に返信
> ByVal 引数ではなく ByRef 引数なので、
> objVBDll.xxxx(ref DTTbl);
> にしてみては如何でしょう。

ref が必要だとすると今のコードはコンパイルエラーになりそうな気がしました。


ところで、C# 側ではオブジェクトブラウザーや InteliSense でその xxxx メソッドはどんなシグネチャ(引数の型)に見えていますか?
引用返信 編集キー/
■62405 / inTopicNo.4)  Re[2]: C#からVBで作成したDLLへの構造体渡し
□投稿者/ 魔界の仮面弁士 (2385回)-(2011/10/07(Fri) 13:51:48)
No62392 (魔界の仮面弁士) に追記
>>objVBDll.xxxx(DTTbl);
> ByVal 引数ではなく ByRef 引数なので、
> objVBDll.xxxx(ref DTTbl);
> にしてみては如何でしょう。

テストコードを書いて試してみたところ、うちの環境では
xxxx メソッドの引数は「ref Array dData」になっていました。

タイプライブラリ/相互運用機能アセンブリを自作した場合は、
別の定義になるかもしれませんが、少なくとも上記の場合は
 Array a = DTTbl;
objVBDll.xxxx(ref a);
で呼べました。VB 側で引数オブジェクトの差し替えがある場合は
a を VBDLL.Type_Data[] に再キャストした方が良いかもしれません。


>>> ((System.ComponentModel.ISupportInitialize)(objVBDll)).BeginInit();
確認ですが、VB 側に ISupportInitialize を Implements させてあるのでしょうか?
引用返信 編集キー/
■62414 / inTopicNo.5)  Re[3]: C#からVBで作成したDLLへの構造体渡し
□投稿者/ コバピー (2回)-(2011/10/08(Sat) 06:14:34)
No62405 (魔界の仮面弁士 さん) に返信
> ■No62392 (魔界の仮面弁士) に追記
> >>objVBDll.xxxx(DTTbl);
>>ByVal 引数ではなく ByRef 引数なので、
>> objVBDll.xxxx(ref DTTbl);
>>にしてみては如何でしょう。
>
> テストコードを書いて試してみたところ、うちの環境では
> xxxx メソッドの引数は「ref Array dData」になっていました。
>
> タイプライブラリ/相互運用機能アセンブリを自作した場合は、
> 別の定義になるかもしれませんが、少なくとも上記の場合は
>  Array a = DTTbl;
> objVBDll.xxxx(ref a);
> で呼べました。VB 側で引数オブジェクトの差し替えがある場合は
> a を VBDLL.Type_Data[] に再キャストした方が良いかもしれません。
>
>
> >>> ((System.ComponentModel.ISupportInitialize)(objVBDll)).BeginInit();
> 確認ですが、VB 側に ISupportInitialize を Implements させてあるのでしょうか?
お手数をお掛けして申し訳ありません。
「objVBDll.xxxx(ref a);」と記述した行にカーソルを移動しますと
「dynamic clsVBDll.xxxx(ref Array dData)」と表示されますので、メソッドの引数は
同じ様に認識できていると思います。
エディタ上でのエラー表示も消えましたが、実行しますと、やはり「パラメータが間違っています」
と表示されてしまいます。
尚、BeginInit();の行は、DLLの初期化の為に必要かと思い記述致しましたが、
objVBDLL = new vbDLL.clsVBDLL();行を実行した際に初期化メソッドが実行されることが分かりました
ので削除致しました。
紛らわしい記述で申し訳ありません。

引用返信 編集キー/
■62432 / inTopicNo.6)  Re[4]: C#からVBで作成したDLLへの構造体渡し
□投稿者/ 魔界の仮面弁士 (2388回)-(2011/10/09(Sun) 22:22:29)
No62414 (コバピー さん) に返信
>> テストコードを書いて試してみたところ、うちの環境では
>> xxxx メソッドの引数は「ref Array dData」になっていました。
ちなみに当方では、
>>> public Function xxxx(ByRef dData() as Type_Data)
ではなく、
 Public Function xxxx(ByRef dData() As Type_Data) As Integer
  xxxx = -2
  On Error Resume Next
  xxxx = UBound(dData) - LBound(dData) + 1
 End Function
という宣言を用いて検証しました。


> 「objVBDll.xxxx(ref a);」と記述した行にカーソルを移動しますと
変数 a は System.Array 型なのですよね。

> 「dynamic clsVBDll.xxxx(ref Array dData)」と表示されますので、
戻り値が dynamic なのが気になります。

VB6 側の Function の戻り値に As キーワードがありませんでしたが、
曖昧さを排除するためにも、VB6 側では戻り値を明示しておくべきかと思います。
(互換性維持のために型を変更できない状況でも、型名自体は明記すべきです)

> エディタ上でのエラー表示も消えましたが、実行しますと、やはり「パラメータが間違っています」
実行時にエラーになるという事は、変数 a に格納してあるインスタンスが、
『VBDLL.clsVBDLL[] 型』のオブジェクトになっていない可能性があります。

あるいは、DLL のバイナリ互換性が失われたために、VB6 側の「clsVBDLL ユーザー定義型」と
C# 側の「clsVBDLL 構造体」が不一致状態になっている可能性もあります。この場合は、
 (1) DLL への参照設定を解除する。
 (2) 相互運用機能アセンブリ(Interop.*.DLL)を削除する。
 (3) クリーン操作後、DLL を再度参照設定する。
のように、参照設定をやりなおすことで回復する可能性があります。


>>>>> ((System.ComponentModel.ISupportInitialize)(objVBDll)).BeginInit();
> 尚、BeginInit();の行は、DLLの初期化の為に必要かと思い記述致しましたが、
> objVBDLL = new vbDLL.clsVBDLL();行を実行した際に初期化メソッドが実行されることが分かりました
> ので削除致しました。
実際にはそんなコードは記述されていなかった、という事でしょうか。
通常であれば、objVBDll を ISupportInitialize にキャストすることは
できないはずなので、どうやって実装したのか少し混乱していました。
引用返信 編集キー/
■62434 / inTopicNo.7)  Re[5]: C#からVBで作成したDLLへの構造体渡し
□投稿者/ コバピー (3回)-(2011/10/11(Tue) 09:17:52)
No62432 (魔界の仮面弁士 さん) に返信
> ■No62414 (コバピー さん) に返信
> >> テストコードを書いて試してみたところ、うちの環境では
> >> xxxx メソッドの引数は「ref Array dData」になっていました。
> ちなみに当方では、
> >>> public Function xxxx(ByRef dData() as Type_Data) 
> ではなく、
>  Public Function xxxx(ByRef dData() As Type_Data) As Integer
>   xxxx = -2
>   On Error Resume Next
>   xxxx = UBound(dData) - LBound(dData) + 1
>  End Function
> という宣言を用いて検証しました。
> 
> 
>>「objVBDll.xxxx(ref a);」と記述した行にカーソルを移動しますと
> 変数 a は System.Array 型なのですよね。
> 
>>「dynamic clsVBDll.xxxx(ref Array dData)」と表示されますので、
> 戻り値が dynamic なのが気になります。
> 
> VB6 側の Function の戻り値に As キーワードがありませんでしたが、
> 曖昧さを排除するためにも、VB6 側では戻り値を明示しておくべきかと思います。
> (互換性維持のために型を変更できない状況でも、型名自体は明記すべきです)
> 
>>エディタ上でのエラー表示も消えましたが、実行しますと、やはり「パラメータが間違っています」
> 実行時にエラーになるという事は、変数 a に格納してあるインスタンスが、
> 『VBDLL.clsVBDLL[] 型』のオブジェクトになっていない可能性があります。
> 
> あるいは、DLL のバイナリ互換性が失われたために、VB6 側の「clsVBDLL ユーザー定義型」と
> C# 側の「clsVBDLL 構造体」が不一致状態になっている可能性もあります。この場合は、
>  (1) DLL への参照設定を解除する。
>  (2) 相互運用機能アセンブリ(Interop.*.DLL)を削除する。
>  (3) クリーン操作後、DLL を再度参照設定する。
> のように、参照設定をやりなおすことで回復する可能性があります。
> 
> 
> >>>>> ((System.ComponentModel.ISupportInitialize)(objVBDll)).BeginInit();
>>尚、BeginInit();の行は、DLLの初期化の為に必要かと思い記述致しましたが、
>>objVBDLL = new vbDLL.clsVBDLL();行を実行した際に初期化メソッドが実行されることが分かりました
>>ので削除致しました。
> 実際にはそんなコードは記述されていなかった、という事でしょうか。
> 通常であれば、objVBDll を ISupportInitialize にキャストすることは
> できないはずなので、どうやって実装したのか少し混乱していました。
度々お手数をお掛けして申し訳ありません。
教えて頂いた点の修正を行い再度実行してみましたが結果は変わりませんでした。
以下が今回試してみました内容です。
@VB側Functionに戻り値の定義を追加し、DLLを再作成致しました。
Public Function xxxx(ByRef dData() as Type_Data) as Integer
ARegsvr32にてVBDLL.DLLをUnregistし、再作成したDLLのSystem32へのコピー後、
 Regsvr32にてVBDLL.DLLを再Regist。
BC#側ソリューションエクスプローラより
 (1) 参照設定下に表示されているVBDLLの削除
 (2) Interop.VBDLL.dllを全て削除
 (3) 再度、参照設定にVBDLL.DLLを追加
C変数aの記述を変更。
 Array a = DTTBL; → System.Array a = DTTBL;
DFunctionの呼び出し記述を変更。
 objVBDLL.xxxx(ref a); → short r = objVBDLL.xxxx(ref a);
Functionの呼び出し行にブレークポイントを設定して実行しますと、「ローカル」表示には
名前    値           型
+DTTBL   {VBDLL.Type_Data[10]}  VBDLL.Type_Data[]
+a     {VBDLL.Type_Data[10]}  System.Array {VBDLL.Type_Data[10]}
 r     0            short
と表示されています。
名前の左側に表示されている「+」をクリックしますと、配列の各要素に設定した値も表示
されます。
良さそうには見えますが実行しますと、
「パラメータが間違っています。(HRESULTからの例外:0x80070057 (E_INVALIDARG))」
になります。
なお、
((System.ComponentModel.ISupportInitialize)(objVBDll)).BeginInit();
行は記述は有りますが、コメントアウトしてあります。
曖昧な知識でいいかげんな記述をしてしまい、恥ずかしく思います。
余計な混乱を招いたようで申し訳ありません。




引用返信 編集キー/
■62435 / inTopicNo.8)  Re[6]: C#からVBで作成したDLLへの構造体渡し
□投稿者/ 魔界の仮面弁士 (2389回)-(2011/10/11(Tue) 09:37:48)
No62434 (コバピー さん) に返信
> VB側Functionに戻り値の定義を追加し、DLLを再作成致しました。
> Public Function xxxx(ByRef dData() as Type_Data) as Integer
その場合、DLL のバイナリ互換性が失われることになります。
http://support.microsoft.com/kb/161137/ja

アンレジストは「古いバージョンのDLL」に対して行い、その後、
「新しいバージョンのDLL」をレジストリ登録しておいてください。


> 変数aの記述を変更。
>  Array a = DTTBL; → System.Array a = DTTBL;
これは同義ですね。通常、「using System;」相当の記述があるはずなので、
Array と System.Array を global::System.Array は同じ結果となります。


> Functionの呼び出し記述を変更。
>  objVBDLL.xxxx(ref a); → short r = objVBDLL.xxxx(ref a);
これでコンパイルが通るなら、C# 側の実装に問題はありません。
(ただし、C# 側は x86 ビルドにしておいてください)


> 良さそうには見えますが実行しますと、
そのエラーを発生させているのは、.NET 側ではなく ActiveX 側だと思います。
いわゆる「実行時エラー」でしょうね。

DLL そのものの実装に問題がある可能性もありそうなので、VB6 開発環境で
デバッグ実行した状態で C# から呼び出し、問題がないかどうか確認してみてください。
引用返信 編集キー/
■62461 / inTopicNo.9)  Re[7]: C#からVBで作成したDLLへの構造体渡し
□投稿者/ コバピー (4回)-(2011/10/12(Wed) 18:30:49)
No62435 (魔界の仮面弁士 さん) に返信
> ■No62434 (コバピー さん) に返信
>>VB側Functionに戻り値の定義を追加し、DLLを再作成致しました。
>>Public Function xxxx(ByRef dData() as Type_Data) as Integer
> その場合、DLL のバイナリ互換性が失われることになります。
> http://support.microsoft.com/kb/161137/ja
>
> アンレジストは「古いバージョンのDLL」に対して行い、その後、
> 「新しいバージョンのDLL」をレジストリ登録しておいてください。
>
>
>>変数aの記述を変更。
>> Array a = DTTBL; → System.Array a = DTTBL;
> これは同義ですね。通常、「using System;」相当の記述があるはずなので、
> Array と System.Array を global::System.Array は同じ結果となります。
>
>
>>Functionの呼び出し記述を変更。
>> objVBDLL.xxxx(ref a); → short r = objVBDLL.xxxx(ref a);
> これでコンパイルが通るなら、C# 側の実装に問題はありません。
> (ただし、C# 側は x86 ビルドにしておいてください)
>
>
>>良さそうには見えますが実行しますと、
> そのエラーを発生させているのは、.NET 側ではなく ActiveX 側だと思います。
> いわゆる「実行時エラー」でしょうね。
>
> DLL そのものの実装に問題がある可能性もありそうなので、VB6 開発環境で
> デバッグ実行した状態で C# から呼び出し、問題がないかどうか確認してみてください。
度々申し訳ありません。
デバッグ実行してみましたが、結果は同じでした。(「パラメータが間違っています」となります)
また、VB側DLLのメソッドに設定したブレークポイントにも掛かりませんでした。
ちなみに、以下の様にメソッド及び呼び出しを追加し、メソッドの先頭行にブレークポイントを
設定してみましたが、こちらはブレークポイントでの停止と、その後の実行でMsgBoxの表示、
C#側で配列の内容まで確認することができました。

●C#側
float[] fltBuf = new float[10]{ 1,2,3,4,5,6,7,8,9,10 };
System.Array a = fltBuf;
float[] fltBuf2 = new float[10];
System.Array b = fltBuf2;
short r = objVBDLL.yyyy(ref a,ref b);
●VB側DLL
public function yyyy(ByRef sngBuf() as Single, sngRBuf() as Single) as Integer
Dim intI as integer
for intI = 0 to 9
MsgBox "sngBuf(" & intI & ")=" & sngBuf(intI) , vbOKOnly
sngRBuf(intI) = sngBuf(intI) * 19
Next intI
End function
何か考えられる事がありましたらお教え頂けませんでしょうか。
よろしくお願いします。


引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -