将字符串数组从C#传递到C ++ DLL函数并将其填充到DLL中并返回
我正在编写一个C#应用程序,该程序将大小为30的空字符串数组传递给C ++ DLL.该字符串数组需要填充到DLL中,并返回给C#应用程序.
I am writing a C# application that passes an empty string array of size 30 to a C++ DLL. This string array needs to be filled in the DLL and given back to the C# application.
我的代码在DLL的函数调用结束时观察到内存损坏.
I my code I observe memory corruption at the end of function call from DLL.
我的C ++ DLL代码如下:
My C++ DLL code is as follows:
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);
要使这种当前方法有效,您需要传递StringBuilder
实例而不是string
.那是因为数据从调用者流向被调用者.字符串是out参数.这意味着调用者必须为每个字符串分配缓冲区,并知道缓冲区需要多大.
To make this current approach work you'd need to pass StringBuilder
instances rather than string
. That's because the data is flowing from caller to callee. The strings are out parameters. And that means that the caller has to allocate the buffers for each string, and know how large the buffers need to be.
在这里使用BSTR
要容易得多.这使您可以在本机代码中分配字符串,并在托管代码中将它们释放.这是因为BSTR
是分配在共享COM堆上的,而p/invoke marshaller可以理解它们.进行此轻微更改意味着调用者不需要知道字符串的大小.
It's much easier to use BSTR
here. This allows you to allocate the strings in the native code, and have them deallocated in the managed code. That's because BSTR
is allocated on the shared COM heap, and the p/invoke marshaller understands them. Making this slight change means that the caller does not need to know how large the strings are up front.
代码如下:
SAMPLEDLL_API BOOL InitExecution(BSTR* names, int count)
{
for (int i = 0 ; i < count; i++)
names[i] = SysAllocStr(...);
return TRUE;
}
在C#端,您可以这样编写:
And on the C# side you write it like this:
[DllImport(@"mydll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool InitExecution(
[Out] IntPtr[] names,
int count
);
然后您需要做一些工作才能从BSTR
编组到C#string
.
And then you've got a bit of work to marshal from BSTR
to 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]);
}