2014-11-02 103 views
1

我需要动态调用dll函数。C#GetDelegateForFunctionPointer与通用委托

我使用标准的Windows API来加载DLL并获取proc地址。

我找回进程内的IntPtr的后,我尝试将其转换为委托:

Func<int> inv = (Func<int>)Marshal.GetDelegateForFunctionPointer(proc, typeof(Func<int>)); 

但它失败,因为typeof运算(Func键)返回泛型类型。

有没有干净的方式来完成我想做而不只是声明会员代表和 使用它作为类型?

我的意思是我试图避免以下冗余:

//I need this member only for typeof operator 
private delegate int RunDll(); 
RunDll inv = (RunDll)Marshal.GetDelegateForFunctionPointer(proc, typeof(RunDll)); 

回答

1

根据the documentation仿制药根本不受此API支持。请注意,这不是一个很大的损失 - 毕竟,你只是需要指定一次签名;唯一的缺点是,你不能内嵌指定它 - 用Func<int>不需要间接的,但(由于铸)是在一定意义上其实更是多余的。顺便说一句,你可能想看看普通的旧DllImport - 如果提前知道DLL和函数,你不需要做这个手动的委托包装。

2

这将是糟糕的,如果委托类型是动态的,你不知道的参数。然后你可以使用.NET方法来生成它。

public static class DelegateCreator 
{ 
    private static readonly Func<Type[],Type> MakeNewCustomDelegate = (Func<Type[],Type>)Delegate.CreateDelegate(typeof(Func<Type[],Type>), typeof(Expression).Assembly.GetType("System.Linq.Expressions.Compiler.DelegateHelpers").GetMethod("MakeNewCustomDelegate", BindingFlags.NonPublic | BindingFlags.Static)); 

    public static Type NewDelegateType(Type ret, params Type[] parameters) 
    { 
     Type[] args = new Type[parameters.Length]; 
     parameters.CopyTo(args, 0); 
     args[args.Length-1] = ret; 
     return MakeNewCustomDelegate(args); 
    } 
} 

DelegateCreator.NewDelegateType(typeof(int)) //returns non-generic variant of Func<int> 
+0

这完全是我所需要的,非泛型的委托类型创建者,所以我可以调用Marshal.GetFunctionPointerForDelegate。 :) – Ani 2015-04-24 00:38:51

0

起初:方法DelegateCreator.NewDelegateType的实现是不正确的!

public static Type NewDelegateType(Type ret, params Type[] parameters) { 
    /* 
    Type[] args = new Type[parameters.Length]; // Create "args" array of same length as "parameters" (must be length + 1) 
    parameters.CopyTo(args, 0);     // Copy all values of parameters to "args" array 
    args[args.Length - 1] = ret;     // Put "ret" value to last item of "args" array 
    return MakeNewCustomDelegate(args); 
    */ 
    var offset = parameters.Length; 
    Array.Resize(ref parameters, offset + 1); 
    parameters[offset] = ret; 
    return MakeNewCustomDelegate(parameters); 
} 

什么是助手的利润,如果我们不能得到一个类型的委托来调用?见下文试验例。

using System; 
using System.Linq.Expressions; 
using System.Reflection; 
using System.Runtime.InteropServices; 

namespace GenericDelegates { 
    static class DelegateCreator { 
    public static readonly Func<Type[], Type> MakeNewCustomDelegate = (Func<Type[], Type>) Delegate.CreateDelegate(
     typeof(Func<Type[], Type>), 
     typeof(Expression).Assembly.GetType("System.Linq.Expressions.Compiler.DelegateHelpers").GetMethod(
     "MakeNewCustomDelegate", 
     BindingFlags.NonPublic | BindingFlags.Static 
    ) 
    ); 
    public static Type NewDelegateType(Type ret, params Type[] parameters) { 
     var offset = parameters.Length; 
     Array.Resize(ref parameters, offset + 1); 
     parameters[offset] = ret; 
     return MakeNewCustomDelegate(parameters); 
    } 
    } 
    static class Kernel { 
    [DllImport("kernel32.dll", SetLastError = true)] 
    public static extern IntPtr GetModuleHandle(string name); 
    [DllImport("kernel32.dll", SetLastError = true)] 
    public static extern IntPtr GetProcAddress(IntPtr module, string name); 
    } 
    static class InvokeHelper { 
    public static Delegate MakeDelegate(this IntPtr address, Type ret, params Type[] parameters) { 
     return Marshal.GetDelegateForFunctionPointer(address, DelegateCreator.NewDelegateType(ret, parameters)); 
    } 
    } 
    class Program { 
    static void Main(string[] args) { 
     var kernel = Kernel.GetModuleHandle("kernel32.dll"); 
     var address = Kernel.GetProcAddress(kernel, "GetModuleHandleW"); 
     Console.WriteLine(@" 
Module base: 0x{0:X8} 
Entry point: 0x{1:X8} 
", (int) kernel, (int) address); 
     var invoke = address.MakeDelegate(typeof(IntPtr), typeof(string)); 
     Console.WriteLine(@" 
Untyped delegate: {0} 
Cast to Invoke: {1} 
", invoke, invoke as Func<string, IntPtr> == null ? "Error" : "Valid"); // invoke as Func<string, IntPtr> = NULL 
     Console.ReadKey(); 
    } 
    } 
}