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

わんくま同盟

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

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


(過去ログ 127 を表示中)
■75336 / )  Re[4]: VB.netからVC++6.0のへの構造体配列参照渡し
□投稿者/ 魔界の仮面弁士 (239回)-(2015/03/16(Mon) 19:34:59)
2015/03/17(Tue) 10:06:34 編集(投稿者)

No75312 (魔界の仮面弁士) に追記
> もし、引数が C スタイルの配列ではなく、COM の SAFEARRAY で宣言されていたなら
> C++ 側で要素数を確認することもできるでしょうけれども、その場合、VB6 では
> 「Type ステートメントで型定義されたユーザー定義型」の配列ではなく、
> 「タイプライブラリにて型定義された構造体」の配列になっていたはず。

駄目元で、型定義を公開してみました。
P/Invoke の際に必要な手続きなのかどうかは分かりませんけど。
(COM Interop だった場合は、型公開が必要なはず…?)


(1) AssemblyInfo.vb にて、
   <Assembly: ComVisible(True)>
   <Assembly: Guid("……")>
  を指定しておきます。プロジェクトのプロパティの[アプリケーション]-[アセンブリ情報]でも指定可。

(2) 構造体側にも、また別の GUID を割り当てておきます。

  <ComVisible(True), Guid("……"), StructLayout(LayoutKind.Sequential)> _
  Public Structure Structure1
    <MarshalAs(UnmanagedType.I4)> Public aaa As Integer
    <MarshalAs(UnmanagedType.I4)> Public bbb As Integer
    <MarshalAs(UnmanagedType.I4)> Public ccc As Integer
  End Structure


実際の Guid 属性には、 Visual Studio 付属の GUIDGEN.EXE もしくは
「TextBox.Text = Guid.NewGuid().ToString("D")」などで生成した値を指定します。


(3) スタートメニューの "Visual Studio コマンドプロンプト" を右クリックして管理者起動し、
 「RegAsm C:\YourFolder\YourAppName.EXE」を実行します。(実際のパスにあわせてください)

 『型は正常に登録されました。』などのメッセージがされれば登録完了。

この段階で、レジストリの
 HKEY_CLASSES_ROOT\Record\{構造体のGuid}\バージョン番号\
に、構造体が記録されるはず。


---------

上記を実施したうえで、SafeArraySubType を変更してみたり、
Object 型でしてみたりと試行錯誤していたところ、

・配列が 1 件になることもなく呼び出せたものの、
 DLL 側での編集結果が反映されないケース(中身が呼び出し時のまま)。

に至りました。好転したかと思いきや、同じコードのまま
 AccessViolationException「保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリが壊れていることが考えられます。」
が発生することもあったので、恐らくは誤った呼び出し方のようです。…難しいですね。

他のパターンとしては、
 SafeArrayTypeMismatchException「指定された配列は期待されたタイプではありません。」
で呼び出せなかったり、呼び出せても配列が 1 件になってしまう状況だったりしており、
解決までの道のりは長そうです。


ただ、以前と同じ Declare 宣言でも、構造体定義を RegAsm するかどうかで
エラーの内容が変わる組み合わせがあったので、公開すること自体は
まったくの無意味では無さそうに思います。(確証は持てませんが)


No75332 (とら さん) に返信
> 引き続き他の方々もご存知の方がおられましたらご回答頂ければ助かります。

SAFEARRAY** や LPSAFEARRAY* での構造体受け渡しに関する質問は
ネット上でも度々見かけますが、成功事例がなかなか見当たりません。

セーフ配列を使わず、配列先頭ポインタと配列長を渡す実装に変更して回避するケース、
質問を取り下げて諦めるケース、中継用のヘルパーライブラリを用意して回避したケース、
VB/C# 側でSAFEARRAY 相当のメモリ構造を組み上げてそれを IntPtr で渡すケース、
カスタムマーシャラを作るケースなどなど…。


そんな中、こんな記事を見つけました。参考になりますか?

"Marshaling a SAFEARRAY of Managed Structures by P/Invoke"
https://limbioliong.wordpress.com/category/netcomactivex-interop/safearrays/

私自身まだ読みきっていませんが、標題から推察するに、今回の案件に相当する話題かと。
返信 編集キー/


管理者用

- Child Tree -