プログラミング

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

2005年11月21日

 VB6で用いられていたAddressOf演算子による関数ポインタの取得等は、.NETではデリゲートという、より高機能なものに取って代わられたらしい。現在制作中のSFC for vbscriptは.NETを利用したものに移行しつつあるが、ここでは相変わらず関数ポインタが必要である。VB.NETでの関数ポインタの取得について色々と調べてみた。

 デリゲート型を引数として外部DLLを呼び出せば、関数ポインタ値が32bit整数型として引き渡されるので、その値をそのままVB.NETに返すようなDLL関数を用いればよい。一番簡単なのはC/C++を用いてそのようなDLLを作成することなのであるが、今回の目的はC/C++を用いずにこれを可能にすることである。要するに、そのようなWin32APIがあればよいと言うことになる。
 32bit整数型を引数として渡せばそのままそれを返すようなWin32APIを探すのに苦労したが、ようやく見つけた。EnumWindowsである。このAPIの第2パラメータは、EnumWindowsProcの第2パラメータとしてそのまま引き継がれる。かくして出来たテストプログラムが以下の通り。

Imports System
Imports System.Runtime.InteropServices

Public Class dwWndProc
    '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

    'This EnumWindows is used to test the obtained 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()
        EnumWindows(AddressOf dwWndProc.EnumWindowsProc, AddressOf dwWndProc.WndProc)
        Console.Write("The pointer of WndProc is ")
        Console.WriteLine(fPointer)
        EnumWindows2(fPointer, 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

 しかし、このようなことが外部DLLを経由してしか出来ない(VB.NET内部では出来ない)ようにしてあるのは、それによるバグの生成を回避したかった為なんだろうな、Microsoftの.NET開発メンバの人たちにとっては。
 このルーチンの製作にあたり、かなりの数のWebページを参考にさせて頂いたが、その記録を取っていなかったのが残念である。

追記 2005-11-23
 この方法では、WndProcは使えないことが分かった。関数ポインタ値を取得した後に、その値が変化するためである(EnumWindows等はOK)。GCHandleのPinned等を試しているが、今のところ解決策は見いだせていない。

追記 2005-11-25
 上記の問題の解決策は、続きのページで。
(続く)

コメント

コメントはありません

コメント送信