使用协议缓冲区/ Protobuf的PInvoke的通用字符串格式

时间:2018-02-13 14:36:56

标签: c# c++ serialization protocol-buffers pinvoke

我有一个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编码的开销。我的问题是,我可以使用编组参数和/或调用函数中的正确数据类型来获得相同的结果吗?

1 个答案:

答案 0 :(得分:1)

由于你已经使用LPStr作为Marshalling-Type,你应该确保使用unicode字符串,因为C#中的System.String是unicode,而C ++中的默认字符集是Multi-Byte(UCS2)。

您可以在Visual Studio的项目设置中执行此操作。 确保将字符集设置为“使用Unicode字符集”。这应该可以解决你的问题。

您也可以在C#中将UCS2转换为Unicode(已在SO上,但这也意味着开销,您可以通过在C ++中选择Unicode来避免开销。