【发布时间】:2016-03-03 21:53:30
【问题描述】:
我有一个代码可以通过 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 上重现此问题,这与日文版本有某种关系。
【问题讨论】:
-
源字符串以 utf-8 编码。但是 CComVariant 不知道,它会一直使用系统默认的代码页。它是 utf-8 的几率非常接近于零。嗯,零。您必须使用 std::wstring 来防止此类意外编码问题。从问题中不清楚需要从哪里开始,当然越早越好。如果您的 json 解析器太不稳定,那么使用 CP_UTF8 将自己转换为 MultiByteToWideChar()。
-
唯一适用于 UTF-8 字节的 VARIANT 是一个字节数组。如果您从 UTF-8 转换为 UTF-16,则可以使用 BSTR — UTF-16 代码单元的计数序列。 (抱歉,如果我在这里更改 MFC、ATL 和 Win32 API 的组合。)