动态调用DLL中的方法;如何更改方法签名? [英] Dynamic invocation of methods in DLLs; How to change method signature?

查看:229
本文介绍了动态调用DLL中的方法;如何更改方法签名?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用一些有趣的代码来执行动态非托管dll调用:

I am using some interesting code to perform dynamic unmanaged dll calling:

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或返回整数,字符串或布尔值的函数。

I want to be able to change the parameter signature and type of the delegate to void or to a function returning integer, string, or boolean.

基本上,我希望我的程序(解释器)能够调用程序员可以访问的任何非托管DLL中的任何方法...因为我无法预测程序员想要访问的方法 - 我想让他们能够访问任何有用的方法。

Basically, I want my program (interpreter) to be able to call upon any method in any unmanaged dll that the programmer has access to... since I cannot predict what method the programmer will want to have access to - I'd like to enable them to have access to any useful method.

这似乎是可能的在vb.net - 也许与反思? - 但我不知道该怎么做。

This seems like it's possible in vb.net - perhaps with reflection? - but I'm just not sure how to do it.

---编辑:这是我想出的:

--- Here's what I've come up with:

<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

这引发了对lin e和'Dim theResult = ...'就可以了。错误是System.Int32类型的对象不能转换为类型'System.Object []'。

This raises a complaint on the line with 'Dim theResult = ...' on it. The error is "Object of type 'System.Int32' cannot be converted to type 'System.Object[]'."

我似乎在某个地方但...在哪里?我真的不知道。

I seem to be getting somewhere but... where? I don't really know.

推荐答案

我已经有了。我现在可以动态调用方法:

I've got it. I can now dynamically call methods:

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

这篇关于动态调用DLL中的方法;如何更改方法签名?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆