如何通过 COM 变体编组 utf-8 字节串?
How to marshall utf-8 bytestring via 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无法重现这个问题,这跟日版有点关系。
问题在评论中解释了。至于解决方案,因为您使用的是 std
(还有很多其他解决方案),我建议您使用此答案中定义的 widen
函数: Is this code safe using wstring with MultiByteToWideChar?
并将代码更改为:
CComVariant result = widen(json).c_str();
让我们在调试器下检查一下。之前:
之后:
现在,VARIANT(或它包含的 BSTR)没问题了。
请注意,如果您需要来自此 VARIANT 或来自 BSTR 的等效字节字符串(您真的吗?),请不要使用像这样的损坏代码将其转换回来:std::string(CStringA(varJson))
,再次使用widen
的反向等效值,这次基于 WideCharToMultiByte
。
我找到了 2 种方法来解决这个问题:
- (按照建议)将我的 json 对象的 utf-8 编码字符串表示形式转换为预期的 Variant 正确的 unicode 字符串
- (稍微复杂一点)将我的字符串中的任何非 ascii 字符转换为 unicode 转义序列,例如
\u1234
,因此确保我的所有数据都是纯 ascii。
由于向后兼容的限制,我不得不走第二条路。
我有一个代码可以通过 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无法重现这个问题,这跟日版有点关系。
问题在评论中解释了。至于解决方案,因为您使用的是 std
(还有很多其他解决方案),我建议您使用此答案中定义的 widen
函数: Is this code safe using wstring with MultiByteToWideChar?
并将代码更改为:
CComVariant result = widen(json).c_str();
让我们在调试器下检查一下。之前:
之后:
现在,VARIANT(或它包含的 BSTR)没问题了。
请注意,如果您需要来自此 VARIANT 或来自 BSTR 的等效字节字符串(您真的吗?),请不要使用像这样的损坏代码将其转换回来:std::string(CStringA(varJson))
,再次使用widen
的反向等效值,这次基于 WideCharToMultiByte
。
我找到了 2 种方法来解决这个问题:
- (按照建议)将我的 json 对象的 utf-8 编码字符串表示形式转换为预期的 Variant 正确的 unicode 字符串
- (稍微复杂一点)将我的字符串中的任何非 ascii 字符转换为 unicode 转义序列,例如
\u1234
,因此确保我的所有数据都是纯 ascii。
由于向后兼容的限制,我不得不走第二条路。