WangZm
WangZm

Reputation: 233

C++ : Why this window title gets truncated?

Visual C++ 2012 RC, Win7

Chinese simplified

Project Properties > use multi byte character set

When I run this program, the window's title shows a single letter "S", not a whole word "Sample".

#pragma comment(linker, "/SubSystem:Windows")

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, int) {
    WNDCLASSW wc = { 0 };

    wc.style            = CS_VREDRAW | CS_HREDRAW;
    wc.hInstance        = hInstance;
    wc.hIcon            = LoadIcon(nullptr, IDI_APPLICATION);
    wc.hCursor          = LoadCursor(nullptr, IDC_ARROW);
    wc.hbrBackground    = reinterpret_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
    wc.lpszClassName    = L"MyWindowClass";

    wc.lpfnWndProc = [](HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
        if (uMsg - WM_DESTROY)
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
        else {
            PostQuitMessage(0);
            return HRESULT();
        }
    };

    RegisterClassW(&wc);

    CreateWindowExW(0, L"MyWindowClass", L"Sample",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, SW_SHOW, CW_USEDEFAULT, 0,
        nullptr, nullptr, hInstance, nullptr);

    for (MSG msg; GetMessage(&msg, nullptr, 0, 0); DispatchMessage(&msg));
}

If I use Unicode (Project Properties), keep source code unchanged, window title shows "Sample", looks correct.

If I use multi byte, in source code I use WNDCLASS = { ..., "MyWindowClass" } and RegisterClassA, keep CreateWindowExW unchanged, window title shows word "Sample", looks correct.

If I use multi byte, in source code I use CreateWindowExA("MyWindowClass", "Sample"), keep WNDCLASSW and RegisterClassW unchanged, window title shows letter "S".

What makes it show a single "S", am I doing something wrong?

Append

If I keep all unchanged, that is, use multi byte, use code shown above, window title shows letter "S".

(If you run this program and see "Sample" on window title, rather than "S", then it's more likely a specific problem on chs version of vc++ 2012 (or OS)).

Upvotes: 21

Views: 6801

Answers (6)

Werner Henze
Werner Henze

Reputation: 16781

This is a very nice one, learned something new!

You need to change

return DefWindowProc(hWnd, uMsg, wParam, lParam);  

to

if(IsWindowUnicode(hWnd))  
  return DefWindowProcW(hWnd, uMsg, wParam, lParam);  
else  
  return DefWindowProcA(hWnd, uMsg, wParam, lParam);

Or even better: stick to one character encoding. At best just use RegisterClass, CreateWindowEx and so on and let the compiler take the right Unicode or ANSI function.

Upvotes: 9

display101
display101

Reputation: 2085

I think the msdn page for RegisterClass hints at the reason for the failure here, in the remarks section it mentions how that if you use either wide character or ansi support, then it will pass internal text paramaters/message in this format (wide char/ansi). Quite possibly that's what's happening with the window title, even though we're saying use CreateWindowExA, this doesn't work as internally the Windows SDK has encoded that string as a wide character string, and the CreateWinowExA tries to output as if it was an Ansi string.

In short don't go mixing the W and A methods, unless you've a good reason for doing so, and let windows headers take care of it for you, if you want wide char support define your UNICODE macro.

Upvotes: 1

JDługosz
JDługosz

Reputation: 5652

I'm glad I found this. I was looking all over for an answer, and it seems rather difficult to find correctly with Google etc. I did find similar problems reported for specific programs, always blaming "some plug in".

It is maddening because the problem with the WndProc is nowhere near the call to CreateWindowEx nor RegisterClassEx!

BTW, I use -W suffixes explicitly, because I want to make one DLL that works for programs built either way, or overcome the non-Unicode settings of the program I'm adding to.

Upvotes: 0

tenfour
tenfour

Reputation: 36906

The problem in your code is that you are using DefWindowProc instead of DefWindowProcW. Changing that will fix the code.

Ideally you should change your project settings to use Unicode, not multi-byte character set. This will simplify everything and you can use the macros like CreateWindowEx and RegisterClassEx instead of explicitly using the Unicode / ANSI versions as you are.

As others have said, this is a mismatch between character sets.

You should ideally match character sets between all your API calls that interact with each other. So if you use CreateWindowExW you should also use RegisterClassExW, DefWindowProcW, DispatchMessageW...

Upvotes: 39

Pete
Pete

Reputation: 1323

CreateWindowExA interprets the string as 8 bit characters. The second 8 bits of L"Sample" is zero, because its first character is 0x0053 - the L means use wide characters. So the function interprets that as a 1 character null terminated string.

Upvotes: 2

Steed
Steed

Reputation: 1300

In your last case your L"Sample" still remains Unicode, isn't it? You can use _T() macro, which automatically adds or removes L prefix depending on Unuicode setting of the project.

And Unicode L"Sample", as @Pete have already said, is "S\0..." in ascii, that's why only one symbol is printed.

Upvotes: 0

Related Questions