将字符串数组从 C# 传递到C++ DLL 函数,并将其填充到 DLL 中并返回

本文关键字:DLL 返回 填充 函数 C++ 数组 字符串 | 更新日期: 2023-09-27 18:35:52

我正在编写一个 C# 应用程序,该应用程序将大小为 30 的空字符串数组传递给C++ DLL。此字符串数组需要在 DLL 中填充,并返回给 C# 应用程序。

我的代码我观察到从 DLL 调用函数结束时内存损坏。

我的C++DLL代码如下:

SAMPLEDLL_API BOOL InitExecution (wchar_t **paszStrings, int count)
{
    for (int i = 0 ; i < count; i++)
    {
        mbstowcs(*(paszStrings + i), "Good",4);
        //*(paszStrings + i) = "Good";
    }
return TRUE;
}

我的 C# 代码是

string[] names = new[] { "Britto", "Regis" };
if (Wrapper1.InitExecution(ref names, names.Length) == 1)
    MessageBox.Show("Passed");
[DllImport("MFCLibrary1.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern UInt32 InitExecution(ref string[] Names, int count);

将字符串数组从 C# 传递到C++ DLL 函数,并将其填充到 DLL 中并返回

要使当前的方法起作用,您需要传递StringBuilder实例而不是string 。这是因为数据是从调用方流向被叫方的。字符串是输出参数。这意味着调用方必须为每个字符串分配缓冲区,并知道缓冲区需要多大。

在这里使用BSTR要容易得多。这允许您在本机代码中分配字符串,并在托管代码中取消分配字符串。这是因为BSTR是在共享 COM 堆上分配的,并且 p/invoke 封送器可以理解它们。进行此细微更改意味着调用方不需要预先知道字符串的大小。

代码如下所示:

SAMPLEDLL_API BOOL InitExecution(BSTR* names, int count)
{
    for (int i = 0 ; i < count; i++)
        names[i] = SysAllocStr(...);
    return TRUE;
}

在 C# 方面,您可以像这样编写它:

[DllImport(@"mydll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool InitExecution(
    [Out] IntPtr[] names, 
    int count
);

然后,您有一些工作要从BSTR编组到 C# string

IntPtr[] namePtrs = new IntPtr[count];
InitExecution(namePtrs, namePtrs.Length);
string[] names = new string[namePtrs.Length];
for (int i = 0; i < namePtrs.Length; i++)
{
    names[i] = Marshal.PtrToStringBSTR(namePtrs[i]);
    Marshal.FreeBSTR(namePtrs[i]);
}