C # делегат для обратного вызова C ++

Я думаю, что я в основном понял, как писать делегаты c # для обратных вызовов, но это меня смущает.
Определение C ++ выглядит следующим образом:

typedef int (__stdcall* Callback)(
long lCode,
long lParamSize,
void* pParam
);

и мой подход C # будет:

 unsafe delegate int CallbackDelegate (int lCode, int lParamSize, IntPtr pParam);

Хотя это кажется неправильным, потому что я получаю ошибку PInvokeStackInbalance, что означает, что мое определение делегата неверно.

Остальные параметры функции являются строками или целыми числами, что означает, что они не могут вызвать ошибку, и если я просто передам IntPtr.Zero вместо делегата (что будет означать, что я указываю на несуществующую функцию обратного вызова) Я получаю ошибку AccessViolation, которая также имеет смысл.

Что я делаю неправильно?

РЕДАКТИРОВАТЬ:

Полная функция C ++:

int
__stdcall
_Initialize (
const char*         FileName,
Callback            cbFunction,
int                 Code,
const char*         Name,
unsigned int        Option,
unsigned int        Option2
);

Моя версия C #:

[DllImport("MyDll.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int _Initialize (string FileName, CallbackDelegate cbFunction, int Code, string Name, uint Options, uint Options2);

Функция (для тестирования) вызывается только из основной подпрограммы консольного приложения:

static void Main(string[] args)
{
CallbackDelegate del = new CallbackDelegate(onCallback);

Console.Write(_Initialize("SomeFile.dat", del, 1000, "", 0, 4));
Console.Read();
}

где onCallback это:

static int onCallback(int lCode, int lParamSize, IntPtr pParam)
{
return 0;
}

Я получаю PInvokeStackInbalance ошибка на линии, куда я звоню _Initializeесли я передам IntPtr.Zero вместо делегата, и измените определение функции на IntPtr вместо CallbackDelegate тогда я получаю AccessViolationException,

10

Решение

Я добавил ваш код в свой текущий проект, где я много взаимодействую с C # / C ++ в VS2012. И хотя я ненавижу использовать «это работало на моей машине», оно работало нормально для меня. Код, который я запустил, приведен ниже, чтобы проиллюстрировать, что я не внес и фундаментальные изменения.

Мое предложение состоит в том, чтобы вы построили новый собственный dll с функцией-заглушкой для _Initialize, как показано ниже, и посмотрите, работает ли он, когда вы можете контролировать обе стороны интерфейса. Если это работает, но настоящая dll не работает, это сводится либо к настройкам компилятора на нативной стороне, либо к ошибкам на нативной стороне, и это топает по стеку.

extern "C" {

typedef int (__stdcall* Callback)(long lCode,long lParamSize,void* pParam );

TRADITIONALDLL_API int __stdcall _Initialize (const char* FileName,Callback cbFunction, int                 Code,
const char*         Name,unsigned int        Option,unsigned int        Option2)
{
cbFunction(0, 0, nullptr);
return 0;
}
}

На стороне C # я добавил объявления в мой класс интерфейса:

 public delegate int CallbackDelegate(int lCode, int lParamSize, IntPtr pParam);

[DllImport("XXX.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int _Initialize(string FileName, CallbackDelegate cbFunction, int Code, string Name, uint Options, uint Options2);

А потом по-моему:

private int onCallback(int lCode, int lParamSize, IntPtr pParam)
{
return 0;
}
XXXInterface.CallbackDelegate del = new XXXInterface.CallbackDelegate(onCallback);

Console.Write(XXXInterface._Initialize("SomeFile.dat", del, 1000, "", 0, 4));
4

Другие решения

ЧИСТАЯ long это 64 бита. C ++ long может быть всего 32 бита. Проверьте с помощью компилятора C ++, который скомпилировал это определение относительно того, какой это размер longс.

3

[UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)]
unsafe delegate int CallbackDelegate (int lCode, int lParamSize, IntPtr pParam);

Если .NET предполагает использование cdecl вместо stdcall, ваш стек наверняка будет храниться.

3
По вопросам рекламы [email protected]