如何动态加载 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:)
在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:)