如何动态加载 dll 并将 pass/get 值赋给它?

How to load dll dynamically and pass/get value to it?

DllImport我可以做到:

[DllImport(".../Desktop/Calculate.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int Sub(int a, int b);

但我想在 运行 时决定加载哪个 dll。 所以我没有使用 DllImport 但试试这个:

using System;
using System.Runtime.InteropServices;

namespace TestCall   
{
    class Program
    {
        [DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
        static extern int LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpLibFileName);
        [DllImport("kernel32.dll", EntryPoint = "GetProcAddress")]
        static extern IntPtr GetProcAddress(int hModule, [MarshalAs(UnmanagedType.LPStr)] string lpProcName);
        [DllImport("kernel32.dll", EntryPoint = "FreeLibrary")]
        static extern bool FreeLibrary(int hModule);
        delegate void CallMethod();
        static void Main(string[] arg)  //pass in string array
        {
            string DllName = ".../Desktop/Calculate.dll";  //would be like: string  DllName = ChooseWhatDllToCall();
            string FuncName = "Sub";                       //would be like: string FuncName = ChooseWhatFuncToUse();
            int hModule = LoadLibrary(DllName); // you can build it dynamically 
            if (hModule == 0) return;
            IntPtr intPtr;
            CallMethod action;

            intPtr = GetProcAddress(hModule, FuncName);
            action = (CallMethod)Marshal.GetDelegateForFunctionPointer(intPtr, typeof(CallMethod));
            action.Invoke();
        }
    }
}

但是我怎样才能像使用 DllImport 一样将 Sub 定义为 int Sub(int a, int b);

您可以按如下方式定义委托:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate Int32 Sub(Int32 a, Int32 b);

然后,在您的代码中:

Sub sub = (Sub)Marshal.GetDelegateForFunctionPointer(intPtr,typeof(Sub));

Int32 a = 5;
Int32 b = 8;
Int32 result = sub(a, b);

如果您需要 dll 中的多个功能,您将需要此过程的自动化。如果能在一个电话中获得委托,那就太好了,比如:

IntPtr hModule = LoadLibrary(".../MyLibrairy.dll"); 
var sub = DelegateBuilder<Sub>(hModule, "Sub");
var result = sub((Int32)5, (Int32)8);

就是这样:

public static T DelegateBuilder<T>(IntPtr loadedDLL, string delegateName = null) where T : Delegate
{
    string functionName = delegateName ?? typeof(T).ToString().Split('+').Last();
    IntPtr pAddressOfFunctionToCall = GetProcAddress(loadedDLL, functionName);
    if (pAddressOfFunctionToCall == IntPtr.Zero)
    {
        var errorMessage = string.Format("Not found function <{0}> in dll ", functionName);
        throw new EntryPointNotFoundException(errorMessage);
    }
    T functionDelegate = Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, typeof(T)) as T;
    return functionDelegate;
}

有可能直接调用结果出现不可读代码:

var result = DelegateBuilder<Sub>(hModule)((Int32)5, (Int32)8);

如对上述代码提出任何意见,我们将不胜感激 特别感谢 (Damien.B:)