Добрый день.
Работаю с C#.
Есть стандартная библиотека microsoft pinvokelib.dll, написанная на C++:
https://msdn.microsoft.com/ru-ru/library/as6wyhwt.aspx
Я нашёл её реализацию в интернете:
http://files.rsdn.org/82761/pinvokelib.dll
Среди прочего она содержит примеры функций, которые принимают в качестве аргументов ссылки на функции. Пример реализации вызова таких функций из C# также есть в MSDN:
https://msdn.microsoft.com/ru-ru/library/5zwkzwf4.aspx
Я реализовал выше описанный пример у себя. На 2-х разных версиях Студии (2012 и 2015). В обоих случаях возникает СОБЫТИЕ (НЕ ИСКЛЮЧЕНИЕ):
"Обнаружено событие PinvokeStackImbalance"
Вызов функции PInvoke "ConsoleApplication5!ConsoleApplication5.Program::TestCallBack" разбалансировал стек. Вероятно, это вызвано тем, что управляемая сигнатура PInvoke не совпадает с неуправляемой целевой сигнатурой. Убедитесь, что соглашение о вызовах и параметры сигнатуры PInvoke совпадают с неуправляемой целевой сигнатурой.
Переданные функции успешно вызываются и передают корректные результаты в библиотеку. Т.к. это не исключение, то программа не прерывается и, вроде как, полностью и в данном случае корректно выполняется.
Чтобы избежать данного сообщения, я попробовал добавить некоторые атрибуты для данного кода в C#:
public class App
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.U1)]
public delegate bool FPtr([MarshalAs(UnmanagedType.I4)] Int32 value);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.U1)]
public delegate bool FPtr2([MarshalAs(UnmanagedType.LPStr)] string value);
// Declares managed prototypes for unmanaged functions.
//[DllImport("..\\LIB\\PinvokeLib.dll")]
[DllImport("PinvokeLib.dll")]
public static extern void TestCallBack(FPtr cb, [MarshalAs(UnmanagedType.I4)] Int32 value);
//public static extern void TestCallBack(IntPtr cb, [MarshalAs(UnmanagedType.I4)] Int32 value);
//[DllImport("..\\LIB\\PinvokeLib.dll")]
[DllImport("PinvokeLib.dll")]
public static extern void TestCallBack2(FPtr2 cb2, [MarshalAs(UnmanagedType.LPStr)] String value);
//public static extern void TestCallBack2(IntPtr cb2, [MarshalAs(UnmanagedType.LPStr)] String value);
public static void Main()
{
FPtr cb = new FPtr(App.DoSomething);
//LibWrap.TestCallBack(cb, 99);
TestCallBack(cb, 99);
//TestCallBack(Marshal.GetFunctionPointerForDelegate(cb), 99);
FPtr2 cb2 = new FPtr2(App.DoSomething2);
//LibWrap.TestCallBack2(cb2, "abc");
TestCallBack2(cb2, "abc");
//TestCallBack2(Marshal.GetFunctionPointerForDelegate(cb2), "abc");
Console.ReadLine();
}
[return: MarshalAs(UnmanagedType.U1)]
public static bool DoSomething([MarshalAs(UnmanagedType.I4)] Int32 value)
//public static bool DoSomething(int value)
{
Console.WriteLine("\nCallback called with param: {0}", value);
// ...
return true;
}
[return: MarshalAs(UnmanagedType.U1)]
public static bool DoSomething2([MarshalAs(UnmanagedType.LPStr)] String value)
//public static bool DoSomething2(String value)
{
Console.WriteLine("\nCallback called with param: {0}", value);
// ...
return true;
}
}
При этом после обращения и выполнения функции DoSomething функция TestCallBack выдаёт исключение:
AccessViolationException was unhandled
An unhandled exception of type 'System.AccessViolationException' occurred in ConsoleApplication1.exe
Additional information: Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.
Что я делаю не так? Как корректно вызвать данные функции, чтобы не было ни сообщений, ни исключений??