我是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;
}
Edit2我添加了完整的开关语句。当我将strValue从CString改为CStringW时,会得到其他情况下的错误,比如strValue.Format("%g", val->dblVal);
,如何解决这个问题?
Edit3 I已经修复了一个类似的问题,但这是转换为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));
Edit4,感谢到目前为止所提供的所有帮助,我成功地做了一些更改。我在这篇文章中更新了我的初始代码,并添加了函数的所有代码。我现在被困在这句话里:
(*result)[i].expression = "[" + fieldName + "] = \"" + strValue + "\"";
我不能连接CStringW值。
更多的背景信息:这个函数是MapWinGIS的一部分,它是一个开源的地理信息系统应用程序,在这里你可以显示地图(Shapefile)。这些地图有属性数据。这些数据以DBase IV格式存储,可以保存unicode/UTF-8文本。我已经做了一个修复(参见Edit3),以便在网格视图中正确地显示该文本。我现在正在挣扎的函数是对数据进行分类(分组),例如给相似的值以相同的颜色。这个类别有一个名称和一个表达式。稍后将解析此表达式以执行实际分组。例如,我有一个有状态的地图,我想给每个州一个不同的颜色。正如前面提到的,我是C++的新手,而且真的超出了我的舒适范围。我真的很感激你给我的一切帮助。我希望你能再帮我一次。
发布于 2017-08-03 14:22:35
BSTR
s“自然”存储Unicode UTF-16长度-前缀字符串,尽管您可以“拉伸”BSTR
并使用它存储一个更通用的前缀字节序列(但我不喜欢这种用法)。
(有关BSTR
的更多细节,您会发现这篇由Eric Lippert撰写的博客文章非常有趣。)
所以,我正在考虑BSTR
的正常用法,它存储长度前缀UTF-16字符串。
如果要将存储在BSTR
中的UTF-16字符串转换为UTF-8字符串,可以使用带有CP_UTF8
标志的WideCharToMultiByte
Win32 API (参见这篇MSDN杂志的文章获取详细信息和GitHub上的可重用代码)。
可以将目标UTF-8字符串存储在std::string
类的实例中。
P.S.如果您想对UTF-16使用CStringW
,对于UTF-8字符串使用CStringA
,对于UTF-16/8转换使用ATL CW2A
助手,请注意代码中不需要USES_CONVERSION
宏;您可以将const&
(const引用)的输入字符串作为良好的代码卫生:
CStringA Utf8FromUtf16(const CStringW &utf16) {
CStringA utf8 = CW2A(utf16, CP_UTF8);
return utf8;
}
RE编辑2
尝试strValue.Format(L"%g",...
和CStringW
。L
前缀为CStringW::Format
生成一个Unicode 16字符串文本。
RE编辑4
我在注释中对此做出了答复,但为了完整起见,要将字符串文本与CStringW
实例连接起来,可以考虑使用L"..."
:来装饰这些文字--这定义了一个Unicode UTF-16字符串文字,即wchar_t
-based,并且可以很好地处理CStringW
对象。
(*result)[i].expression = L"[" + fieldName + L"] = \"" + strValue + L"\"";
发布于 2017-08-03 12:33:35
如果不将项目转换为Unicode感知的应用程序,则无法获得始终工作的版本。
换句话说,要支持所有可能在BSTR中分离的字符,您需要一个Unicode CString (CStringW)。
您可以继续使用MBCS版本,但在这种情况下,您仍然需要处理Unicode。在这里使用CStringW可能是一种选择。
转换为UTF-8是用WideCHarToMultiByte完成的。
发布于 2021-09-29 05:38:45
如何:在各种字符串类型之间进行转换
https://learn.microsoft.com/en-us/cpp/text/how-to-convert-between-various-string-types
本主题演示如何将各种VisualC++字符串类型转换为其他字符串。涵盖的字符串类型包括char、wchar_t、_bstr_t、CComBSTR、CString、basic_string和System.String。在所有情况下,在转换为新类型时都会生成字符串的副本。对新字符串的任何更改都不会影响原始字符串,反之亦然。
https://stackoverflow.com/questions/45484130
复制相似问题