【问题标题】:SetWindowTextW in an ANSI projectANSI 项目中的 SetWindowTextW
【发布时间】:2012-03-13 17:14:41
【问题描述】:

我有一个 ANSI 项目。我需要将 CDialog 派生类的标题栏设置为 Unicode 文本。

BOOL CMyDialog::OnInitDialog()
{
    CDialog::OnInitDialog();

    ::SetWindowTextW(GetSafeHwnd(), PathFindFileNameW(filename));

    return TRUE;  // return TRUE unless you set the focus to a control
    // EXCEPTION: OCX Property Pages should return FALSE
}

但是,当 unicode 文本包含非 ANSI 字符时,它们会显示为问号。我得到类似“?????.doc”的东西。我对静态控件也有类似的问题,但奇怪的是,编辑框 SetWindowTextW 可以工作。

哦,这个项目是一个大型遗留项目,无法转换为 Unicode。

【问题讨论】:

标签: c++ winapi unicode mfc


【解决方案1】:

SetWindowText()/SetWindowTextA() 和 SetWindowTextW() 都是真正的 WM_SETTEXT,这是创建多字节/Ansi 窗口时需要进行代码页转换的少数消息之一。这意味着该消息没有 W 和 A 版本。

即便如此,在作为 Ansi/多字节应用程序构建的 Vista/Win7 标题栏中显示 Unicode 还是很容易的。您需要做的就是截取窗口中的 WM_SETTEXT 消息并将参数传递给 DefWindowProcW() 而不是通常的 DefWindowProcA/DefWindowProc()。这是可行的,因为在内部所有窗口实际上都是 unicode。

请注意,如果您只是将参数传递给 DefWindowProcW(),那么您必须绝对确定该参数确实指向 wchar_t 字符串。

在我自己的情况下,所有 char 字符串都假定为 UTF-8 字符。这意味着普通的 ANSI 字符串仍然像以前一样工作。当我在窗口中截获 WM_SETTEXT 消息时,我使用 MultiByteToWideChar() 将 UTF-8 字符转换为 wchar_t,然后将结果显式传递给 DefWindowProcW()。

很好的副作用是它还会在任务栏上显示 unicode 字符。

XP 存在一个问题,即即使任务栏显示标题栏也不能正确显示。

【讨论】:

    【解决方案2】:

    Tom Nelson 的答案可能是最好的,但我刚刚找到了另一个快速解决方案并想分享:

    LONG_PTR originalWndProc = GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
    SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR) DefWindowProcW);
    SetWindowTextW(hwnd, L"✈✌❦♫");
    SetWindowLongPtrW(hwnd, GWLP_WNDPROC, originalWndProc);
    

    如果没有最后一行,我们会在调试时遇到断言错误,尽管单击忽略似乎不会导致问题,并且发布模式的行为应该如此。 MFC 对我们很多人来说仍然是个谜,所以希望这段代码是正确的。

    【讨论】:

    • 我试过这个方法,MBCS模式下不显示宽文本。不过还是谢谢...
    【解决方案3】:

    如果您无法将项目转换为 Unicode,那么您将不得不接受这些限制。您的对话框是一个 ANSI 对话框。如果您愿意,可以使用SetWindowTextW,但是当系统想要绘制对话框时,它将使用 ANSI API 来获取窗口文本。它将使用 ANSI 文本绘制 GDI 函数来执行绘制。如果你想要一个 Unicode 对话框,你需要为 Unicode 编译。

    【讨论】:

      【解决方案4】:

      Microsoft 以多种形式定义了许多 API 函数。 PathFindFileName() 有三个版本(未指定,由编译器设置。如您所说的 ANSI。),PathFindFileNameW()(Unicode)和PathFindFileNameA()(ANSI)。 Here 是 MSDN 上的描述。

      我认为您需要将您的线路更改为这个(最终您也需要照顾filename):

      ::SetWindowTextW(GetSafeHwnd(), PathFindFileNameW(filename));
      

      您说您从 Unicode 类派生,因此您不能使用以下内容。这适用于纯 ANSI 项目:

      ::SetWindowTextA(GetSafeHwnd(), PathFindFileNameA(filename));
      

      或者如果所有内容都未指定:

      ::SetWindowText(GetSafeHwnd(), PathFindFileName(filename));
      

      【讨论】:

      • 其实我用的是PathFindFileNameW,但是我手动输入了示例代码,抱歉。我现在已经修好了。
      【解决方案5】:

      除了上面关于SetWindowTextA的正确答案之外,作为类似问题的一般解决方案,您可以将unicode字符串分配给将为您执行转换的CString,然后使用CString。这很可能发生在编辑框的幕后。一般来说,如果你没有在 MFC 下指定函数的 Unicode 或 ANSI 特定变体,你会得到更便携的代码,它们都可以使用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多