Что не так с моим набором символов (Win32 API) - PullRequest
1 голос
/ 14 декабря 2010

В настоящее время я изучаю Win32 с использованием этого учебного пособия , и мне тяжело с отображаемыми персонажами.

Возьмите, например, этот фрагмент кода, который добавляет меню в мое окно при создании:

    case WM_CREATE: {
            HMENU hMenu, hSubMenu;
            HICON hIcon, hIconSm;

            hMenu = CreateMenu();
            hSubMenu = CreatePopupMenu();

            AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "Exit");
            AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "File");

            hSubMenu = CreatePopupMenu();
            AppendMenu(hSubMenu, MF_STRING, ID_STUFF_GO, "&GO");
            AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&Stuff");

            SetMenu(hwnd, hMenu);

            hIcon = LoadImage(NULL, "Stuff.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);

            if (hIcon)
                SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
            else
                MessageBox(hwnd, "Could not load large icon!", "Load Error", MB_OK | MB_ICONERROR);

            hIconSm = LoadImage(NULL, "Stuff.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);

            if(hIconSm)
                SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm);
            else
                MessageBox(hwnd, "Could not load small icon!", "Load Error", MB_OK | MB_ICONERROR);
        }
        break;

Он находится внутри блока switch в моей функции WndProc, которая обрабатывает сообщения Windows, полученные из цикла сообщений.

Каждая строка, которая должна отображаться:

"Exit"
"File"
"&GO"
"&Stuff"

Невозможно прочитать во время выполнения, поскольку они отображаются в виде маленьких квадратов, как будто кодовая страница была неправильной или что-то в этом роде. Когда я запускаю учебник, все строки отображаются правильно. Я стараюсь точно придерживаться того, что говорится в учебнике, чтобы помочь мне понять все правильно, и его педагогика хороша. Так или иначе! ...

Я использую:

  1. Microsoft Visual Studio 2008 Team System;
  2. Microsoft Windows Server 2003 с использованием RDP;
  3. Локальной ОС является Windows Vista Ultimate.

Кто-нибудь знает об этом?

Ответы [ 2 ]

6 голосов
/ 14 декабря 2010

У вас проблема с кодировкой Unicode или Windows ANSI.Исторически Windows использовала расширенный ASCII, который они называли ANSI.Это привело к необходимости кодовых страниц, потому что даже 8-битный символ не обеспечивает достаточного количества кодовых точек для представления всех европейских систем письма, не говоря уже об остальном мире.Когда был разработан Win32, они остановились на Юникоде в качестве предпочтительного набора символов.(На самом деле они остановились на кодировке UTF-16LE набора символов Unicode, но эта деталь сейчас не совсем актуальна.) Однако существовало слишком много существующего кода, чтобы рассмотреть необходимость переноса с Win16 на Win32.измените кодировку символов всех строк.

Их решение было умным (некоторые утверждали, что оно было слишком умным).Каждая точка входа Win32 API, которая принимает строку, имеет две разновидности.Первый вариант принимает строки ANSI и обрабатывает преобразование в UTF-16LE внутри.Второй (и теперь предпочтительный) аромат напрямую принимает строки UTF-16LE.Они также сговорились с командой Visual C, чтобы определить wchar_t как 16-битный тип и обеспечить, чтобы строковые литералы L"" использовали отображение из текста ASCII в UTF-16LE.

Чтобы упростить портирование из существующего кода Win16, функция MessageBox и любой другой Win32 API, принимающий строки, сопоставляются макросом во время компиляции с MessageBoxA или MessageBoxW в зависимости от того, действительно лисимвол препроцессора UNICODE определен.

Это отображение не может исправить строковые литералы, поэтому они также ввели макрос для обозначения строковых литералов, которые должны быть либо узкими, либо широкими в зависимости от UNICODE, исоответствующий typedef, чтобы можно было объявить переменные для хранения указателей на них.

Таким образом, для лучшей переносимости в и из Win16 вы должны #include <tchar.h> использовать TCHAR вместо char или wchar_t, оберните все текстовые строковые литералы в макросе _T() и вызовите API-интерфейсы Win32 с именами без суффиксов, такими как MessageBox.

Однако это не идеальное решение.В тот момент, когда ваш код должен манипулировать или вычислять строку, которая будет отображаться для пользователя, вы обнаруживаете, что трудно написать код, который идеально переносим в режиме TCHAR.Существуют замены для всех стандартных строковых функций, которые манипулируют TCHAR s, но с помощью автоматического тестирования трудно проверить, правильно ли вы их использовали, чтобы код компилировался и работал правильно как с определенным UNICODE, так и без него.

Если вы пишете новый код Win32 сегодня, я бы посоветовал определить UNICODE в проекте, добавить проверку, что он действительно определен в общем заголовочном файле, и использовать строки L"" и разновидности Wвсе завернутые вызовы явно.

Наконец, все это эссе подсказывается вашим кодом, который отображает глиф отсутствующего символа (символ пустого квадратного прямоугольника - это глиф, который отображается, когда в шрифте отсутствует определенный символ).Это происходит потому, что ваши строковые литералы ASCII интерпретируются кодом Win32, как если бы они были UTF-16LE, так что строка «Выход» будет считаться двумя символами Unicode, U+7845 и U+7469, которые обаЕдиные ханские иероглифы.Если у вас не установлены шрифты Han, оба вряд ли будут присутствовать в любом шрифте в вашей системе, поэтому вместо этого вы получите глиф отсутствующего символа.

Это происходит потому, что вы смешиваете макрос-обертку со строковым литералом ASCII,У вас есть:

AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "Exit");

, но у вас должно быть одно из следующих:

AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, _T("Exit"));
AppendMenuA(hSubMenu, MF_STRING, ID_FILE_EXIT, "Exit");
AppendMenuW(hSubMenu, MF_STRING, ID_FILE_EXIT, L"Exit");

, где я предпочитаю рекомендовать последний пример.

4 голосов
/ 14 декабря 2010

Со всей странностью в отношении маленьких квадратов ваш код неверен. Это не Unicode-совместимый. Вы должны поставить перед всеми строками префикс L (как в L "string") и изменить настройки компиляции на Unicode (это заставляет функции Windows принимать кодировку UTF-16) Это собственное кодирование Windows, как текст должен был быть сделан в Windows.

Альтернативным подходом было бы использование широких API и преобразование в UTF-16 при вызове API. Это описано в http://utf8everywhere.org.

...