C # делегат обратного вызова с параметрами вызывает AccessViolation при вызове из C ++ DLL - PullRequest
0 голосов
/ 13 июня 2019

У меня есть неуправляемая C ++ DLL и приложение .net, которые общаются с помощью P / Invoke.Мне нужно обновить словарь в приложении .net из C ++ DLL.

Я попытался сделать это следующим образом:

public delegate void MyDelegate(string address, string username);

[DllImport("MyDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void SaveMyDelegate(MyDelegate callback);

private static SortedDictionary<string, string> dict = new SortedDictionary<string, string>();

public void save_delegate() {

    SaveMyDelegate(delegate(string address, string username) {
        if (username != "") {
            dict.Add(address, username);
        }
     });
 }

На стороне C ++ у меня есть:

typedef void (*MANAGED_CALLBACK)(string user_address, string username);

    extern "C" __declspec(dllexport) void SaveMyDelegate(MANAGED_CALLBACK callback);

    MANAGED_CALLBACK my_callback;
    void SaveMyDelegate(MANAGED_CALLBACK callback) {
        my_callback = callback;
    }

extern "C" __declspec(dllexport) VOID start_collection();
VOID start_collection() {
    my_callback("test", "User");
}

На C # я делаю следующие вызовы:

[DllImport("MyDLL.dll")]
public static extern void start_collection();

private void Button1_Click(object sender, EventArgs e) {
    save_delegate();

    start_collection();
}

Когда я звоню start_collection (), я получаю исключение AccessViolation .Я попытался объявить делегата следующим образом:

public delegate void MyDelegate(
[MarshalAs(UnmanagedType.LPStr)]string address, 
[MarshalAs(UnmanagedType.LPStr)]string username);

Я также добавил это утверждение:

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void MyDelegate(...)

1 Ответ

4 голосов
/ 13 июня 2019

Я не рассматривал каждую деталь вашего кода, но некоторые часто встречающиеся проблемы с p / invoke сразу исчезли:

  1. Вы не можете использовать строки C ++ в качестве типов взаимодействия. Вы должны использовать массивы символов с нулевым символом в конце на стороне C ++. Получите их, используя c_str() метод std::string.
  2. Вероятно, у делегата неправильное соглашение о вызовах. Неуправляемый код (вероятно) использует cdecl, поэтому вам необходимо использовать атрибут [UnmanagedFunctionPointer(CallingConvention.Cdecl)] при объявлении типа делегата в C # .
  3. Ваш делегат C # может быть забран рано (хотя ваш неуправляемый код все еще содержит ссылку на него), поскольку на него нет управляемых ссылок. Обычно это можно решить, удерживая ссылку на делегата в статической переменной в вашем коде C #.
...