2014-11-02 145 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(); 
    } 
    } 
}