ANSI 项目中的 SetWindowTextW

发布于 2025-01-07 23:21:31 字数 491 浏览 1 评论 0原文

我有一个 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。

I have an ANSI project. I need to set the titlebar of a CDialog derived class to a Unicode text.

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
}

When the unicode text contains non-ANSI characters however, they display as question marks. I get something like "?????.doc". I have similar problems with static controls, but, curiously enough, with edit boxes SetWindowTextW works.

Oh, and this project is a big legacy project which can't be converted to Unicode.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

御守 2025-01-14 23:21:31

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 存在一个问题,即使任务栏显示,标题栏也无法正确显示。

SetWindowText()/SetWindowTextA() and SetWindowTextW() are all really WM_SETTEXT which is one of the few messages subject to code-page translation when you create a multibyte/Ansi window. This means there is no W and A versions of the message.

Even so, it is easy to display Unicode in a Vista/Win7 titlebar built as an Ansi/Multibyte application. All you need to do is intercept the WM_SETTEXT message in your window and pass the arguments to DefWindowProcW() instead of the usual DefWindowProcA/DefWindowProc(). This works because internally all windows are actually unicode.

Note that if you simply pass the arguments to DefWindowProcW() then you must be absolutely sure that the argument really does point to a wchar_t string.

In my own case all char strings are assumed to be UTF-8 characters. This means that normal ANSI strings still work as before. When I intercept the WM_SETTEXT message in the window I convert the UTF-8 char to wchar_t using MultiByteToWideChar() and then explictly pass the result to DefWindowProcW().

The nice side effect is that it will also display the unicode characters on the taskbar too.

XP has an issue where the titlebar is not displayed correctly even though the taskbar is.

姐不稀罕 2025-01-14 23:21:31

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

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

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

Tom Nelson's answer is probably the best, but I just found another quick solution and thought I'd share:

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

Without that last line, we were getting assertion errors when debugging, though clicking Ignore didn't seem to cause problems and Release mode behaved as it should. MFC is still a mystery to a lot of us, so hopefully this code is sound.

日暮斜阳 2025-01-14 23:21:31

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

If you can't convert the project to Unicode then you will just have to accept the limitations. Your dialog is an ANSI dialog. You can use SetWindowTextW if you like, but when the system wants to paint the dialog it is going to use the ANSI API to obtain the window text. It is going to use the ANSI text drawing GDI functions to perform the painting. If you want a Unicode dialog, you need to compile for Unicode.

慕烟庭风 2025-01-14 23:21:31

Microsoft 定义了多种 API 函数。有 PathFindFileName() 的三个版本(未指定,由编译器设置。ANSI 正如您在案例中所说的那样。),PathFindFileNameW() (Unicode) 和 PathFindFileNameA() (ANSI)。 这里是MSDN 上的描述。

我认为你需要将你的行更改为此(最终你也需要处理filename):

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

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

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

或者如果一切都未指定:

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

Microsoft defines many of the API functions in several flavors. There are three versions of PathFindFileName() (unspecified, set by the compiler. ANSI as you say in your case.), PathFindFileNameW() (Unicode) and PathFindFileNameA() (ANSI). Here is the description at MSDN.

I think you need to change your line to this (eventually you need to take care of filename too):

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

You say you derive from a Unicode class, therefore you cannot use the following. This would be for a pure ANSI project:

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

or if everything is left unspecified:

::SetWindowText(GetSafeHwnd(), PathFindFileName(filename));
放血 2025-01-14 23:21:31

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

Also, you can just call DefWindowProcW(handle, WM_SETTEXT, 0, (LPARAM)L"✈✌❦♫");

不念旧人 2025-01-14 23:21:31

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

In addition to the correct answers above relating to SetWindowTextA, as a general solution to similar problems, you can assign a unicode string to a CString which will perform the conversion for you, and then use the CString. This is most likely happening under the hood with the edit boxes. In general, if you don't specify Unicode or ANSI specific variants of the function under MFC, you get the more portable code which will work with either.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文