Top / .NET備忘録 / 14.【注意】VarPtr関数

多くのサイトで VB6.0 の VarPtr 関数の代わりになる方法として GCHandle を使用する方法が紹介されています。

Dim gch As GCHandle = GCHandle.Alloc(obj, GCHandleType.Pinned)
Dim address As IntPtr = gch.AddrOfPinnedObject()
(address を使って処理)
gch.Free()

実はこの方法、参照型(Class)なら良いのですが、値型(ValueType)ではまずい点があります。

というのは、値型は Alloc メソッドに渡した時点で Box 化されてしまうため、AddrOfPinnedObject メソッドで返ってくるのは Box 化されたもののアドレスだからです。

そのため API に対して値を渡すことはできても受け取ることができないのです。

配列ならうまくいくという話もありますが、配列は参照型です。(^_^;)

ただし逃げ道はあって GCHandle.Target プロパティを見ると受け取った値を参照することができます。

<DllImport("Kernel32", EntryPoint:="RtlMoveMemory")>
Private Sub MoveMemory(ByVal dest As IntPtr, ByVal src As IntPtr, ByVal size As Integer)
End Sub

Sub Main()
    Dim a As Integer = 1
    Dim b As Integer = 0
    Dim ga As GCHandle = GCHandle.Alloc(a, GCHandleType.Pinned)
    Dim gb As GCHandle = GCHandle.Alloc(b, GCHandleType.Pinned)
    MoveMemory(gb.AddrOfPinnedObject(), ga.AddrOfPinnedObject(), Marshal.SizeOf(a))
    Debug.Print("b={0}", b)
    Debug.Print("gb.Target={0}", gb.Target)
    ga.Free()
    gb.Free()
End Sub

(実行結果)
b=0
gb.Target=1

では、注意点を踏まえたうえで VarPtr 関数を実装してみます。


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   最終更新のRSS
Last-modified: 2017-05-19 (金) 09:33:02 (90d)