【发布时间】:2018-01-11 01:17:51
【问题描述】:
我是 C++ 的新手,我已经接管了一个 COM 项目来解决一些问题。 我正在处理的当前问题是处理 UTF8 字符串。 我有这段代码:
// CString strValue;
CStringW strValue;
CComVariant* val = &(*result)[i].minValue;
switch (val->vt)
{
case VT_BSTR:
//strValue = OLE2CA(val->bstrVal);
strValue = OLE2W(val->bstrVal); // Works
(*result)[i].name = strValue; // Works
(*result)[i].expression = "[" + fieldName + "] = \"" + strValue + "\""; // fails
break;
case VT_R8:
//strValue.Format("%g", val->dblVal);
strValue.Format(L"%g", val->dblVal); // Works
(*result)[i].name = strValue; // Works
(*result)[i].expression = "[" + fieldName + "] = " + strValue; // fails
break;
case VT_I4:
//strValue.Format("%i", val->lVal);
strValue.Format(L"%i", val->lVal); // Works
(*result)[i].name = strValue; // Works
(*result)[i].expression = "[" + fieldName + "] = " + strValue; // fails
break;
}
struct CategoriesData
{
public:
CComVariant minValue;
CComVariant maxValue;
//CString expression;
CStringW expression;
//CString name;
CStringW name;
tkCategoryValue valueType;
int classificationField;
bool skip;
};
问题在于strValue = OLE2CA(val->bstrVal); 这一行当val->bstrVal 是这样的俄罗斯文本Воздух 的Unicode 字符串时,strValue 被转换为?????。
我尝试了几种方法并搜索了互联网,但无法将 strValue 设为Воздух。
CString 可以包含这种文本还是应该更改为另一种类型?那么是哪一个?
minValue 可以是 VT_BSTR、VT_R8 或 VT_I4。
这些是我目前尝试过的选项:
strValue = val->bstrVal;
strValue = Utility::ConvertFromUtf8(val->bstrVal);
strValue = Utility::ConvertToUtf8(val->bstrVal);
temp = Utility::ConvertBSTRToLPSTR(val->bstrVal);
strValue = W2BSTR(Utility::ConvertFromUtf8(temp));
strValue = W2BSTR(val->bstrVal);
strValue = CW2A(val->bstrVal);
strValue = (CString)val->bstrVal;
strValue = Utility::ConvertToUtf8(OLE2W(val->bstrVal));
编辑 辅助函数的代码:
CStringA ConvertToUtf8(CStringW unicode) {
USES_CONVERSION;
CStringA utf8 = CW2A(unicode, CP_UTF8);
return utf8;
}
CStringW ConvertFromUtf8(CStringA utf8) {
USES_CONVERSION;
CStringW unicode = CA2W(utf8, CP_UTF8);
return unicode;
}
char* ConvertBSTRToLPSTR (BSTR bstrIn)
{
LPSTR pszOut = NULL;
if (bstrIn != NULL)
{
int nInputStrLen = SysStringLen (bstrIn);
// Double NULL Termination
int nOutputStrLen = WideCharToMultiByte(CP_ACP, 0, bstrIn, nInputStrLen, NULL, 0, 0, 0) + 2;
pszOut = new char [nOutputStrLen];
if (pszOut)
{
memset (pszOut, 0x00, sizeof (char)*nOutputStrLen);
WideCharToMultiByte (CP_ACP, 0, bstrIn, nInputStrLen, pszOut, nOutputStrLen, 0, 0);
}
}
return pszOut;
}
编辑2
我添加了完整的 switch 语句。
当我将 strValue 从 CString 更改为 CStringW 时,其他情况会出现错误,例如 strValue.Format("%g", val->dblVal);
如何解决?
编辑3
我已经修复了一个类似的问题,但那是转换为 VARIANT 而不是来自:
val->vt = VT_BSTR;
const char* v = DBFReadStringAttribute(_dbfHandle, _rows[RowIndex].oldIndex, _fields[i]->oldIndex);
// Old code, not unicode ready:
//WCHAR *buffer = Utility::StringToWideChar(v);
//val->bstrVal = W2BSTR(buffer);
//delete[] buffer;
// New code, unicode friendly:
val->bstrVal = W2BSTR(Utility::ConvertFromUtf8(v));
编辑4 感谢到目前为止的所有帮助,我设法做出了一些改变。我在这篇文章中更新了我的初始代码并添加了该函数的所有代码。我现在坚持这一行:
(*result)[i].expression = "[" + fieldName + "] = \"" + strValue + "\"";
我无法连接 CStringW 值。
更多背景信息:该函数是MapWinGIS 的一部分,这是一个开源 GIS 应用程序,您可以在其中显示地图(shapefile)。这些地图具有属性数据。该数据以 DBase IV 格式存储,可以保存 unicode/UTF-8 文本。我已经进行了修复(参见 Edit3)以在网格视图中正确显示此文本。我现在正在努力的功能是将数据分类(分组),例如为相似的值赋予相同的颜色。这个类别有一个名称和一个表达式。稍后会解析此表达式以进行实际分组。例如,我有一张带有州的地图,我想为每个州赋予不同的颜色。 如前所述,我是 C++ 新手,我真的不在我的舒适区。我真的很感谢你给我的所有帮助。我希望你能再帮助我一次。
【问题讨论】:
-
bstrVal 最初包含什么?一个 UTF8 字符串?你一开始是怎么放进去的)。 Windows 没有原生的 UTF8 字符串类型,所以你必须以某种方式进行转换,它才能工作,那么 Utility::ConvertToUtf8 是如何编码的?
-
我添加了辅助函数的代码
-
BSTR 存储为 UTF-16 ,你不应该尝试任何 UTF8 的东西。 (好吧,我猜可能有人将 UTF-8 字节复制到 BSTR 中,但这会非常糟糕)
-
答案取决于您是否在 Unicode 项目中。如果是,那么
CString表示CStringW并且您不会使用任何 UTF-8 覆盖;否则它意味着CStringA,你会的。 IMO 最好使用 Unicode 项目,但如果您正在处理最初构建为非 Unicode 的遗留代码,那么您可能会被困住。请澄清哪种情况适合您,因为两者的答案都不同。 (你可以通过重载转换函数同时支持) -
如果它是一个 unicode 项目,那么我不清楚您要在 CStringW 中使用 UTF-8 做什么
标签: c++ unicode com type-conversion bstr