2011-12-27 17 views
1

私は、動的アンマネージドDLLの呼び出しを実行するために、いくつかの興味深いコードを使用しています:DLLでのメソッドの動的呼び出し。メソッドのシグネチャを変更するには?

Imports System.Runtime.InteropServices 

Module NativeMethods 
Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal dllToLoad As String) As IntPtr 
Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As IntPtr, ByVal procedureName As String) As IntPtr 
Declare Function FreeLibrary Lib "kernel32" (ByVal hModule As IntPtr) As Boolean 
End Module 

Module Program 
<UnmanagedFunctionPointer(CallingConvention.Cdecl)> _ 
Delegate Function MultiplyByTen(ByVal numberToMultiply As Integer) As Integer 


Sub Main() 
    Dim pDll As IntPtr = NativeMethods.LoadLibrary("MultiplyByTen.dll") 

    Dim pAddressOfFunctionToCall As IntPtr = NativeMethods.GetProcAddress(pDll, "MultiplyByTen") 

    Dim multiplyByTen As MultiplyByTen = DirectCast(Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, GetType(MultiplyByTen)), MultiplyByTen) 

    Dim theResult As Integer = multiplyByTen(10) 

    Console.WriteLine(theResult) 

    NativeMethods.FreeLibrary(pAddressOfFunctionToCall) 
End Sub 

End Module 

私はvoidへのデリゲートのパラメータの署名と種類を変更することができるか、整数、文字列、またはブール値を返す関数になりたいです。

基本的には、自分のプログラム(インタプリタ)が、アンマネージdllのどのメソッドにでも呼び出せるようにしたいと思います。プログラマがアクセスしたいメソッドを予測できないからです。彼らがどんな有用な方法にもアクセスできるようにしたい。

これはvb.netで可能性があります - おそらく反射ありですか? - しかし、私はそれをやる方法が分かりません。

--- EDIT:その上で「= ...薄暗いtheResult」

<UnmanagedFunctionPointer(CallingConvention.Cdecl)> _ 
Delegate Function DelegateInteger(<[ParamArray]()> ByVal args() As Object) As Integer 

... 

    Dim GetStdHandle = NativeDllCallIntegerMethod("kernel32", "GetStdHandle", -11) 
... 
    Function NativeDllCallIntegerMethod(ByVal DllPath As String, ByVal DllMethod As String, ByVal ParamArray Arguments() As Object) As Integer 
    Dim pDll As IntPtr = NativeMethods.LoadLibrary(DllPath) 

    Dim pAddressOfFunctionToCall As IntPtr = NativeMethods.GetProcAddress(pDll, DllMethod) 

    Dim IntegerFunction As DelegateInteger = DirectCast(Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, GetType(DelegateInteger)), DelegateInteger) 

    Dim theResult As Object = IntegerFunction.DynamicInvoke(Arguments) 

    NativeDllCallIntegerMethod = theResult 

    NativeMethods.FreeLibrary(pAddressOfFunctionToCall) 
    End Function 

これはとのライン上に苦情を提起する:ここで私が作ってみたものです。エラーは、 "型のオブジェクト 'System.Int32'は、 'System.Object []'の型に変換できません。"

どこかでが届いているようですが、どこですか?私は本当に知らない。

+0

これで、ユーザーはメソッド名とシグネチャを指定し、プログラムが関数を呼び出すための適切なコードを自動的に生成できるようにする必要がありますか? – bobbymcr

+0

はい。それが私が探していることです。 – Dominick

+0

これは、最も一般的な場合(署名が使用できる場合)は容易ではありません。 ILが動的メソッド呼び出しを生成するために ".NETアセンブリコード"に相当するものをどのように生成するかを学ぶ必要があります。しかし、このプロジェクトは良い出発点かもしれません:http://dynamic.codeplex.com/ – bobbymcr

答えて

1

私はそれを持っています。

Imports System 
Imports System.Reflection 
Imports System.Reflection.Emit 
Imports System.Runtime.InteropServices 

Module DynamicInvocation 

Sub Main() 
    Dim DI As New DynamicInvoke 
    DI.Invoke("FreeConsole", "Kernel32", GetType(Boolean), Nothing) 
    DI.Invoke("AllocConsole", "Kernel32", GetType(Boolean), Nothing) 
    Dim StandardOutputHandle = DI.Invoke("GetStdHandle", "Kernel32", GetType(Integer), -11) 

    DI.Invoke("WriteConsoleA", "Kernel32", GetType(Integer), StandardOutputHandle, "Testing!", 8, 0, 0) 

End Sub 

End Module 

Public Class DynamicInvoke 
', Optional ByVal AssemblyName As String = "DynamicInvoke", Optional ByVal TypeName As String = "DynamicType", Optional ByVal Convention As CallingConvention = CallingConvention.Winapi, Optional ByVal CharacterSet As CharSet = CharSet.Ansi 

Public AssemblyName As String = "DynamicInvoke" 
Public TypeName As String = "DynamicType" 
Public Convention As CallingConvention = CallingConvention.Winapi 
Public CharacterSet As CharSet = CharSet.Ansi 

Function Invoke(ByVal MethodName As String, ByVal LibraryName As String, ByVal ReturnType As Type, ByVal ParamArray Parameters() As Object) 

    Dim ParameterTypesArray As Array 

    If Parameters IsNot Nothing Then 
     ParameterTypesArray = Array.CreateInstance(GetType(Type), Parameters.Length) 
     Dim PTIndex As Integer = 0 

     For Each Item In Parameters 
      If Item IsNot Nothing Then 
       ParameterTypesArray(PTIndex) = Item.GetType 
      Else 
       'ParameterTypesArray(PTIndex) = 0 
      End If 
      PTIndex += 1 
     Next 
    Else 
     ParameterTypesArray = Nothing 
    End If 

    Dim ParameterTypes() As Type = ParameterTypesArray 


    Dim asmName As New AssemblyName(AssemblyName) 
    Dim dynamicAsm As AssemblyBuilder = _ 
     AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, _ 
      AssemblyBuilderAccess.RunAndSave) 

    ' Create the module. 
    Dim dynamicMod As ModuleBuilder = _ 
     dynamicAsm.DefineDynamicModule(asmName.Name, asmName.Name & ".dll") 

    ' Create the TypeBuilder for the class that will contain the 
    ' signature for the PInvoke call. 
    Dim tb As TypeBuilder = dynamicMod.DefineType(TypeName, _ 
     TypeAttributes.Public Or TypeAttributes.UnicodeClass) 

    Dim mb As MethodBuilder = tb.DefinePInvokeMethod(_ 
     MethodName, _ 
     LibraryName, _ 
     MethodAttributes.Public Or MethodAttributes.Static Or MethodAttributes.PinvokeImpl, _ 
     CallingConventions.Standard, _ 
     ReturnType, _ 
     ParameterTypes, _ 
     Convention, _ 
     CharacterSet) 

    ' Add PreserveSig to the method implementation flags. NOTE: If this line 
    ' is commented out, the return value will be zero when the method is 
    ' invoked. 
    mb.SetImplementationFlags(_ 
     mb.GetMethodImplementationFlags() Or MethodImplAttributes.PreserveSig) 

    ' The PInvoke method does not have a method body. 

    ' Create the class and test the method. 
    Dim t As Type = tb.CreateType() 

    Dim mi As MethodInfo = t.GetMethod(MethodName) 
    Return mi.Invoke(Me, Parameters) 

    '' Produce the .dll file. 
    'Console.WriteLine("Saving: " & asmName.Name & ".dll") 
    'dynamicAsm.Save(asmName.Name & ".dll") 
End Function 

End Class 
関連する問題