我有一个C ++库,可以访问大型数据集。我在C#应用程序中使用它,通过使用PInvoke来调用C ++函数。
我使用protobuf在C ++中序列化数据集,将数据作为字符串传递给C#并在C#中反序列化。
C ++伪代码
ReadData(..., char * &output, ...){
Dataset data = ReadData(...);
ProtoBufDataset protobufDataset = SerializeToProtobufStructure(data);
string serialized = protobufDataset.SeralizeToString();
// allocate serialized to output string
::CoTaskMemAlloc(output, serialized);
return true;
}
C#包装函数定义
[DllImport("CPLusPLusdll.dll", CallingConvention = CallingConvention.Cdecl,
BestFitMapping = false, ThrowOnUnmappableChar = true)]
[return: MarshalAs(UnmanagedType.I1)]
internal static extern bool ReadData(
...
[MarshalAs(UnmanagedType.LPStr)] out string output,
...);
C#伪代码
string serializedData;
ReadDataFromCplusPlus(...., out serializedData, ...)
ProtobufDataset protobufDataset;
protoBufDataset.Deserialize(serializedData);
...
这很有效,但是我在解决某些数据集方面遇到了问题,我相当肯定它与字符串编码或缺乏处理它有关。我在两边添加了base64编码/解码,这似乎有用。
C ++伪代码
ReadData(..., char * &output, ...){
Dataset data = ReadData(...);
ProtoBufDataset protobufDataset = SerializeToProtobufStructure(data);
string serialized = protobufDataset.SeralizeToString();
string encoded = base64_encode(serialized);
// allocate serialized to output string
::CoTaskMemAlloc(output, encoded);
return true;
}
C#伪代码
string serializedData;
ReadDataFromCplusPlus(...., out serializedData, ...)
ProtobufDataset protobufDataset;
protoBufDataset.DeserializeInBase64(serializedData);
...
我不满意base64编码的开销。我的问题是,我可以使用编组参数和/或调用函数中的正确数据类型来获得相同的结果吗?
答案 0 :(得分:1)
由于你已经使用LPStr作为Marshalling-Type,你应该确保使用unicode字符串,因为C#中的System.String是unicode,而C ++中的默认字符集是Multi-Byte(UCS2)。
您可以在Visual Studio的项目设置中执行此操作。 确保将字符集设置为“使用Unicode字符集”。这应该可以解决你的问题。
您也可以在C#中将UCS2转换为Unicode(已在SO上,但这也意味着开销,您可以通过在C ++中选择Unicode来避免开销。