15.12.2017 Передача делегата в библиотеку C++ в качестве параметра
 
Добрый день.

Работаю с 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: Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.

Что я делаю не так? Как корректно вызвать данные функции, чтобы не было ни сообщений, ни исключений??