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に採用したところ、現在の所、問題なく動いている。