Вопрос по c++, callback, c#, interop – C # C ++ Interop callback

7

Недавно я возился с взаимодействием между C # и C ++, в частности настраивая функцию обратного вызова, которая вызывается из C ++ DLL.

namespace TomCSharpDLLImport
{
    class Program
    {
        public delegate void TomDelegate(int a, int b);

        [DllImport("TomDllNative.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern void GetData();

        [DllImport("TomDllNative.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern void SetCallback(TomDelegate aCallback);

        static void Main(string[] args)
        {
            TomDelegate lTD = new TomDelegate(Program.TomCallback);

            SetCallback(lTD); //Sets up the callback

            int thread = Thread.CurrentThread.ManagedThreadId;

            GetData(); //This calls the callback in unmanaged code

            while (true) ;
        }

        //Callback function which is called from the unmanaged code
        public static void TomCallback(int a, int b)
        {
            Console.WriteLine("A: {0} B: {1}", a, b);
            int thread = Thread.CurrentThread.ManagedThreadId;
        }
    }
}

У меня такой вопрос, что когда программный элемент управления входит в функцию TomCallback, я ожидал, что он затем выполнит цикл while (true) в Main. Однако вместо этого программа просто выходит. Я не могу полностью разобраться в поведении, часть меня воображает, что это то, что ожидалось, но часть меня ожидала, что оно продолжится в основном.

Чего я ожидал ...

The GetData() function is called The GetData function calls the callback The callback function returns back to GetData GetData returns back to main()

Однако это не совсем верно.

Будет ли кто-то достаточно любезен, чтобы объяснить, что происходит.

Чтобы сэкономить место, я не разместил неуправляемый код, однако, если это необходимо, я рад опубликовать

Edit: Я включил неуправляемую отладку (совсем забыл это сделать) и теперь вижу сбой ..

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

Нативный код, так как именно здесь происходит сбой

#include "stdafx.h"
typedef void (*callback_function)(int, int);

extern "C" __declspec(dllexport) void SetCallback(callback_function aCallback);
extern "C" __declspec(dllexport) void GetData();

callback_function gCBF;

__declspec(dllexport) void SetCallback(callback_function aCallback)
{
    gCBF = aCallback;
}

__declspec(dllexport) void GetData()
{
    gCBF(1, 2);
}

Ваш Ответ

2   ответа
11

Вы должны преобразовать управляемый обратный вызов в указатель на собственную функцию (IntPtr в C #) с помощью

IntPtr Marshal.GetFunctionPointerForDelegate(Delegate d)

метод.

Использование SetCallback () с System.Delegate в качестве аргумента неверно.

Сделай это

SetCallback(Marshal.GetFunctionPointerForDelegate(lTD));

и переопределить SetCallback как

/// StdCall is crucial here
[DllImport("TomDllNative.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void SetCallback(IntPtr aCallback);
Попробуйте & quot; stdcall & quot; Соглашение о вызовах! Вы должны были опубликовать журнал раньше :) Я отредактировал ответ для StdCall.
Программа "выходит" - это означает крах. Будете ли вы так любезны, чтобы показать аварийный дамп? Это можно сделать в средстве просмотра событий, в списке ошибок приложения. Или просто скопируйте и вставьте консольный вывод вашей программы.
Спасибо Виктор, я обновил вопрос TomP89
Это работает сейчас?
Привет Виктор, спасибо за ответ. Я внес изменения, как вы предложили, но они по-прежнему демонстрируют точно такое же поведение. TomP89
4

У меня была та же проблема, что и у ОП (то же сообщение об ошибке). Принятый ответ совсем не помог, что даже @ TomP89 признает в комментариях.

Это неудивительно, потому что сообщение об ошибке указывает, чтоcalling convention of the passed callback функция неверна, тогда как предполагаемое решение меняетcalling convention of the function that passes the callback, что приводит к дисбалансу стека, если то, что экспортирует библиотека, является cdecl-функциями (как в случае по умолчанию для всех функций за пределами Win32 API).

Оказывается, что .Net по умолчанию принимает соглашение о вызовах & quot; stdcall & quot; для любого делегата. Как правило, неуправляемый код принимает то же соглашение о вызовах, что и его экспортируемые функции (в данном случае и мой: «cdecl»).

Таким образом, истинное решение (которое наконец-то сработало для меня) заключается в изменении соглашения о вызовах обратного вызова на «cdecl». этовопрос показывает, как это достигается, вкратце:

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void TomDelegate(int a, int b);

Похожие вопросы