我如何使用MultiByteToWideChar?

时间:2011-07-14 12:19:02

标签: c++ winapi visual-c++ character-encoding

我想将正常string转换为wstring。为此,我尝试使用Windows API函数MultiByteToWideChar。 但它对我不起作用。

这就是我所做的:

string x = "This is c++ not java";
wstring Wstring;
MultiByteToWideChar( CP_UTF8 , 0 , x.c_str() , x.size() , &Wstring , 0 ); 

最后一行产生编译错误:

'MultiByteToWideChar' : cannot convert parameter 5 from 'std::wstring *' to 'LPWSTR'

如何解决此错误?

此外,参数cchWideChar的值应该是多少?好吗?

5 个答案:

答案 0 :(得分:32)

您必须拨打MultiByteToWideChar两次:

  1. 第一次调用MultiByteToWideChar用于查找宽字符串所需的缓冲区大小。看看Microsoft's documentation;它说:

      

    如果函数成功且 cchWideChar 为0,则返回值为 lpWideCharStr 指示的缓冲区所需的大小(以字符为单位)。

    因此,要使MultiByteToWideChar为您提供所需的大小,请将0作为最后一个参数cchWideChar的值。您还应该将NULL作为前一个lpWideCharStr传递。

  2. 使用上一步中的缓冲区大小,获取足够大的非const缓冲区以容纳宽字符串。将此缓冲区传递给另一个MultiByteToWideChar的调用。而这次,最后一个参数应该是缓冲区的实际大小,而不是0。

  3. 一个粗略的例子:

    int wchars_num = MultiByteToWideChar( CP_UTF8 , 0 , x.c_str() , -1, NULL , 0 );
    wchar_t* wstr = new wchar_t[wchars_num];
    MultiByteToWideChar( CP_UTF8 , 0 , x.c_str() , -1, wstr , wchars_num );
    // do whatever with wstr
    delete[] wstr;
    

    另外,请注意使用-1作为cbMultiByte参数。这将使得结果字符串以空值终止,从而使您无需处理它们。

答案 1 :(得分:2)

一些常见的转换:

#define WIN32_LEAN_AND_MEAN

#include <Windows.h>

#include <string>

std::string ConvertWideToANSI(const std::wstring& wstr)
{
    int count = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.length(), NULL, 0, NULL, NULL);
    std::string str(count, 0);
    WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, &str[0], count, NULL, NULL);
    return str;
}

std::wstring ConvertAnsiToWide(const std::string& str)
{
    int count = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), NULL, 0);
    std::wstring wstr(count, 0);
    MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), &wstr[0], count);
    return wstr;
}

std::string ConvertWideToUtf8(const std::wstring& wstr)
{
    int count = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr.length(), NULL, 0, NULL, NULL);
    std::string str(count, 0);
    WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &str[0], count, NULL, NULL);
    return str;
}

std::wstring ConvertUtf8ToWide(const std::string& str)
{
    int count = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0);
    std::wstring wstr(count, 0);
    MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), &wstr[0], count);
    return wstr;
}

答案 2 :(得分:1)

关于这个的第二个问题,今天早上!

WideCharToMultiByte()和MultiByteToWideChar()很难用。每次转换都需要对例程进行两次调用,并且必须考虑分配/释放内存并确保字符串正确终止。你需要一个包装器!

我的博客here上有一个方便的C ++包装器,欢迎您使用。

这是今天早上的另一个question

答案 3 :(得分:0)

该函数无法获取指向C ++字符串的指针。它需要一个指向宽字符缓冲区的指针 - 你必须自己分配这个缓冲区。

string x = "This is c++ not java";
wstring Wstring;
Wstring.resize(x.size());
int c =  MultiByteToWideChar( CP_UTF8 , 0 , x.c_str() , x.size() , &Wstring[0], 0 ); 

答案 4 :(得分:0)

您可以在下面尝试此解决方案。我测试过它可以检测特殊字符(例如:ºäçá),适用于Windows XP,Windows 2000和SP4及更高版本,Windows 7,8,8.1和10。 使用std::wstring代替new wchar_t / delete,我们可以减少泄漏资源,溢出缓冲区和损坏堆的问题。

dwFlags设置为MB_ERR_INVALID_CHARS,适用于带有SP4及更高版本Windows XP的Windows 2000。如果未设置此标志,则该函数将以静默方式删除非法代码点。

std::wstring ConvertStringToWstring(const std::string &str)
{
    if (str.empty())
    {
        return std::wstring();
    }
    int num_chars = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, str.c_str(), str.length(), NULL, 0);
    std::wstring wstrTo;
    if (num_chars)
    {
        wstrTo.resize(num_chars);
        if (MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, str.c_str(), str.length(), &wstrTo[0], num_chars))
        {
            return wstrTo;
        }
    }
    return std::wstring();
}