如何将CComVariant bstr转换为CString

时间:2017-08-03 12:24:54

标签: c++ unicode com type-conversion bstr

我是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 我添加了完整的switch语句。 当我将strValue从CString更改为CStringW时,我得到其他情况的错误,例如strValue.Format("%g", val->dblVal); 怎么解决这个问题?

EDIT3 我已经解决了类似的问题,但是转换为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的一部分,这是一个开源GIS应用程序,您可以在其中显示地图(shapefile)。这些地图具有属性数据。此数据以DBase IV格式存储,可以保存unicode / UTF-8文本。我已经修复了(请参阅Edit3)以在网格视图中正确显示此文本。我现在正在努力的功能是对数据进行分类(分组),例如给出相同颜色的相同值。此类别具有名称和表达式。稍后将解析此表达式以执行实际分组。例如,我有一个状态的地图,我想给每个州一个不同的颜色。 如前所述,我是C ++的新手,我真的在我的舒适区之外。我非常感谢你给我的所有帮助。我希望你能再次帮助我。

2 个答案:

答案 0 :(得分:2)

BSTR s“自然地”存储Unicode UTF-16 长度前缀字符串,但您可以“拉伸” BSTR并存储有一个更通用的长度前缀字节序列(但我不喜欢这种用法)。

(有关BSTR的详细信息,您会发现this blog post by Eric Lippert非常有趣。)

所以,我正在考虑BSTR的正常用法,它存储长度为前缀的UTF-16字符串。

如果要将存储在BSTR中的UTF-16字符串转换为 UTF-8 字符串,可以将WideCharToMultiByte Win32 API与{{{ 1}}标志(有关详细信息,请参阅例如this MSDN Magazine article,以及this reusable code on GitHub)。

您可以将目标UTF-8字符串存储在CP_UTF8类的实例中。

PS 如果您想将std::string用于UTF-16而CStringW用于UTF-8字符串,并使用ATL CStringA帮助程序用于UTF-16 / 8转换,请注意您的代码中不需要CW2A宏;你可以通过USES_CONVERSION(const引用)获取输入字符串作为良好的代码卫生:

const&

RE编辑2

使用CStringA Utf8FromUtf16(const CStringW &utf16) { CStringA utf8 = CW2A(utf16, CP_UTF8); return utf8; } 尝试strValue.Format(L"%g",...CStringW前缀为L生成Unicode UTF-16字符串文字。

RE编辑4

我在评论中回复了这一点,但为了完整起见,要将字符串文字与CStringW::Format个实例连接起来,请考虑使用 CStringW 来装饰这些文字:这定义Unicode UTF-16字符串文字,基于L"...",适用于wchar_t个对象。

CStringW

答案 1 :(得分:1)

如果不将项目转换为支持Unicode的应用程序,您将无法获得始终可用的版本。

换句话说,要支持可能属于BSTR的所有字符,您需要Unicode CString(CStringW)

您可能会继续使用MBCS版本,但在这种情况下,您仍需要处理Unicode。使用CStringW可能是一个选项。

使用WideCHarToMultiByte

转换为UTF-8