如何通过COM变体编组utf-8字节串?

时间:2016-02-22 09:29:27

标签: c++ utf-8 com variant

我有一个代码通过COM变体传递一些utf-8编码的JSON字符串,特别是使用CComVariant。一切顺利,直到我的软件安装在日本用户的计算机上,我想他正在使用日语版的Windows 7.不知何故,Windows决定更改1个非ascii字符的字节序列并打破JSON格式。

组合问题:

"nić" (bytes: 0x22 0x6E 0x69 0xC4 0x87 0x22)

将它打包到CComVariant然后解压缩后,上面的字符串变为:

"niāE (bytes: 0x22 0x6E 0x69 0xC4 0x81 0x45)

即。合并ć"成为āE

我的代码如下(简化版):

void get_json(VARIANT *out)
{
    const std::string json = "\"nić\"";
    CComVariant result = json.c_str();
    result.Detach(out);
}

然后在代码的其他部分:

CComVariant varJson;
get_json(&varJson);
const std::string utf8json = std::string(CStringA(varJson));
// At this point utf8json is not the same as original json above
// and cannot be decoded properly by JSON parser.

似乎我在COM Variant中误解了CStringA的一些内容,并且在这里传递UTF-8字节并不安全。我不能用西欧的Windows版本重现这个问题,这与日文版本有所不同。

2 个答案:

答案 0 :(得分:1)

评论中解释了这个问题。至于解决方案,因为您正在使用std(还有很多其他解决方案),我建议您使用此答案中定义的widen函数:Is this code safe using wstring with MultiByteToWideChar? 并将代码更改为:

CComVariant result = widen(json).c_str();

我们在调试器下检查一下。之前:

enter image description here

后:

enter image description here

现在,VARIANT(或它包含的BSTR)没问题。

注意,如果你需要一个来自这个VARIANT或BSTR的等效字节字符串(你真的吗?),不要用这样的破坏代码将它转换回来:std::string(CStringA(varJson))再次使用反向等价物widen的{​​{1}},基于WideCharToMultiByte这次。

答案 1 :(得分:0)

我找到了两种方法来解决这个问题:

  1. (如建议的那样)将我的json对象的utf-8编码字符串表示转换为正确的unicode字符串,作为预期的Variant
  2. (稍微复杂一点)将我的字符串中的任何非ascii字符转换为像\u1234这样的unicode-escape序列,因此请确保我的所有数据都是纯粹的ascii。
  3. 由于向后兼容性的限制,我必须走第二条路线。