从C ++ DLL

时间:2019-06-12 23:06:17

标签: c# c++ .net pinvoke unmanaged

我有一个非托管C ++ DLL和一个.net应用程序,它们使用P / Invoke进行通信。 我需要从C ++ DLL更新.net应用程序中的字典。

我试图通过以下方式做到这一点:

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 个答案:

答案 0 :(得分:4)

我没有查看代码的每个细节,但立即发现了一些常见的p / invoke问题:

  1. 您不能将C ++字符串用作互操作类型。您应该在C ++端使用以null结尾的字符数组。使用c_str()的{​​{1}}方法获取这些内容。
  2. 该代表可能有错误的调用约定。非托管代码(可能)使用std::string,因此在declaring the delegate type in C#时需要使用cdecl属性。
  3. 您的C#委托很容易被尽早收集(尽管您的非托管代码仍保留对它的引用),因为没有托管对它的引用。通常,这可以通过在C#代码的静态变量中保留对委托的引用来解决。