С++: Почему заголовок этого окна обрезается?

Visual С++ 2012 RC, Win7

Китайский упрощенный

Свойства проектa > использовать многобайтовый набор символов

Когда я запускаю эту программу, заголовок окна показывает единственную букву "S" , а не целое слово "Образец".

#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));
}

Если я использую Unicode (Свойства проекта), сохраните исходный код без изменений, заголовок окна показывает "Пример", выглядит правильно.

Если я использую многобайтовый код, в исходном коде я использую WNDclass= {..., MyWindowClass} и RegisterClassA, сохраняйте CreateWindowExW без изменений, заголовок окна показывает слово "Пример", выглядит правильно.

Если я использую несколько байтов, в исходном коде я использую CreateWindowExA ( "MyWindowClass", "Sample" ), сохраняйте WNDCLASSW и RegisterClassW без изменений, заголовок окна показывает букву "S" .

Что заставляет показывать одиночный "S" , я что-то делаю неправильно?

Append

Если я сохраняю все неизменным, т.е. использую несколько байт, используйте код, показанный выше, заголовок окна показывает букву "S" .

(Если вы запустите эту программу и увидите "Образец" в заголовке окна, а не "S" , то это скорее определенная проблема в версии chs vС++ 2012 (или ОС)).

Ответ 1

Проблема в вашем коде заключается в том, что вы используете DefWindowProc вместо DefWindowProcW. Изменение, которое исправит код.

В идеале вы должны изменить настройки своего проекта, чтобы использовать Unicode, а не многобайтовый набор символов. Это упростит все, и вы можете использовать макросы типа CreateWindowEx и RegisterClassEx вместо явного использования версий Unicode/ANSI, как вы.

Как говорили другие, это несоответствие между наборами символов.

В идеале вы должны соответствовать наборам символов между всеми вашими вызовами API, которые взаимодействуют друг с другом. Поэтому, если вы используете CreateWindowExW, вы также должны использовать RegisterClassExW, DefWindowProcW, DispatchMessageW...

Ответ 2

Это очень хороший, узнал что-то новое!

Вам нужно изменить

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

to

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

Или даже лучше: придерживаться кодировки одного символа. В лучшем случае просто используйте RegisterClass, CreateWindowEx и т.д., И пусть компилятор выполнит правильную функцию Unicode или ANSI.

Ответ 3

CreateWindowExA интерпретирует строку как 8-битные символы. Второй 8 бит L "Sample" равен нулю, поскольку его первый символ равен 0x0053 - L означает использование широких символов. Таким образом, функция интерпретирует это как строку с нулевым символом с нулевым символом.

Ответ 4

Я думаю, что msdn page для RegisterClass намекает на причину неудачи здесь, в разделе замечаний упоминается, как это, если вы используйте поддержку широкого символа или ansi, затем он будет передавать внутренние текстовые параметры/сообщение в этом формате (широкий char/ansi). Вполне возможно, что то, что происходит с заголовком окна, даже если мы говорим, что оно используется CreateWindowExA, это не работает, так как внутренне SDK Windows закодировал эту строку как широкую символьную строку, а CreateWinowExA пытается выполнить вывод как если это была строка Ansi.

Короче не смешивайте методы W и A, если у вас нет веских оснований для этого, и пусть заголовки окон позаботятся об этом для вас, если вы хотите, чтобы широкая поддержка char определяла ваш макрос UNICODE.

Ответ 5

В вашем последнем случае ваш L "Sample" все еще остается Unicode, не так ли? Вы можете использовать макрос _T(), который автоматически добавляет или удаляет префикс L в зависимости от настроек Unuicode проекта.

И Unicode L "Образец", как уже сказал @Pete, является "S\0..." в ascii, поэтому печатается только один символ.

Ответ 6

Я рад, что нашел это. Я искал ответы на все вопросы, и, кажется, довольно сложно правильно найти Google и т.д. Я обнаружил похожие проблемы, о которых сообщалось для определенных программ, всегда обвиняя "некоторые подключаемые модули".

Это сходит с ума, потому что проблема с WndProc нигде не приближается к вызову CreateWindowEx и RegisterClassEx!

BTW, я использую -W суффикс явно, потому что хочу сделать одну DLL, которая работает для программ, построенных в любом случае, или преодолеть настройки, отличные от Unicode, к программе, которую я добавляю.