Вызов функции C++ с указателем на функцию C# в качестве параметра

У меня есть следующий код в Native C dll.

typedef void CallbackType( INT32 param1, INT32 param2 );

NATIVE_API void RegisterEventCallBack(CallbackType *callBackFunction);


//INT32 is defined as below:

typedef signed int          INT32, *PINT32;

Я должен вызвать этот метод из моего кода C#. Выполнив некоторые решения, доступные в stackflow, я попробовал это:

Декларация делегата:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void CallbackType(Int32 param1, Int32 param2); 

Объявление импорта метода:

[DllImport("EtIPAdapter.dll")]
public static extern void RegisterEventCallBack([MarshalAs(UnmanagedType.FunctionPtr)]CallbackType callbackFunc);

Звонок:

RegisterEventCallBack(ReceivedData);

private static void ReceivedData(Int32 param1, Int32 param2)
{
    //Do something
}

Но это не работает, и я получаю следующую ошибку:

Вызов функции PInvoke «RegisterEventCallBack» разбалансировал стек. Вероятно, это связано с тем, что управляемая подпись PInvoke не соответствует неуправляемой целевой подписи. Убедитесь, что соглашение о вызовах и параметры подписи PInvoke соответствуют целевой неуправляемой подписи.

Я также попытался передать указатель функции, который я получил, используя GetFunctionPointerFromDelegate(ReceivedDataDelegate). Но это также приводит к той же ошибке.

Ошибка указывает на несоответствие подписи, но я не вижу явного несоответствия подписи. Пожалуйста помоги.


person Nirdesh    schedule 09.04.2013    source источник
comment
Вы можете попробовать следующее объявление в ссылке: stackoverflow.com/a/9855516/2253250 также следует проверить правильность прототипа функции? nirsoft.net/utils/dll_export_viewer.html может использовать DllExport Viewer.   -  person Gencebay    schedule 09.04.2013
comment
Как определяется макрос NATIVE_API? Я думаю, что проблема связана с вашим управляемым объявлением функции RegisterEventCallBack, а не с делегатом обратного вызова. Используете ли вы правильное соглашение о вызовах? Кажется странным, что RegisterEventCallBack будет использовать stdcall (по умолчанию для DllImport), когда его параметр обратного вызова использует cdecl.   -  person anton.burger    schedule 09.04.2013


Ответы (1)


Пожалуйста, проверьте соглашение о вызовах при выполнении DLLImport - по умолчанию это Winapi / StdCall.
Также важно, чтобы вы сохраняли ссылку на свой делегат внутри управляемого кода в течение всего времени существования приложения, поскольку в противном случае сборщик мусора удалит ваш делегат через некоторое время, потому что сборщик мусора может подсчитывать ссылки только внутри управляемого кода. Обычно я сохраняю ссылку на делегат как на статическое свойство класса, который устанавливает делегат.

person weismat    schedule 09.04.2013
comment
Спасибо. сработало изменение соглашения об именовании DLLImport на cdecl. [DllImport(EtIPAdapter.dll,CallingConvention=CallingConvention.Cdecl)] public static extern void RegisterEventCallBack([MarshalAs(UnmanagedType.FunctionPtr)]LogEventCallbackType pfnLogEvent); - person Nirdesh; 09.04.2013