元帅.GetDelegateForFunctionPointer失败
本文关键字:失败 GetDelegateForFunctionPointer 元帅 | 更新日期: 2023-09-27 18:11:55
我正在尝试从。net应用程序调用C函数。我确实做了以下的事情:
public unsafe class Simd
{
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
public delegate void MatrixMultiplyDelegate(float* left, float* right);
public static MatrixMultiplyDelegate MatrixMultiply;
public static void LoadSimdExtensions()
{
string assemblyPath = "Derm.Simd.dll";
// Really calls 'LoadLibrary', 'GetProcAddress', 'FreeLibrary' from Kernel32.dll
IntPtr address = GetProcAddress.GetAddress(assemblyPath, "Matrix4x4_Multiply_SSE");
if (address != IntPtr.Zero) {
MatrixMultiply = (MatrixMultiplyDelegate)Marshal.GetDelegateForFunctionPointer(address, typeof(MatrixMultiplyDelegate));
}
}
}
加载的函数声明如下:
extern "C" {
void __declspec(dllexport) Matrix4x4_Multiply_SSE(float *left, float *right);
}
遗憾的是,当调用GetDelegateForFunctionPointer时,我得到了以下异常:
InvalidFunctionPointerInDelegate:
无效的函数指针0xb81005被传递到运行时已转换为委托。
我做错了什么?
首先,你确定你正在使用__stdcall调用约定吗?
c#默认使用__stdcall调用约定,如果你不指定任何c++默认使用__cdecl !
extern "C" void __declspec(dllexport) __stdcall Matrix4x4_Multiply_SSE(float *left, float *right);
第二……如果你要使用那个方法,你就不能使用FreeLibrary。加载一次库并将其保存在内存中。你不需要调用FreeLibrary,实际上从来没有,当你卸载你的程序时,操作系统会这样做。
第三……您确定通过委托调用P/Invoke函数使用SSE乘法比在纯c#中执行它更快吗?P/Invoke调用非常昂贵!
看一下带有反射器的XNA矩阵乘法代码,它是用c#手工编写的,对于单个矩阵更快。
如果你需要将所有10000个矩阵相乘,那么我建议你在dll中使用SSE代码,该代码将在本机超优化代码中执行10000个乘法,但仅用于单个乘法,在c#中执行更快,没有p/Invoke,没有任何委托。
还要注意SSE指令的内存必须以16字节的边界对齐,当然c#不遵循这种对齐:)特别是你将不得不处理垃圾收集器,它喜欢在需要的时候移动内存。您需要使用固定数组或非托管内存。