使用协议缓冲区/Protobuf 的 PInvoke 通用字符串格式
Posted
技术标签:
【中文标题】使用协议缓冲区/Protobuf 的 PInvoke 通用字符串格式【英文标题】:Common string format for PInvoke using Protocol buffers / Protobuf 【发布时间】:2018-02-13 14:36:56 【问题描述】:我有一个 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 编码的开销不满意。我的问题是,我能否在 Invoke 函数中使用封送参数和/或正确的数据类型来获得相同的结果?
【问题讨论】:
【参考方案1】:由于您已经使用 LPStr 作为 Marshalling-Type,因此您应该确保使用 unicode 字符串,因为 C# 中的 System.String 是 unicode,而 C++ 中的默认字符集是多字节 (UCS2)。
您可以在 Visual Studio 的项目设置中执行此操作。 确保字符集设置为“使用 Unicode 字符集”。这应该可以解决您的问题。
您还可以在 C# 中将 UCS2 转换为 Unicode(已经在 SO,但这也意味着开销,您可以通过在 C++ 中选择 Unicode 来避免这种情况。
【讨论】:
以上是关于使用协议缓冲区/Protobuf 的 PInvoke 通用字符串格式的主要内容,如果未能解决你的问题,请参考以下文章
协议缓冲区 c# (protobuf-net) Message::ByteSize
协议缓冲区架构无效。导入“google/protobuf/any.proto”尚未加载:GCP/Pub-Sub
C++ 协议缓冲区:常量表达式中的临时非文字类型 'google::protobuf::internal::CallOnInitializedMutex <std::mutex>'