プログラミング

VB.NETで関数ポインタの値を取得する2

2005年11月25日

(←戻る)

 前回の記事では、取得した関数ポインタの値が、ガベージコレクションにより変化する問題があった。これを、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に採用したところ、現在の所、問題なく動いている。

コメント

コメントはありません

コメント送信