如何在 MFC 多字节应用程序中显示西里尔文字?

Posted

技术标签:

【中文标题】如何在 MFC 多字节应用程序中显示西里尔文字?【英文标题】:How to show Cyrillic text in MFC Multi-Byte application? 【发布时间】:2018-03-09 11:08:23 【问题描述】:

我是 C++ 和 MFC 的新手。主要问题是我有一个需要翻译成俄语的 MFC 项目。我看到最好的选择是将项目更改为 Unicode,但我不能,因为这是一个巨大的项目,当我更改时,我收到超过 4000 个错误。稍后我们会将所有代码传递给 Unicode,但现在我只需要在按钮和 CListBox 上显示 Cyrillic。

嗯,主要是:如何用 Multibyte 打印 Cyrillic?

谢谢大家!

PD:抱歉,我会更明确地说明我的尝试:

使用俄语语言环境:

setlocale(LC_ALL, "russian_russia.1251");
setlocale(LC_CTYPE, "rus");

但是没有用。显示问号。

我还尝试使用函数 WideCharToMultiByte 进行转换。但显示的字符似乎编码错误。

std::string utf8_encode(const std::wstring &wstr)

    if (wstr.empty()) return std::string();
    int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
    std::string strTo(size_needed, 0);
    WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
    return strTo;


    wchar_t* wch = L"Привет";

    std::string ch = utf8_encode(wch);

    m_wndOutputBuild.AddString(ch.c_str()); //OUTPUT Привет

PD2:现在我这样打电话

setlocale(LC_ALL, "russian_russia.1251");

std::wstring wch = L"Привет";

std::string ch = encode_1251(wch);

m_wndOutputBuild.AddString(ch.c_str()); //OUTPUT Ïðèâåò

和功能:

std::string encode_1251(const std::wstring &wstr)

    if (wstr.empty()) return std::string();
    int size_needed = WideCharToMultiByte(1251, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
    std::string strTo(size_needed, 0);
    WideCharToMultiByte(1251, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
    return strTo;

我发现 Windows-1251 将 CP 放在 WideCharToMultiByte here 上。

【问题讨论】:

我知道,***.com/questions/48558810/… 这对我不起作用,因为我无法更改为 Unicode,我的项目是一个巨大的项目。我也尝试使用语言环境,但没有做任何改变。显示问号。 @Treith:我是在previous answer 中建议您迁移到Unicode 的人,我仍然认为这是最好的方法。无论如何,如果您和您的团队确实想保留您的代码库 MBCS(“多字节”),我建议您从一个简单的基于 MFC 对话框的应用程序开始,然后在其中插入一个编辑控件和一个列表框.从编辑控件读取用户输入,并将用户输入的行添加到列表框中。使用CEdit::GetWindowText 从编辑控件读取用户输入,使用CListBox::AddString 填充LB。 ... ... 您应该会在列表框中看到用户输入的完全相同的字符串。如果你不这样做,那么在这里发布你的代码和确切的结果。从简单开始,并尝试找出您的确切问题。我不是 MBCS/Cyrillic 方面的专家,所以我无法提供更好的帮助。 嗨@Mr.C64,这不是我的帖子。只有一个示例解决方案在我的情况下不起作用。但是谢谢,我将从这个开始。 @Treith:我注意到您在问题中添加了更多详细信息和 C++ 代码 sn-p,因此我根据这些新信息添加了答案。 【参考方案1】:

在您的utf8_encode 函数中,将您的Unicode UTF-16 字符串转换为std::string 时,您将CP_UTF8 传递给WideCharToMultiByte。然后你获取返回的 UTF-8 std::string,并通过 .c_str() 将其传递给 CListBox::AddString 方法。

但是,如果您的应用程序使用 MBCS 西里尔文,您应该将 UTF-16 转换为您的 西里尔代码页,而不是 UTF-8,并将在您的西里尔代码页中编码的字符串传递给您的 MFC 类方法,例如 CListBox::AddString

换句话说,您可能希望用cyrillic_encode 函数替换您的utf8_encode 函数,该函数将UTF-16 文本作为输入,并将其转换为您的西里尔代码页:

// Convert from Unicode UTF-16 to Cyrillic code page
std::string cyrillic_encode(const std::wstring &utf16)

然后将返回的字符串传递给感兴趣的MFC类方法,例如:

// From Unicode UTF-16 to Cyrillic code page
std::string cyrillic_text = cyrillic_encode(wch);

// Show Cyrillic-encoded "MBCS" text
m_wndOutputBuild.AddString(cyrillic_text.c_str());

此外,正如 @IInspectable 在 cmets 中正确指出的那样,请考虑在转换函数中添加适当的错误检查代码。事实上,一般情况下,可能有 UTF-16 文本无法以西里尔文正确编码,因为后者是前者的真子集。

【讨论】:

检查WideCharToMultiByte 的返回值是否有错误可能也是一个好主意,和/或传递适当的标志以优雅地处理无法在目标字符集中表示的字符。另一种解决方案是构造一个CStringA,使用conversion c'tor 采用wchar_t*。我相信转换是使用调用线程的语言环境执行的。 @IInspectable 我同意。 嗨,我更新了代码。好的,我会检查退货。但似乎输出不正确。我是否在 Windows 上选择了主要语言西里尔文? @Treith 我不知道。我没有使用西里尔文 Windows 的经验。我仍然相信你能做的最好的事情是在 Windows API/MFC 边界使用 Unicode UTF-16,并在边界从任何编码转换为 UTF-16,然后将 UTF-16 编码的文本提供给 Windows API 和MFC 包装器方法。

以上是关于如何在 MFC 多字节应用程序中显示西里尔文字?的主要内容,如果未能解决你的问题,请参考以下文章

MFC 解决中文乱码问题

React组件中的JSX将西里尔文本显示为habra-codabra

MFC中,比如我要做一个管理系统,我得创建单文档,多文档,还是基于对话框。还是3个都可以。

MFC/VC 在多文档MDI程序中 子窗口初始最大化显示 如何去掉菜单栏右侧的最小化及向下还原按钮

React 组件中的 JSX 将西里尔文文本显示为 habra-codabra

如何在 MFC 中垂直同步两个列表控件