Marshal.GetDelegateForFunctionPointer не работает - PullRequest
1 голос
/ 22 октября 2011

Я пытаюсь вызвать функцию C из приложения .NET. На самом деле я делаю следующее:

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 был передан во время выполнения для преобразован в делегата.

Что я делаю не так?

1 Ответ

3 голосов
/ 22 октября 2011

Прежде всего, вы уверены, что используете соглашение о вызовах __stdcall?

C # использует соглашение о вызовах __stdcall по умолчанию, если не указано, что C ++ по умолчанию использует __cdecl!

extern "C" void __declspec(dllexport) __stdcall Matrix4x4_Multiply_SSE(float *left, float *right);

Второе ... вы не можете использовать FreeLibrary, если собираетесь использовать этот метод.Загрузите библиотеку один раз и сохраните ее в памяти.Вам не нужно вызывать FreeLibrary никогда в реальности, операционная система сделает это, когда вы выгружаете свою программу.

В-третьих ... вы уверены, что используете умножение SSE через вызов делегата для P / Invoke?функция быстрее, чем выполнять ее в чистом C #?Вызовы P / Invoke очень дороги!

Взгляните на код умножения матриц XNA с отражателем, он написан от руки на C # и быстрее для одиночных матриц.

Если вам нужно умножить все вместе10000 матриц, то я бы предложил вам SSE-код в вашей dll, который будет выполнять умножение 10000 в собственном ультраоптимизированном коде, но только для умножения в один раз, делая это в C # быстрее, без P / Invoke и без какого-либо делегата.

Обратите внимание, что память для инструкций SSE должна быть выровнена по 16-байтовой границе, и, конечно, C # не следует этому выравниванию :) Особенно вам придется иметь дело с сборщиком мусора, который любит перемещать память при необходимости.Тогда вам потребуется использовать закрепленные массивы или неуправляемую память.

...