动态平台调用
如果要调用的非托管函数没有位于所有可供搜索的路径下,那么就无法对非托管函数进行平台调用。这时可以使用动态平台调用。
通过手动加载非托管DLL实现动态平台调用
在CLR开始搜索DLL并加载之前,先手动用Win32APILoadLibary
来加载DLL。这样CLR就可以搜索到该DLL并进行平台调用了。
[DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
public static extern IntPtr LoadLibrary(string lpLibFileName);
//...
IntPtr dllAddr = LoadLibrary(dllPath);
//...
利用反射实现动态平台调用
- 使用
DefineDynamicAssembly
创建一个动态程序集对象。 - 使用
DefineDynamicModule
为该程序集定义一个动态模块。 - 使用
DefinePInvokeMethod
为该模块定义一个用于访问非托管函数的P/Invoke方法。 - 调用
CreateGlobalFunctions
函数完成动态模块的全局函数定义和全局数据定义。 - 调用
GetMethod
方法获得方法并进行调用。
使用GetDelegateForFunctionPointer实现动态平台调用
前面两种方法是.NET Framework 1.0和1.1下进行动态平台调用的主要方法。从.NET Framework2.0开始引入了一个能够进行动态平台调用的新技术,即Marshal.GetDelegateForFunctionPointer
。
主要步骤:
- 为非托管函数定义一个委托。
- 使用Win32API
LoadLibrary
加载非托管DLL。 - 使用Win32API
GetProcAddress
获取非托管函数地址。 - 使用
Marshal.GetDelegateForFunctionsPointer
将上述函数地址封送到第一步定义的委托。 - 使用委托调用函数。
- 使用Win32API
FreeLibrary
释放DLL。
//1
[UnmanagedFunctionPointer(CallingConvertion.StdCall)]
delegate int MultiplyDelegate(int x, int y);
public static void Test()
{
string entryPoint = "_Multiply@8";
string currentDir = (Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
string dllPath = Path.Combine(currentDir, @"nativelibfordynamicpinvoke\NativeLibForDynamicPInvoke.dll");
//2
IntPtr dllAddr = Win32API.LoadLibrary(dllPath);
//3
IntPtr procAddr = Win32API.GetProcAddress(dllAddr, entryPoint);
//4
MultiplyDelegate multiplyDel = (MultiplyDelegate)Marshal.GetDelegateForFunctionPointer(procAddr, typeof(MultiplyDelegate));
//5
int result = multiplyDel(233, 233);
//6
bool isFree = Win32API.FreeLibrary(dllAddr);
}
//已忽略错误和异常处理
(END)