如何将 CComVariant bstr 转换为 CString
How to convert CComVariant bstr to CString
我是 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
感谢到目前为止的所有帮助,我设法做出了一些改变。我已经在此 post 中更新了我的初始代码并添加了该函数的所有代码。我现在坚持这一行:
(*result)[i].expression = "[" + fieldName + "] = \"" + strValue + "\"";
我无法连接 CStringW 值。
更多背景信息:该函数是 MapWinGIS 的一部分,这是一个开源 GIS 应用程序,您可以在其中显示地图(shapefile)。这些地图具有属性数据。此数据以 DBase IV 格式存储,可以容纳 unicode/UTF-8 文本。我已经进行了修复(请参阅 Edit3)以在网格视图中正确显示此文本。我现在正在努力的功能是对数据进行分类(分组),例如为相似的值赋予相同的颜色。这个类别有一个名称和一个表达式。这个表达式稍后被解析以进行实际的分组。例如,我有一张包含各州的地图,我想为每个州赋予不同的颜色。
如前所述,我是 C++ 的新手并且真的不在我的舒适区。我真的很感谢你给我的所有帮助。我希望你能再次帮助我。
如果不将您的项目转换为支持 Unicode 的应用程序,您将无法获得始终可用的版本。
换句话说,要支持可能在 BSTR 中分开的所有字符,您需要一个 Unicode CString (CStringW)
您可以继续使用 MBCS 版本,但在这种情况下您仍然必须处理 Unicode。在这里使用 CStringW 可能是一个选项。
转换为 UTF-8 是通过 WideCHarToMultiByte
完成的
BSTR
s "naturally" 存储 Unicode UTF-16 长度前缀字符串,尽管您可以 "stretch" a BSTR
并存储更通用的长度前缀字节序列(但我不喜欢这种用法)。
(有关 BSTR
的更多详细信息,您会发现 this blog post by Eric Lippert 非常有趣。)
因此,我正在考虑 BSTR
的正常用法,它存储以长度为前缀的 UTF-16 字符串。
如果要将存储在BSTR
中的UTF-16字符串转换为UTF-8字符串,可以使用WideCharToMultiByte
Win32 API 带有 CP_UTF8
标志(参见 this MSDN Magazine article for details, and this reusable code on GitHub)。
您可以将目标 UTF-8 字符串存储在 std::string
class.
的实例中
P.S. 如果要对 UTF-16 字符串使用 CStringW
,对 UTF-8 字符串使用 CStringA
,以及 ATL CW2A
用于 UTF-16/8 转换的助手,请注意,您的代码中不需要 USES_CONVERSION
宏;您可以将 const&
(常量参考)的输入字符串作为良好的代码卫生:
CStringA Utf8FromUtf16(const CStringW &utf16) {
CStringA utf8 = CW2A(utf16, CP_UTF8);
return utf8;
}
重新编辑 2
尝试 strValue.Format(L"%g",...
和 CStringW
。 L
前缀为 CStringW::Format
.
生成一个 Unicode UTF-16 字符串文字
重新编辑 4
我在评论中回复了那个,但为了完整起见,要将字符串文字与 CStringW
个实例连接起来,请考虑用 L"..."
[=63 装饰这些文字=]:这定义了一个 Unicode UTF-16 字符串文字,它基于 wchar_t
,并且可以很好地处理 CStringW
个对象。
(*result)[i].expression = L"[" + fieldName + L"] = \"" + strValue + L"\"";
如何:在各种字符串类型之间进行转换
https://docs.microsoft.com/en-us/cpp/text/how-to-convert-between-various-string-types
This topic demonstrates how to convert various Visual C++ string types
into other strings. The strings types that are covered include char ,
wchar_t, _bstr_t, CComBSTR, CString, basic_string, and System.String.
In all cases, a copy of the string is made when converted to the new
type. Any changes made to the new string will not affect the original
string, and vice versa.
我是 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 感谢到目前为止的所有帮助,我设法做出了一些改变。我已经在此 post 中更新了我的初始代码并添加了该函数的所有代码。我现在坚持这一行:
(*result)[i].expression = "[" + fieldName + "] = \"" + strValue + "\"";
我无法连接 CStringW 值。
更多背景信息:该函数是 MapWinGIS 的一部分,这是一个开源 GIS 应用程序,您可以在其中显示地图(shapefile)。这些地图具有属性数据。此数据以 DBase IV 格式存储,可以容纳 unicode/UTF-8 文本。我已经进行了修复(请参阅 Edit3)以在网格视图中正确显示此文本。我现在正在努力的功能是对数据进行分类(分组),例如为相似的值赋予相同的颜色。这个类别有一个名称和一个表达式。这个表达式稍后被解析以进行实际的分组。例如,我有一张包含各州的地图,我想为每个州赋予不同的颜色。 如前所述,我是 C++ 的新手并且真的不在我的舒适区。我真的很感谢你给我的所有帮助。我希望你能再次帮助我。
如果不将您的项目转换为支持 Unicode 的应用程序,您将无法获得始终可用的版本。
换句话说,要支持可能在 BSTR 中分开的所有字符,您需要一个 Unicode CString (CStringW)
您可以继续使用 MBCS 版本,但在这种情况下您仍然必须处理 Unicode。在这里使用 CStringW 可能是一个选项。
转换为 UTF-8 是通过 WideCHarToMultiByte
完成的BSTR
s "naturally" 存储 Unicode UTF-16 长度前缀字符串,尽管您可以 "stretch" a BSTR
并存储更通用的长度前缀字节序列(但我不喜欢这种用法)。
(有关 BSTR
的更多详细信息,您会发现 this blog post by Eric Lippert 非常有趣。)
因此,我正在考虑 BSTR
的正常用法,它存储以长度为前缀的 UTF-16 字符串。
如果要将存储在BSTR
中的UTF-16字符串转换为UTF-8字符串,可以使用WideCharToMultiByte
Win32 API 带有 CP_UTF8
标志(参见 this MSDN Magazine article for details, and this reusable code on GitHub)。
您可以将目标 UTF-8 字符串存储在 std::string
class.
P.S. 如果要对 UTF-16 字符串使用 CStringW
,对 UTF-8 字符串使用 CStringA
,以及 ATL CW2A
用于 UTF-16/8 转换的助手,请注意,您的代码中不需要 USES_CONVERSION
宏;您可以将 const&
(常量参考)的输入字符串作为良好的代码卫生:
CStringA Utf8FromUtf16(const CStringW &utf16) {
CStringA utf8 = CW2A(utf16, CP_UTF8);
return utf8;
}
重新编辑 2
尝试 strValue.Format(L"%g",...
和 CStringW
。 L
前缀为 CStringW::Format
.
重新编辑 4
我在评论中回复了那个,但为了完整起见,要将字符串文字与 CStringW
个实例连接起来,请考虑用 L"..."
[=63 装饰这些文字=]:这定义了一个 Unicode UTF-16 字符串文字,它基于 wchar_t
,并且可以很好地处理 CStringW
个对象。
(*result)[i].expression = L"[" + fieldName + L"] = \"" + strValue + L"\"";
如何:在各种字符串类型之间进行转换
https://docs.microsoft.com/en-us/cpp/text/how-to-convert-between-various-string-types
This topic demonstrates how to convert various Visual C++ string types into other strings. The strings types that are covered include char , wchar_t, _bstr_t, CComBSTR, CString, basic_string, and System.String. In all cases, a copy of the string is made when converted to the new type. Any changes made to the new string will not affect the original string, and vice versa.