С++: Почему заголовок этого окна обрезается?
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, к программе, которую я добавляю.