ANSI 项目中的SetWindowTextW

问题描述 投票:0回答:6

我有一个 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
6个回答
6
投票

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

即便如此,在构建为 Ansi/Multibyte 应用程序的 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 存在一个问题,即使任务栏显示,标题栏也无法正确显示。


4
投票

汤姆·尼尔森的答案可能是最好的,但我刚刚找到了另一个快速解决方案并认为我会分享:

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

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


2
投票

如果您无法将项目转换为 Unicode,那么您将不得不接受这些限制。您的对话框是 ANSI 对话框。如果您愿意,可以使用

SetWindowTextW
,但是当系统想要绘制对话框时,它将使用 ANSI API 来获取窗口文本。它将使用 ANSI 文本绘制 GDI 函数来执行绘制。如果您想要 Unicode 对话框,则需要针对 Unicode 进行编译。


1
投票

Microsoft 以多种方式定义了许多 API 函数。

PathFindFileName()
有三个版本(未指定,由编译器设置。按照您的情况所说的 ANSI。)、
PathFindFileNameW()
(Unicode)和
PathFindFileNameA()
(ANSI)。 这里是MSDN上的描述。

我认为你需要将你的线路更改为这个(最终你也需要照顾

filename
):

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

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

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

或者如果一切都未指定:

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

0
投票

除了上面与

SetWindowTextA
相关的正确答案之外,作为类似问题的通用解决方案,您可以将unicode字符串分配给
CString
,它将为您执行转换,然后使用CString。这很可能发生在编辑框的幕后。一般来说,如果您没有在 MFC 下指定函数的 Unicode 或 ANSI 特定变体,您将获得可与其中任何一个一起使用的更可移植的代码。


0
投票

另外,你可以直接调用 DefWindowProcW(handle, WM_SETTEXT, 0, (LPARAM)L"✈✌❦♫");

© www.soinside.com 2019 - 2024. All rights reserved.