Передача функции обратного вызова C # через Interop / pinvoke

#c# #function #interop #callback #pinvoke

#c# #функция #взаимодействие #обратный вызов #pinvoke

Вопрос:

Я пишу приложение на C #, которое использует службы взаимодействия для доступа к функциям в собственной C DLL. Я уже использую около 10 различных функций, которые работают.

Теперь я не уверен, как обрабатывать передачу обратного вызова в качестве параметра, чтобы DLL могла вызывать мой код.

Вот прототип функции DLL:

 typedef void (WINAPI * lpfnFunc)(const char *arg1, const char *arg2)
 

И функция, которая позволяет мне передавать указанный выше тип:

 int WINAPI SetFunc(lpfnFunc f)
 

Вот мой код на C # для определения делегата и функции:

 public delegate void Func(string arg1, string arg2);

public static void MyFunc(string arg1, string arg2)
 

Вот мой код на C # для функции взаимодействия SetFunc:

 [DllImport("lib.dll", CharSet = CharSet.Ansi)]
public static extern int SetFunc(Func lpfn);
 

И, наконец, вот код, в котором я вызываю функцию SetFunc и передаю ей свой обратный вызов:

 SetFunc(new Func(MyFunc));
 

К сожалению, моя функция не вызывается, когда это должно быть. Возвращаемое значение функции SetFunc возвращает код ошибки для успешного выполнения, поэтому либо она не вызывает мою функцию, либо она не работает, потому что мой код неверен.

Комментарии:

1. Код неправильный, объект делегата будет собирать мусор. Обычно это приводит к сбою вместо «просто не работает». Сохраните делегат в переменной, чтобы сборщик мусора видел ссылку на него.

2. Я создал статическую ссылку. Его все еще не вызывают. Должно быть, какие-то проблемы с библиотекой.

Ответ №1:

Это работает для меня:

Calc.h (Calc.dll , C ):

 extern "C" __declspec(dllexport) double Calc(double x, double y, double __stdcall p(double, double));
 

Calc.cpp (Calc.dll , C ):

 #include "calc.h"

__declspec(dllimport) double Calc(double x, double y, double __stdcall p(double, double))
{
    double s = p(x*x, y*y);
    return x * y   s;
}
 

Program.cs (Sample.exe , C#):

 class Program
{
    delegate double MyCallback(double x, double y);
    [DllImport("Calc.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern double Calc(double x, double y, [MarshalAs(UnmanagedType.FunctionPtr)]MyCallback func);

    static void Main(string[] args)
    {
        double z = Calc(1, 2, (x, y) => 45);
    }
}
 

Комментарии:

1. Это работает для меня на C, но объявление метода в обоих. h и .c должны быть dllexport . dllimport не разрешен

Ответ №2:

Можете ли вы попробовать изменить делегат функции на

     public delegate void Func([In, MarshalAs(UnmanagedType.LPStr)] string arg1, [In, MarshalAs(UnmanagedType.LPStr)] string arg2);
 

И метод SetFunc для

 [DllImport("lib", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Winapi)]
public static extern int SetFunc(Func lpfn);