- PR -

VB.NETからvoidポインタを引数にとるDLL関数を呼び出す方法

投稿者投稿内容
masataka
会議室デビュー日: 2006/02/17
投稿数: 13
投稿日時: 2006-02-18 17:54
引用:
Hongliangさんの書き込み (2006-02-18 14:40) より:
あ、これは失礼。VB では In は予約語でしたね。
予約語を予約語の用途以外で使う場合、[In] と言う風に書いてください。InAttribute でもいいですけど。



ためしてみたのですが、現象は変わりませんでした。なぜでしょうか?

コード:
    Declare Function fnDllProc2C Lib "DllProc" Alias "_fnDllProc2@4" (<MarshalAs(UnmanagedType.AsAny), InAttribute(), OutAttribute()> ByVal ptr As Object) As Integer

    Dim dpr2c As DLLSTRUCT2
    Dim dpr2c_o As Object
    dpr2c.dummy = 100008
    dpr2c_o = dpr2c       ' ボクシング
    fnDllProc2C(dpr2c_o)
    dpr2c = dpr2c_o       ' アンボクシング
    ' ここで dpr2c_o を確認したのですが、fnDllProc2C() で変更した内容が
    ' 反映されていません。



ちなみに最初に教えて頂いた方法では、DirectCast()を使うように説明されていましたが、上記のように直接代入する方法でも大丈夫のようです。
(fnDllProc2C()関数呼び出しの後でデバッガで dpr2c_o を変更したら、dpr2c にも反映されていました。)
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-02-18 20:27
引用:

masatakaさんの書き込み (2006-02-18 17:54) より:

ためしてみたのですが、現象は変わりませんでした。なぜでしょうか?


んー、これに関しては分かりかねます。私のところでは問題ないので。
<MarshalAs(UnmanagedType.AsAny), [In], Out>


引用:

コード:
Declare Function fnDllProc2C Lib "DllProc" Alias "_fnDllProc2@4" ( _
    <MarshalAs(UnmanagedType.AsAny), InAttribute(), OutAttribute()> _
    ByVal ptr As Object) As Integer

    Dim dpr2c As DLLSTRUCT2
    Dim dpr2c_o As Object
    dpr2c.dummy = 100008
    dpr2c_o = dpr2c       ' ボクシング
    fnDllProc2C(dpr2c_o)
    dpr2c = dpr2c_o       ' アンボクシング
    ' ここで dpr2c_o を確認したのですが、fnDllProc2C() で変更した内容が
    ' 反映されていません。




慌てて確認したら、本当ですね。適当なこと言ってすいませんでした。
言い訳すると、これ、VBのコンパイラのせいなんです。
私はC#畑の人間ですので、テストコードもC#で書いて、巧くいったコードをVBに翻訳しています。
で、C#なら巧くいくんですよ。UnmanagedType.AsAny / Object で。
だから等価のコードなら問題なくVBでもいけるだろうと考えてコメントを付けた訳なんですが、改めてVBで確認してみたら、Object 型を関数に渡すときだけ、なぜか事前に System.Runtime.CompilerServices 名前空間 RuntimeHelpers クラスの GetObjectValue 静的メソッドを呼び出す仕様になっているようです( ILDASM で確認)。その結果、構造体のインスタンスであるものはコピーが作成され、コード上で渡したインスタンスではなくそのコピーが渡されます ( C# では直接渡すのですが)。
// 重要な問題だと思うけど、仕様書に見当たらない気がする。
その結果、渡したインスタンスと実際に使われるインスタンスが異なるために結果を受け取れないことになってます。
AsAny / Object による解決は絶望的ですね。

あとは IntPtr と Marshal クラス使ってこんなのかな。
コード:
Private Declare Function Hoge Lib "foo.dll" (ByVal ptr As IntPtr) As IntPtr

Public Shared Function CallHoge (ByVal obj As object, ByRef result As Integer) As Object
    Dim ptr As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(obj))
    Try
        Marshal.StructureToPtr(obj, ptr, true)
        result = Hoge(ptr)
        Return Marshal.PtrToStructure(ptr, obj.GetType())
    Finally 
        Marshal.FreeCoTaskMem(ptr)
    End Try
End Function




引用:

ちなみに最初に教えて頂いた方法では、DirectCast()を使うように説明されていましたが、上記のように直接代入する方法でも大丈夫のようです。


型は大事にしましょう。
Option Strict Onで。
masataka
会議室デビュー日: 2006/02/17
投稿数: 13
投稿日時: 2006-02-20 09:25
引用:

Hongliangさんの書き込み (2006-02-18 20:27) より:
その結果、渡したインスタンスと実際に使われるインスタンスが異なるために結果を受け取れないことになってます。
AsAny / Object による解決は絶望的ですね。


御回答ありがとうございます。
AsAny / Object による解決はあきらめます。
VBの動きが変(仕様?)なら仕方がないですね。

引用:

引用:

ちなみに最初に教えて頂いた方法では、DirectCast()を使うように説明されていましたが、上記のように直接代入する方法でも大丈夫のようです。


型は大事にしましょう。
Option Strict Onで。



Option Strict Onでテストしていますが、問題ないようです。
実験したら以下のような動作でした。
コード:
    Dim st1 As DLLSTRUCT1
    Dim st2 As DLLSTRUCT2
    Dim obj As Object
    obj = st2
    st2 = obj  ' 正常
    st1 = obj  ' コンパイルエラー(型の不一致)
    st2 = DirectCast(obj, DLLSTRUCT2)  ' 正常
    st1 = DirectCast(obj, DLLSTRUCT2)  ' コンパイルエラー(型の不一致)
    st1 = DirectCast(obj, DLLSTRUCT1)  ' コンパイルは正常終了するが、実行時エラー(型の不一致)


DirectCast()を使わない方が実行時エラーにならない分、安全のような気がします。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-02-20 09:38
引用:

masatakaさんの書き込み (2006-02-20 09:25) より:

DirectCast()を使わない方が実行時エラーにならない分、安全のような気がします。


「型を大事に」とはこういう明示的なキャストも含みます。
キャストなんて、ないに越したことはないんですけどね。

Optin Strict Off の状態だと DirectCast 自体が不要なのですが、これは暗黙的な型変換が行われます。
これはやめましょうという意味です。(先の投稿には明示的なキャストがなかったですよね?)
遅延バインディングにならない (コンパイル解決できる) ようにしましょうという意味です。

それと実行時エラーというか例外にならない保証はありません。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
masataka
会議室デビュー日: 2006/02/17
投稿数: 13
投稿日時: 2006-02-20 10:03
じゃんぬねっと様ご回答ありがとうございます。

引用:

masatakaの書き込み (2006-02-20 09:25) より:
引用:

引用:

ちなみに最初に教えて頂いた方法では、DirectCast()を使うように説明されていましたが、上記のように直接代入する方法でも大丈夫のようです。


型は大事にしましょう。
Option Strict Onで。



Option Strict Onでテストしていますが、問題ないようです。


申し訳ありません。上記書き込み自体が勘違いです。
Option Strict Onにしていたのが、実験していたのと違うモジュールでした。
(VB6でいう標準モジュールで、Cの様にヘッダファイル的に使用していたので、Option Strict Onにしていると思いこんでしまっていました。)

お騒がせして申し訳ありませんでした。


[ メッセージ編集済み 編集者: masataka 編集日時 2006-02-20 10:15 ]

スキルアップ/キャリアアップ(JOB@IT)