Вызов функции DLL, содержащей указатель на функцию из C#


У меня есть библиотека DLL, написанная на языке C++, которая включает экспортируемую функцию, имеющую указатели функций, которые будут использоваться в качестве функции обратного вызова.

// C++ 
DllExport unsigned int DllFunctionPointer( unsigned int i, unsigned int (*TimesThree)( unsigned int number ) ) {
    return TimesThree( i )  ; 
}

У меня есть приложение CSharp, которое я хотел бы использовать для вызова функций DLL.

// C#
public unsafe delegate System.UInt32 CallBack( System.UInt32 number ); 
class Program
{
    [DllImport("SimpleDLL.dll")]
    public static extern System.UInt32 DllFunctionPointer( System.UInt32 i, CallBack cb) ;

    static unsafe void Main(string[] args)
    {
        System.UInt32 j = 3;
        System.UInt32 jRet = DllFunctionPointer(j, CallBack );
        System.Console.WriteLine("j={0}, jRet={1}", j, jRet); 
    }

    static System.UInt32 CallBack( System.UInt32 number ) {
        return number * 3 ; 
    }
}

Проблема с приведенным выше кодом заключается в том, что приложение завершает работу со следующим сообщением об ошибке.

'CallingACallbackFromADLL.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:XXXXCallingACallbackFromADLL.exe', Symbols loaded.
Managed Debugging Assistant 'PInvokeStackImbalance' has detected a problem in 'C:XXXXCallingACallbackFromADLL.vshost.exe'.
Additional Information: A call to PInvoke function 'CallingACallbackFromADLL!CallingACallbackFromADLL.Program::DllFunction' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

The program '[9136] CallingACallbackFromADLL.vshost.exe: Managed (v4.0.30319)' has exited with code 1073741855 (0x4000001f).

Я не знаю, что делать дальше.

Мой вопрос:

  • Как правильно вызвать библиотеку DLL C++ функция, содержащая указатель обратного вызова из приложения C#.
1 4

1 ответ:

Это связано с тем, что по умолчанию соглашение о вызове функций в C# равно __stdcall, но в C/C++ по умолчанию равно __cdecl, поэтому вы должны изменить соглашение о вызове вашей функции следующим образом:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void TimesTree( uint frame );
[DllImport("SimpleDLL.dll")]
public static extern System.UInt32 DllFunctionPointer( uint i,
    [MarshalAs(UnmanagedType.FunctionPtr)] TimesTree callback ) ;

static unsafe void Main(string[] args)
{
    // ...
    System.UInt32 jRet = DllFunctionPointer(j, CallBack );
    // ...
}