我需要对用C ++编写的DLL进行互操作调用。在C ++代码中,有各种函数可以接收和返回字符串。这些都使用C ++中常用的类型(struct),它包含一个指向字符串的指针以及一个大小的整数,如下所示:
struct StringParam
{
int size; // 4 byte integer for the size of the string buffer
LPWSTR buff; // Pointer to a wide char buffer
}
当从DLL返回字符串并且字符串缓冲区太小而无法存储字符串结果时,将返回错误代码以及整数 size 中所需的正确大小缓冲区字段,以便调用者可以提供正确大小的缓冲区。
暂时忽略结构,这可以通过使用StringBuilder参数的组合以及大小的ref int参数的interop轻松完成。但是,我们使用的是结构,并且在编组的结构中不允许使用StringBuilder字段。
给定一个接收字符串的C ++函数,如下所示:
int __stdcall DoSomethingWithString(StringParam *stringParam)
可以在C#中声明以下结构:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct StringParam
{
public int Size;
[MarshalAs(UnmanagedType.LPWStr)]
public string Text;
public StringParam(string text)
{
this.Text = text;
this.Size = text.Length;
}
}
并且可以使用以下签名成功初始化结构并调用C ++函数:
[DllImport("Custom.dll", CharSet = CharSet.Unicode)]
public static extern int DoSomethignWithString(ref StringParam stringParam);
但是,如果函数需要按如下方式返回字符串,则会出现问题:
[DllImport("Custom.dll", CharSet = CharSet.Unicode)]
public static extern int GetSomeString(ref StringParam stringParam);
当从interop调用接收字符串时,我们不知道字符串的大小,并且必须分配足够大的缓冲区来存储字符串结果。 StringBuilder是理想的,但不能在编组的结构中使用。我们可以预先分配带有2048个虚拟字符的字符串,然后可以用它来存储结果。事实上,这在尝试使用StringBuilder类型的错误消息中建议:
无法编组'StringParam'类型的字段'Text':struct或class字段不能是StringBuilder类型。通常可以通过使用String字段并将其初始化为长度与相应缓冲区长度匹配的字符串来实现相同的效果。
使用虚拟值预先初始化字符串似乎很麻烦。还有其他/更好的方法吗?