元帅.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被传递到运行时已转换为委托。

我做错了什么?

元帅.GetDelegateForFunctionPointer失败

首先,你确定你正在使用__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#不遵循这种对齐:)特别是你将不得不处理垃圾收集器,它喜欢在需要的时候移动内存。您需要使用固定数组或非托管内存。