VB.NETで関数ポインタの値を取得する2
2005年11月25日
(←戻る)
前回の記事では、取得した関数ポインタの値が、ガベージコレクションにより変化する問題があった。これを、GCHandleを用いて、pinnedオブジェクトとして回避する方法を考えてみた。
バイトアレイをpinnedオブジェクトとして固定し、そこにデリゲート型から得られる関数ポインタ以降のメモリをコピーして呼び出してみた。
うまくいっている気がする。
2005-11-27 追記
このテストプログラムを制作中に見つけた面白いweb pages:
x86 なメソッドを動的に生成する方法
Dynamically Writing and Executing Native Assembly in C#
.NET ver 2.0 ではインラインマシン語が使えるらしい。こういった物を使用すると、もう少しフレキシブルに色々なことができそう。
2005-12-03 追記
上記の方法は、再現性がかなり低い。うまくいかないことの方が多いようだ。一方、このMSDNのページを参考にすると、デリゲートオブジェクトを破棄せずにおけば、大丈夫のようである。実際にこれを SFC v0.3.0.8に採用したところ、現在の所、問題なく動いている。
前回の記事では、取得した関数ポインタの値が、ガベージコレクションにより変化する問題があった。これを、GCHandleを用いて、pinnedオブジェクトとして回避する方法を考えてみた。
バイトアレイをpinnedオブジェクトとして固定し、そこにデリゲート型から得られる関数ポインタ以降のメモリをコピーして呼び出してみた。
Imports System
Imports System.Runtime.InteropServices
Public Class dwWndProc
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Integer, ByVal Source As Integer, ByVal Length As Integer)
'Delegate declarations
Private Delegate Function d_EnumWindowsProc(hwnd As Integer, lParam As Integer) As Boolean
Private Delegate Function d_WndProc(ByVal p_hWnd As Integer, ByVal p_uiMsg As Integer, _
ByVal wParam As Integer, ByVal lParam As Integer) As Integer
'EnumWindows is used to get the pointer of function (as 2nd parameter)
Private Declare Function EnumWindows Lib "user32" (x As d_EnumWindowsProc, y As d_WndProc) As Integer
'EnumWindows2 is used to check the created function pointer.
Private Declare Function EnumWindows2 Lib "user32" alias "EnumWindows" (x As integer, y As integer) As Integer
'Pointer is put into this variable.
Public Shared fPointer as integer
Public Shared Sub Main()
Dim buff (4096) as byte
Dim gch as GCHandle =GCHandle.Alloc(buff, GCHandleType.Pinned)
Dim CallBackAddr as Integer = gch.AddrOfPinnedObject().ToInt32()
Dim CallBackAddrOrg as Integer
Dim dGate1 as d_WndProc=AddressOf dwWndProc.WndProc
Dim dGate2 as d_WndProc=AddressOf dwWndProc.WndProc
EnumWindows(AddressOf dwWndProc.EnumWindowsProc, dGate1)
Console.Write("dGate1 ")
Console.WriteLine(fPointer)
CallBackAddrOrg=fPointer
EnumWindows(AddressOf dwWndProc.EnumWindowsProc, dGate2)
Console.Write("dGate2 ")
Console.WriteLine(fPointer)
CopyMemory(CallBackAddr,CallBackAddrOrg, fPointer-CallBackAddrOrg)
EnumWindows2(CallBackAddr, 0)
End Sub 'Main
Public Shared Function EnumWindowsProc(hwnd As Integer, lParam As Integer) As Boolean
dwWndProc.fPointer=lParam
Return 0
End Function 'Report
Public Shared Function WndProc(ByVal p_hWnd As Integer, ByVal p_uiMsg As Integer, _
ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Console.WriteLine("WndProc is called")
Return 0
End Function
End Class 'dwWndProcうまくいっている気がする。
2005-11-27 追記
このテストプログラムを制作中に見つけた面白いweb pages:
x86 なメソッドを動的に生成する方法
Dynamically Writing and Executing Native Assembly in C#
.NET ver 2.0 ではインラインマシン語が使えるらしい。こういった物を使用すると、もう少しフレキシブルに色々なことができそう。
2005-12-03 追記
上記の方法は、再現性がかなり低い。うまくいかないことの方が多いようだ。一方、このMSDNのページを参考にすると、デリゲートオブジェクトを破棄せずにおけば、大丈夫のようである。実際にこれを SFC v0.3.0.8に採用したところ、現在の所、問題なく動いている。