Добавление поддержки многоязычного пользовательского интерфейса в приложение
В этом руководстве показано, как сделать одноязычное приложение готовым к международной аудитории. Это приложение находится в виде полного решения, созданного в Microsoft Visual Studio.
- Обзор
- настройка решения Hello MUI
- Шаг 0: Создание фиксированного Hello MUI
- шаг 1. Реализация базового модуля ресурсов
- шаг 2. Создание базового модуля ресурсов
- шаг 3. Создание Resource-Savvy "Hello MUI"
- шаг 4. Глобализация "Hello MUI"
- Шаг 5: Настройка "Hello MUI"
- Дополнительные соображения по MUI
- Сводка
Обзор
Начиная с Windows Vista операционная система Windows была создана с нуля, чтобы быть многоязычной платформой, с дополнительной поддержкой, которая позволяет создавать многоязычные приложения, использующие модель ресурсов Windows MUI.
В этом руководстве показана новая поддержка многоязычных приложений, охватывающих следующие аспекты:
- Использует улучшенную поддержку платформы MUI, чтобы легко включить многоязычные приложения.
- Расширяет многоязычные приложения для запуска в версиях Windows до Windows Vista.
- Касается дополнительных соображений, связанных с разработкой специализированных многоязычных приложений, таких как консольные приложения.
Эти ссылки помогают быстро обновить знания о концепциях интернационализации и Material-UI.
- Краткий обзоринтернационализации.
- концепции MUI.
- использование MUI для разработки приложений Win32.
Идея Hello MUI
Вы, вероятно, знакомы с классическим приложением Hello World, которое иллюстрирует основные понятия программирования. В этом руководстве показано, как использовать модель ресурсов MUI для обновления монолингвального приложения для создания многоязычной версии Hello MUI.
Заметка
Задачи, описанные в этом руководстве, описаны в подробных шагах из-за точности выполнения этих действий, а также необходимость объяснить подробные сведения разработчикам, у которых мало опыта работы с этими задачами.
Настройка решения Hello MUI
В этих шагах описано, как подготовиться к созданию решения Hello MUI.
Требования к платформе
В этом руководстве необходимо скомпилировать примеры кода с помощью пакета SDK для Windows 7 и Visual Studio 2008. Пакет SDK для Windows 7 будет установлен в Windows XP, Windows Vista и Windows 7, а пример решения можно создать на любой из этих версий операционной системы.
Все примеры кода в этом руководстве предназначены для выполнения в версиях x86 и x64 Windows XP, Windows Vista и Windows 7. Конкретные части, которые не будут работать в Windows XP, вызываются в случае необходимости.
Необходимые условия
Установите Visual Studio 2008.
Дополнительные сведения см. в Центре разработчиков Visual Studio.
Установите пакет SDK для Windows 7.
Его можно установить на странице пакета SDK для Windows Центра разработчиков Windows. Пакет SDK включает служебные программы для разработки приложений для версий ОС, начиная с Windows XP до последней версии.
Заметка
Если пакет не устанавливается в расположение по умолчанию или не устанавливается на системном диске, который обычно является диском C, запишите путь установки.
Настройте параметры командной строки Visual Studio.
- Откройте командное окно Visual Studio.
- Введите команду , чтобы установить путь.
- Убедитесь, что переменная пути содержит путь к папке bin пакета SDK для Windows 7: ... Пакеты SDK Майкрософт\Windows\v7.0\bin
Установите пакет расширения Microsoft NLS downlevel API.
Заметка
В контексте этого руководства этот пакет необходим только в том случае, если приложение будет работать в версиях Windows до Windows Vista. См. шаг 5: Настройка Hello MUI.
Скачайте и установите пакет, который больше не доступен в центре загрузки Майкрософт . Используйте API глобализации ICU в обновлении Windows 10 от мая 2019 г. и более поздних версий.
Как и в пакете SDK для Windows, если пакет не устанавливается в расположение по умолчанию или если вы не устанавливаете на системном диске, который обычно является диском C, запишите путь установки.
Если ваша платформа разработки — Windows XP или Windows Server 2003, убедитесь, что Nlsdl.dll установлен и зарегистрирован правильно.
- Перейдите к папке Redist в расположении пути установки.
- Запустите соответствующую распространяемую библиотеку Nlsdl.*.exe, например nlsdl.x86.exe. Этот шаг устанавливает и регистрирует Nlsdl.dll.
Заметка
Если вы разрабатываете приложение, использующее MUI и которое должно работать в версиях Windows до Windows Vista, Nlsdl.dll должны присутствовать на целевой платформе Windows. В большинстве случаев это означает, что приложению необходимо включать и устанавливать комплект установки Nlsdl для распространения (а не просто копировать Nlsdl.dll как отдельный компонент).
Шаг 0: Создание жестко прописанного Hello MUI
Это руководство начинается с одноязычной версии приложения Hello MUI. Приложение предполагает использование языка программирования C++, широких символьных строк и функции MessageBoxW для выходных данных.
Начните с создания начального приложения GuiStep_0, а также решения HelloMUI, содержащего все приложения в этом руководстве.
В Visual Studio 2008 создайте проект. Используйте следующие параметры и значения:
- Тип проекта: в разделе Visual C++ выберите Win32, а затем в разделе установленных шаблонов Visual Studio выберите Проект Win32.
- Имя: GuiStep_0.
- Расположение: ProjectRootDirectory (дальнейшие шаги ссылаются на этот каталог).
- Имя решения: HelloMUI.
- Выберите "Создать каталог для решения".
- В мастере приложений Win32 выберите тип приложения по умолчанию: приложение Windows.
Настройте модель потоков проекта:
В обозревателе решений щелкните правой кнопкой мыши проект GuiStep_0 и выберите пункт "Свойства".
В диалоговом окне "Страницы свойств проекта":
- В раскрывающемся списке в верхнем левом углу задайте для параметра Configuration значение "Все конфигурации".
- В разделе "Свойства конфигурации" разверните C/C++, выберите "Создание кода" и задайте библиотеку среды выполнения: многопоточная отладка (/MTd).
Замените содержимое GuiStep_0.cpp следующим кодом:
// GuiStep_0.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "GuiStep_0.h" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hInstance); UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); UNREFERENCED_PARAMETER(nCmdShow); MessageBoxW(NULL,L"Hello MUI",L"HelloMUI!",MB_OK | MB_ICONINFORMATION); return 0; }
Создайте и запустите приложение.
Простой исходный код, приведенный выше, использует упрощенный подход проектирования, заключающийся в «хардкодинге» или встраивании всех выходных данных, которые увидит пользователь, в данном случае текста "Hello MUI". Этот выбор ограничивает полезность приложения для пользователей, которые не распознают английское слово "Hello." Поскольку MUI является акронимом на английском языке, в этом руководстве предполагается, что строка остается "MUI" для всех языков.
Шаг 1. Реализация базового модуля ресурсов
Microsoft Win32 уже давно предоставляет возможность разработчикам приложений отделять данные ресурса пользовательского интерфейса от исходного кода приложения. Это разделение происходит в виде модели ресурсов Win32, в которой строки, растровые изображения, значки, сообщения и другие элементы обычно отображаются пользователю в отдельный раздел исполняемого файла, разделенный от исполняемого кода.
Чтобы проиллюстрировать это разделение между исполняемым кодом и упаковкой данных ресурсов, в этом шаге учебник помещает ранее жестко закодированную строку Hello (ресурс "en-US" в раздел ресурсов модуля DLL в проекте HelloModule_en_us.
Эта DLL Win32 также может содержать исполняемую функциональность библиотечного типа (как и любая другая DLL). Но чтобы помочь сосредоточиться на аспектах, связанных с ресурсами Win32, мы оставим код DLL во время выполнения в dllmain.cpp. В последующих разделах этого руководства используются данные ресурсов HelloModule, созданные здесь, а также соответствующий код среды выполнения.
Чтобы создать модуль ресурсов Win32, начните с создания библиотеки DLL с заглушенной функцией dllmain.
Добавьте новый проект в решение HelloMUI:
- В меню "Файл" выберите "Добавить" и "Создать проект".
- Тип проекта: Win32 Project.
- Имя: HelloModule_en_us.
- Расположение: ProjectRootDirectory\HelloMUI.
- В мастере приложений Win32 выберите тип приложения: DLL.
Настройте модель потоков этого проекта:
В обозревателе решений щелкните правой кнопкой мыши проект HelloModule_en_us и выберите "Свойства".
В диалоговом окне страниц свойств проекта:
- В раскрывающемся списке в верхнем левом углу задайте для параметра Configuration значение "Все конфигурации".
- В разделе "Свойства конфигурации" разверните C/C++, выберите "Создание кода" и задайте библиотеку среды выполнения: многопоточная отладка (/MTd).
Проверьте dllmain.cpp. (Вы можете добавить макросы UNREFERENCED_PARAMETER в созданный код, как мы здесь, чтобы включить компиляцию на уровне предупреждения 4.)
// dllmain.cpp : Defines the entry point for the DLL application. #include "stdafx.h" BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { UNREFERENCED_PARAMETER(hModule); UNREFERENCED_PARAMETER(lpReserved); switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
Добавьте в проект файл определения ресурса HelloModule.rc:
В HelloModule_en_us проекта щелкните правой кнопкой мыши папку "Файлы ресурсов" и выберите "Добавить", а затем выберите "Создать элемент".
В диалоговом окне "Добавление нового элемента" выберите следующее:
- Категории: в разделе Visual C++ выберите ресурс, а затем в разделе "Установленные шаблоны Visual Studio" выберите файл ресурсов (RC).
- Имя: HelloModule.
- Расположение: примите значение по умолчанию.
- Нажмите кнопку "Добавить".
Укажите, что новый файл HelloModule.rc должен быть сохранен в юникоде:
- В обозревателе решений щелкните правой кнопкой мыши HelloModule.rc и выберите "Просмотреть код".
- Если появится сообщение, указывающее, что файл уже открыт, и спрашивает, нужно ли закрыть его, нажмите кнопку "Да".
- Когда файл отображается как текст, выберите пункт меню Файл, затем Дополнительные параметры сохранения.
- В разделе "Кодировка" укажите Юникод — Codepage 1200.
- Нажмите кнопку "ОК".
- Сохраните и закройте HelloModule.rc.
Добавьте таблицу строк, содержащую строку "Привет".
В представлении ресурсов щелкните правой кнопкой мыши HelloModule.rc и выберите "Добавить ресурс".
Выберите таблицу строк.
Нажмите кнопку "Создать".
Добавьте строку в таблицу строк:
- Идентификатор: HELLO_MUI_STR_0.
- Значение: 0.
- Подпись: Привет.
Если вы просматриваете HelloModule.rc как текст сейчас, вы увидите различные фрагменты исходного кода для конкретного ресурса. Одним из наиболее интересных является раздел, описывающий строку Hello:
///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE BEGIN HELLO_MUI_STR_0 "Hello" END
Эта строка Hello — это ресурс, который должен быть локализован (то есть переведен) на каждый язык, который приложение надеется поддерживать. Например, проект HelloModule_ta_in (который будет создан на следующем шаге) будет содержать собственную локализованную версию HelloModule.rc для "ta-IN":
///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE BEGIN HELLO_MUI_STR_0 "வணக்கம்" END
Создайте проект HelloModule_en_us, чтобы убедиться, что нет ошибок.
Создайте еще шесть проектов в решении HelloMUI (или столько, сколько хотите), чтобы создать еще шесть библиотек DLL ресурсов для дополнительных языков. Используйте значения в этой таблице:
Имя проекта Имя RC-файла Идентификатор строки Строковое значение Заголовок строки HelloModule_de_de HelloModule HELLO_MUI_STR_0 0 Привет HelloModule_es_es HelloModule HELLO_MUI_STR_0 0 Привет HelloModule_fr_fr HelloModule HELLO_MUI_STR_0 0 Bonjour HelloModule_hi_in HelloModule HELLO_MUI_STR_0 0 привет HelloModule_ru_ru HelloModule HELLO_MUI_STR_0 0 Здравствуйте HelloModule_ta_in HelloModule HELLO_MUI_STR_0 0 வணக்கம்
Дополнительные сведения о структуре и синтаксисе RC-файла см. в разделе о файлах ресурсов.
Шаг 2. Создание базового модуля ресурсов
Используя предыдущие модели ресурсов, создание любого из семи проектов HelloModule приведёт к семи отдельным библиотекам DLL. Каждая библиотека DLL содержит раздел ресурса с одной строкой, локализованной на соответствующем языке. Несмотря на то, что она подходит для исторической модели ресурсов Win32, эта конструкция не использует преимущества muI.
В пакете SDK Для Windows Vista и более поздних версий MUI позволяет разделить исполняемые файлы на исходный код и локализуемые модули содержимого. С помощью дополнительной настройки, описанной далее на шаге 5, приложения могут быть включены для поддержки нескольких лингвистов для запуска в версиях до Windows Vista.
Основными механизмами, доступными для разделения ресурсов из исполняемого кода, начиная с Windows Vista, являются:
- Использование rc.exe (компилятор RC) с определенными коммутаторами или
- Использование средства разделения стиля после сборки под названием muirct.exe.
См. Утилиты ресурсов для получения дополнительной информации.
Для простоты в этом руководстве используется muirct.exe для разделения исполняемого файла Hello MUI.
Разделение различных языковых ресурсов: обзор
Процесс из нескольких частей включает разделение DLL на один исполняемый файл HelloModule.dll, а также HelloModule.dll.mui для каждого из семи поддерживаемых языков в этом руководстве. В этом обзоре описаны необходимые действия; В следующем разделе представлен файл команды, выполняющий эти действия.
Во-первых, разделите модуль HelloModule.dll, предназначенный только для английского, с помощью команды:
mkdir .\en-US
muirct.exe -q DoReverseMuiLoc.rcconfig -v 2 -x 0x0409 -g 0x0407 .\HelloModule_en_us.dll .\HelloModule.dll .\en-US\HelloModule.dll.mui
В приведенной выше командной строке используется файл конфигурации DoReverseMuiLoc.rcconfig. Этот тип файла конфигурации обычно используется muirct.exe для разделения ресурсов между библиотекой DLL, независимой от языка (LN) и зависимыми от языка файлами .MUI. В этом случае XML-файл DoReverseMuiLoc.rcconfig (указанный в следующем разделе) указывает на множество типов ресурсов, но все они попадают в категорию "localizedResources" или .mui-файла, а ресурсы в нейтральной категории языка отсутствуют. Дополнительные сведения о подготовке файла конфигурации ресурсов см. в разделе .
Помимо создания HelloModule.dll.mui-файла, содержащего английскую строку Hello, muirct.exe также внедряет ресурс MUI в модуль HelloModule.dll во время разделения. Для правильной загрузки во время выполнения соответствующих ресурсов из языковых модулей HelloModule.dll.mui каждый файл mui должен иметь свои контрольные суммы, чтобы соответствовать контрольным суммам в базовом модуле LN, нейтральном на языке. Это делается командой, например:
muirct.exe -c HelloModule.dll -e en-US\HelloModule.dll.mui
Аналогичным образом вызывается muirct.exe для создания HelloModule.dll.mui-файла для каждого из других языков. Однако в таких случаях языконезависимая библиотека DLL удаляется, так как потребуется только первая созданная DLL. Команды, обрабатывающие испанские и французские ресурсы, выглядят следующим образом:
mkdir .\es-ES
muirct.exe -q DoReverseMuiLoc.rcconfig -v 2 -x 0x0C0A -g 0x0407 .\HelloModule_es_es.dll .\HelloModule_discard.dll .\es-ES\HelloModule.dll.mui
muirct.exe -c HelloModule.dll -e es-ES\HelloModule.dll.mui
mkdir .\fr-FR
muirct.exe -q DoReverseMuiLoc.rcconfig -v 2 -x 0x040C -g 0x0407 .\HelloModule_fr_fr.dll .\HelloModule_discard.dll .\fr-FR\HelloModule.dll.mui
muirct.exe -c HelloModule.dll -e fr-FR\HelloModule.dll.mui
Одной из самых важных вещей, на которые стоит обратить внимание в командных строках muirct.exe выше, является то, что флаг -x используется для указания идентификатора целевого языка. Значение, предоставленное muirct.exe, отличается для каждого модуля HelloModule.dll языка. Это значение языка является центральным и используется muirct.exe для корректной маркировки .mui файла во время разделения. Неправильное значение приводит к сбоям загрузки ресурсов для конкретного файла MUI во время выполнения. Дополнительные сведения о сопоставлении имени языка с LCID см. в Константы идентификаторов языка и Строки названий языков.
Каждый разбитый .mui файл в конечном итоге помещается в каталог, соответствующий названию его языка, непосредственно под каталогом, в котором будет находиться нейтральный к языку HelloModule.dll. Дополнительные сведения о размещении файлов .MUI см. в развертывании приложений.
Разделение различных языковых ресурсов: создание файлов
В этом руководстве вы создаете командный файл, содержащий команды для разделения разных библиотек DLL, и запускаете его вручную. Обратите внимание, что в фактической работе по разработке можно уменьшить вероятность ошибок сборки, включив эти команды в качестве событий предварительной сборки или после сборки в решении HelloMUI, но это выходит за рамки этого руководства.
Создайте файлы для отладочной сборки.
Создайте файл команды DoReverseMuiLoc.cmd, содержащий следующие команды:
mkdir .\en-US muirct.exe -q DoReverseMuiLoc.rcconfig -v 2 -x 0x0409 -g 0x0407 .\HelloModule_en_us.dll .\HelloModule.dll .\en-US\HelloModule.dll.mui muirct.exe -c HelloModule.dll -e en-US\HelloModule.dll.mui mkdir .\de-DE muirct.exe -q DoReverseMuiLoc.rcconfig -v 2 -x 0x0407 -g 0x0407 .\HelloModule_de_de.dll .\HelloModule_discard.dll .\de-DE\HelloModule.dll.mui muirct.exe -c HelloModule.dll -e de-DE\HelloModule.dll.mui mkdir .\es-ES muirct.exe -q DoReverseMuiLoc.rcconfig -v 2 -x 0x0C0A -g 0x0407 .\HelloModule_es_es.dll .\HelloModule_discard.dll .\es-ES\HelloModule.dll.mui muirct.exe -c HelloModule.dll -e es-ES\HelloModule.dll.mui mkdir .\fr-FR muirct.exe -q DoReverseMuiLoc.rcconfig -v 2 -x 0x040C -g 0x0407 .\HelloModule_fr_fr.dll .\HelloModule_discard.dll .\fr-FR\HelloModule.dll.mui muirct.exe -c HelloModule.dll -e fr-FR\HelloModule.dll.mui mkdir .\hi-IN muirct.exe -q DoReverseMuiLoc.rcconfig -v 2 -x 0x0439 -g 0x0407 .\HelloModule_hi_in.dll .\HelloModule_discard.dll .\hi-IN\HelloModule.dll.mui muirct.exe -c HelloModule.dll -e hi-IN\HelloModule.dll.mui mkdir .\ru-RU muirct.exe -q DoReverseMuiLoc.rcconfig -v 2 -x 0x0419 -g 0x0407 .\HelloModule_ru_ru.dll .\HelloModule_discard.dll .\ru-RU\HelloModule.dll.mui muirct.exe -c HelloModule.dll -e ru-RU\HelloModule.dll.mui mkdir .\ta-IN muirct.exe -q DoReverseMuiLoc.rcconfig -v 2 -x 0x0449 -g 0x0407 .\HelloModule_ta_in.dll .\HelloModule_discard.dll .\ta-IN\HelloModule.dll.mui muirct.exe -c HelloModule.dll -e ta-IN\HelloModule.dll.mui pause
Создайте XML-файл DoReverseMuiLoc.rcconfig со следующими строками:
<?xml version="1.0" encoding="utf-8"?> <localization> <resources> <win32Resources fileType="Application"> <neutralResources> </neutralResources> <localizedResources> <resourceType typeNameId="#1"/> <resourceType typeNameId="#10"/> <resourceType typeNameId="#1024"/> <resourceType typeNameId="#11"/> <resourceType typeNameId="#12"/> <resourceType typeNameId="#13"/> <resourceType typeNameId="#14"/> <resourceType typeNameId="#15"/> <resourceType typeNameId="#16"/> <resourceType typeNameId="#17"/> <resourceType typeNameId="#18"/> <resourceType typeNameId="#19"/> <resourceType typeNameId="#2"/> <resourceType typeNameId="#20"/> <resourceType typeNameId="#2110"/> <resourceType typeNameId="#23"/> <resourceType typeNameId="#240"/> <resourceType typeNameId="#3"/> <resourceType typeNameId="#4"/> <resourceType typeNameId="#5"/> <resourceType typeNameId="#6"/> <resourceType typeNameId="#7"/> <resourceType typeNameId="#8"/> <resourceType typeNameId="#9"/> <resourceType typeNameId="HTML"/> <resourceType typeNameId="MOFDATA"/> </localizedResources> </win32Resources> </resources> </localization>
Скопируйте DoReverseMuiLoc.cmd и DoReverseMuiLoc.rcconfig в ProjectRootDirectory\HelloMUI\Debug.
Откройте командную строку Visual Studio 2008 и перейдите в каталог отладки.
Запустите DoReverseMuiLoc.cmd.
При создании сборки релиз скопируйте те же файлы DoReverseMuiLoc.cmd и DoReverseMuiLoc.rcconfig в каталог Релиз и запустите командный файл там.
Шаг 3: Создание Resource-Savvy "Привет, MUI"
Основываясь на исходном жестко закодированном примере GuiStep_0.exe выше, вы можете расширить доступ приложения к нескольким пользователям языка, выбрав включить модель ресурсов Win32. Новый код времени выполнения, представленный на этом шаге, включает загрузку модуля (LoadLibraryEx) и логику извлечения строк (LoadString).
Добавьте новый проект в решение HelloMUI, выбрав из меню пункты Файл, Добавить, Новый Проект, и примените следующие параметры и значения:
- Тип проекта: Win32 Project.
- Имя: GuiStep_1.
- Расположение: примите значение по умолчанию.
- В мастере приложений Win32 выберите тип приложения по умолчанию: приложение Windows.
Установите этот проект для запуска из Visual Studio и настройте ее модель потоков:
В обозревателе решений щелкните правой кнопкой мыши проект GuiStep_1 и выберите "Задать в качестве проекта запуска".
Щелкните его правой кнопкой мыши и выберите пункт "Свойства".
В диалоговом окне страниц свойств проекта:
- В раскрывающемся списке в верхнем левом углу задайте для параметра Configuration значение "Все конфигурации".
- В разделе "Свойства конфигурации" разверните C/C++, выберите "Создание кода" и задайте библиотеку среды выполнения: многопоточная отладка (/MTd).
Замените содержимое GuiStep_1.cpp следующим кодом:
// GuiStep_1.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "GuiStep_1.h" #include "..\HelloModule_en_us\resource.h" #define SUFFICIENTLY_LARGE_STRING_BUFFER (MAX_PATH*2) #define SUFFICIENTLY_LARGE_ERROR_BUFFER (1024*2) #define HELLO_MODULE_CONTRIVED_FILE_PATH (L"HelloModule.dll") int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hInstance); UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); UNREFERENCED_PARAMETER(nCmdShow); // The following code presents a hypothetical, yet common use pattern of MUI technology WCHAR displayBuffer[SUFFICIENTLY_LARGE_ERROR_BUFFER]; // 1. Basic application obtains access to the proper resource container // for standard Win32 resource loading this is normally a PE module - use LoadLibraryEx // LoadLibraryEx is the preferred alternative for resource modules as used below because it // provides increased security and performance over that of LoadLibrary HMODULE resContainer = LoadLibraryExW(HELLO_MODULE_CONTRIVED_FILE_PATH,NULL,LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE); if(!resContainer) { swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"FAILURE: Unable to load the resource container module, last error = %d.",GetLastError()); MessageBoxW(NULL,displayBuffer,L"HelloMUI ERROR!",MB_OK | MB_ICONERROR); return 1; // exit } // 2. Application parses the resource container to find the appropriate item WCHAR szHello[SUFFICIENTLY_LARGE_STRING_BUFFER]; if(LoadStringW(resContainer,HELLO_MUI_STR_0,szHello,SUFFICIENTLY_LARGE_STRING_BUFFER) == 0) { swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"FAILURE: Unable to load the resource string, last error = %d.",GetLastError()); MessageBoxW(NULL,displayBuffer,L"HelloMUI ERROR!",MB_OK | MB_ICONERROR); FreeLibrary(resContainer); return 1; // exit } // 3. Application presents the discovered resource to the user via UI swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"%s MUI",szHello); MessageBoxW(NULL,displayBuffer,L"HelloMUI",MB_OK | MB_ICONINFORMATION); // 4. Application cleans up memory associated with the resource container after this item is no longer needed. if(!FreeLibrary(resContainer)) { swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"FAILURE: Unable to unload the resource container, last error = %d.",GetLastError()); MessageBoxW(NULL,displayBuffer,L"HelloMUI ERROR!",MB_OK | MB_ICONERROR); return 1; // exit } return 0; }
Создайте и запустите приложение. Выходные данные будут отображаться на языке, заданном в настоящее время как язык отображения компьютера (если он является одним из семи созданных языков).
Шаг 4. Глобализация "Hello MUI"
Хотя предыдущий пример может отображать выходные данные на разных языках, он имеет недостатки в ряде аспектов. Возможно, наиболее заметным является то, что приложение доступно только в небольшом подмножестве языков по сравнению с самой операционной системой Windows. Например, если приложение GuiStep_1 из предыдущего шага было установлено в японской сборке Windows, скорее всего, произойдет сбой расположения ресурсов.
Для решения этой ситуации у вас есть два основных варианта:
- Убедитесь, что включены ресурсы на заранее установленном языке по умолчанию.
- Предоставьте пользователю возможность настроить свои языковые настройки из подмножества языков, специально поддерживаемых приложением.
Из этих вариантов, предоставляющий конечный резервный язык, настоятельно рекомендуется и реализуется в этом руководстве путем передачи флага -g в muirct.exe, как показано выше. Этот флаг сообщает muirct.exe сделать определенный язык (de-DE / 0x0407) конечным резервным языком, связанным с неязыковым модулем dll (HelloModule.dll). Во время выполнения этот параметр используется в качестве последнего средства для создания текста для отображения пользователю. В случае, если конечный резервный язык не найден, и соответствующий ресурс недоступен в нейтральном языке двоичном файле, загрузка ресурса завершается сбоем. Поэтому следует тщательно определить сценарии, с которыми может столкнуться ваше приложение, и запланировать конечный резервный язык соответствующим образом.
Другой вариант, позволяющий настраивать языковые предпочтения и загружать ресурсы на основе этой определяемой пользователем иерархии, может значительно повысить удовлетворенность клиентов. К сожалению, это также усложняет функциональные возможности, необходимые в приложении.
На этом шаге руководства используется упрощенный механизм текстового файла для настройки пользовательской конфигурации языка. Текстовый файл анализируется во время выполнения приложением, а синтаксический и проверенный список языков используется при создании настраиваемого резервного списка. После установки настраиваемого резервного списка API Windows загрузит ресурсы в соответствии с приоритетом языка, заданным в этом списке. Оставшаяся часть кода аналогична приведенному на предыдущем шаге.
Добавьте новый проект в решение HelloMUI, выбрав в меню пункты: Файл, Добавить, Новый проект, и задайте следующие параметры и значения:
- Тип проекта: Win32 Project.
- Имя: GuiStep_2.
- Расположение: примите значение по умолчанию.
- В мастере приложений Win32 выберите тип приложения по умолчанию: приложение Windows.
Установите этот проект для запуска из Visual Studio и настройте ее модель потоков:
В обозревателе решений щелкните правой кнопкой мыши проект GuiStep_2 и выберите "Задать в качестве проекта запуска".
Щелкните его правой кнопкой мыши и выберите пункт "Свойства".
В диалоговом окне страниц свойств проекта:
- В раскрывающемся списке в верхнем левом углу задайте для параметра Configuration значение "Все конфигурации".
- В разделе "Свойства конфигурации" разверните C/C++, выберите "Создание кода" и задайте библиотеку среды выполнения: многопоточная отладка (/MTd).
Замените содержимое GuiStep_2.cpp следующим кодом:
// GuiStep_2.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "GuiStep_2.h" #include <strsafe.h> #include "..\HelloModule_en_us\resource.h" #define SUFFICIENTLY_LARGE_STRING_BUFFER (MAX_PATH*2) #define USER_CONFIGURATION_STRING_BUFFER (((LOCALE_NAME_MAX_LENGTH+1)*5)+1) #define SUFFICIENTLY_LARGE_ERROR_BUFFER (1024*2) #define HELLO_MODULE_CONTRIVED_FILE_PATH (L"HelloModule.dll") BOOL GetMyUserDefinedLanguages(WCHAR * langStr, DWORD langStrSize); BOOL ConvertMyLangStrToMultiLangStr(WCHAR * langStr, WCHAR * langMultiStr, DWORD langMultiStrSize); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hInstance); UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); UNREFERENCED_PARAMETER(nCmdShow); // The following code presents a hypothetical, yet common use pattern of MUI technology WCHAR displayBuffer[SUFFICIENTLY_LARGE_ERROR_BUFFER]; // 1. Application starts by applying any user defined language preferences // (language setting is potentially optional for an application that wishes to strictly use OS system language fallback) // 1a. Application looks in pre-defined location for user preferences (registry, file, web, etc.) WCHAR userLanguagesString[USER_CONFIGURATION_STRING_BUFFER*2]; if(!GetMyUserDefinedLanguages(userLanguagesString,USER_CONFIGURATION_STRING_BUFFER*2)) { swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"FAILURE: Unable to find the user defined language configuration, last error = %d.",GetLastError()); MessageBoxW(NULL,displayBuffer,L"HelloMUI ERROR!",MB_OK | MB_ICONERROR); return 1; // exit } // 1b. Application converts the user defined 'readable' languages to the proper multi-string 'less readable' language name format WCHAR userLanguagesMultiString[USER_CONFIGURATION_STRING_BUFFER]; if(!ConvertMyLangStrToMultiLangStr(userLanguagesString,userLanguagesMultiString,USER_CONFIGURATION_STRING_BUFFER)) { swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"FAILURE: Unable to convert the user defined language configuration to multi-string, last error = %d.",GetLastError()); MessageBoxW(NULL,displayBuffer,L"HelloMUI ERROR!",MB_OK | MB_ICONERROR); return 1; // exit } // 1c. Application now sets the appropriate fallback list DWORD langCount = 0; // next commented out line of code could be used on Windows 7 and later // using SetProcessPreferredUILanguages is recomended for new applications (esp. multi-threaded applications) // if(!SetProcessPreferredUILanguages(MUI_LANGUAGE_NAME,userLanguagesMultiString,&langCount) || langCount == 0) // the following line of code is supported on Windows Vista and later if(!SetThreadPreferredUILanguages(MUI_LANGUAGE_NAME,userLanguagesMultiString,&langCount) || langCount == 0) { swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"FAILURE: Unable to set the user defined languages, last error = %d.",GetLastError()); MessageBoxW(NULL,displayBuffer,L"HelloMUI ERROR!",MB_OK | MB_ICONERROR); return 1; // exit } // NOTES on step #1: // an application developer that makes the assumption the fallback list provided by the // system / OS is entirely sufficient may or may not be making a good assumption based // mostly on: // A. your choice of languages installed with your application // B. the languages on the OS at application install time // C. the OS users propensity to install/uninstall language packs // D. the OS users propensity to change laguage settings // 2. Application obtains access to the proper resource container // for standard Win32 resource loading this is normally a PE module - use LoadLibraryEx // LoadLibraryEx is the preferred alternative for resource modules as used below because it // provides increased security and performance over that of LoadLibrary HMODULE resContainer = LoadLibraryExW(HELLO_MODULE_CONTRIVED_FILE_PATH,NULL,LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE); if(!resContainer) { swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"FAILURE: Unable to load the resource container module, last error = %d.",GetLastError()); MessageBoxW(NULL,displayBuffer,L"HelloMUI ERROR!",MB_OK | MB_ICONERROR); return 1; // exit } // 3. Application parses the resource container to find the appropriate item WCHAR szHello[SUFFICIENTLY_LARGE_STRING_BUFFER]; if(LoadStringW(resContainer,HELLO_MUI_STR_0,szHello,SUFFICIENTLY_LARGE_STRING_BUFFER) == 0) { swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"FAILURE: Unable to load the resource string, last error = %d.",GetLastError()); MessageBoxW(NULL,displayBuffer,L"HelloMUI ERROR!",MB_OK | MB_ICONERROR); FreeLibrary(resContainer); return 1; // exit } // 4. Application presents the discovered resource to the user via UI swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"%s MUI",szHello); MessageBoxW(NULL,displayBuffer,L"HelloMUI",MB_OK | MB_ICONINFORMATION); // 5. Application cleans up memory associated with the resource container after this item is no longer needed. if(!FreeLibrary(resContainer)) { swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"FAILURE: Unable to unload the resource container, last error = %d.",GetLastError()); MessageBoxW(NULL,displayBuffer,L"HelloMUI ERROR!",MB_OK | MB_ICONERROR); return 1; // exit } return 0; } BOOL GetMyUserDefinedLanguages(WCHAR * langStr, DWORD langStrSize) { BOOL rtnVal = FALSE; // very simple implementation - assumes that first 'langStrSize' characters of the // L".\\langs.txt" file comprises a string of one or more languages HANDLE langConfigFileHandle = CreateFileW(L".\\langs.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(langConfigFileHandle != INVALID_HANDLE_VALUE) { // clear out the input variables DWORD bytesActuallyRead = 0; if(ReadFile(langConfigFileHandle,langStr,langStrSize*sizeof(WCHAR),&bytesActuallyRead,NULL) && bytesActuallyRead > 0) { rtnVal = TRUE; DWORD nullIndex = (bytesActuallyRead/sizeof(WCHAR) < langStrSize) ? bytesActuallyRead/sizeof(WCHAR) : langStrSize; langStr[nullIndex] = L'\0'; } CloseHandle(langConfigFileHandle); } return rtnVal; } BOOL ConvertMyLangStrToMultiLangStr(WCHAR * langStr, WCHAR * langMultiStr, DWORD langMultiStrSize) { BOOL rtnVal = FALSE; size_t strLen = 0; rtnVal = SUCCEEDED(StringCchLengthW(langStr,USER_CONFIGURATION_STRING_BUFFER*2,&strLen)); if(rtnVal && strLen > 0 && langMultiStr && langMultiStrSize > 0) { WCHAR * langMultiStrPtr = langMultiStr; WCHAR * last = langStr + (langStr[0] == 0xFEFF ? 1 : 0); WCHAR * context = last; WCHAR * next = wcstok_s(last,L",; :",&context); while(next && rtnVal) { // make sure you validate the user input if(SUCCEEDED(StringCchLengthW(last,LOCALE_NAME_MAX_LENGTH,&strLen)) && IsValidLocaleName(next)) { langMultiStrPtr[0] = L'\0'; rtnVal &= SUCCEEDED(StringCchCatW(langMultiStrPtr,(langMultiStrSize - (langMultiStrPtr - langMultiStr)),next)); langMultiStrPtr += strLen + 1; } next = wcstok_s(NULL,L",; :",&context); if(next) last = next; } if(rtnVal && (langMultiStrSize - (langMultiStrPtr - langMultiStr))) // make sure there is a double null term for the multi-string { langMultiStrPtr[0] = L'\0'; } else // fail and guard anyone whom might use the multi-string { langMultiStr[0] = L'\0'; langMultiStr[1] = L'\0'; } } return rtnVal; }
Создайте текстовый файл Юникода langs.txt со следующей строкой:
hi-IN ta-IN ru-RU fr-FR es-ES en-US
Заметка
Не забудьте сохранить файл в юникоде.
Скопируйте langs.txt в каталог, из которого будет выполняться программа:
- При запуске из Visual Studio скопируйте его в ProjectRootDirectory\HelloMUI\GuiStep_2.
- При запуске из проводника Windows скопируйте его в тот же каталог, что и GuiStep_2.exe.
Соберите и запустите проект. Попробуйте изменить langs.txt, чтобы различные языки отображались в передней части списка.
Шаг 5. Настройка "Hello MUI"
Ряд функций времени выполнения, упомянутых до сих пор в этом руководстве, доступны только в Windows Vista и более поздних версиях. Возможно, вы хотите повторно использовать усилия, вложенные в локализацию и разделение ресурсов, сделав приложение работой над версиями операционной системы Windows нижнего уровня, например Windows XP. Этот процесс включает настройку предыдущего примера в двух ключевых областях:
Функции загрузки ресурсов до Windows Vista (например, LoadString, LoadIcon, LoadBitmap, FormatMessageи другие) не поддерживают MUI. Приложения, которые поставляется с разделенными ресурсами (LN и MUI-файлы), должны загружать модули ресурсов с помощью одной из этих двух функций:
- Если приложение должно запускаться только на Windows Vista и более поздних версиях, оно должно загружать модули ресурсов с LoadLibraryEx.
- Если приложение должно выполняться в версиях до Windows Vista, а также Windows Vista или более поздней версии, оно должно использовать LoadMUILibrary, которая является определенной функцией нижнего уровня, предоставляемой в пакете SDK для Windows 7.
Поддержка управления языками и порядка резервирования языков, предлагаемая в версиях операционной системы Windows до Windows Vista, значительно отличается от поддержки в Windows Vista и более поздних версиях. По этой причине приложения, которые разрешают обратную передачу на языке, настроенного пользователем, должны настроить свои методики управления языком:
- Если приложение должно выполняться только в Windows Vista и более поздних версиях, задайте список языков с помощью SetThreadPreferredUILanguages.
- Если приложение должно выполняться во всех версиях Windows, необходимо создать код, который будет выполняться на платформах нижнего уровня, чтобы выполнить итерацию по пользовательскому списку языков и пробе для требуемого модуля ресурсов. Это можно увидеть в разделах 1c и 2 кода, предоставленных далее на этом шаге.
Создайте проект, который может использовать локализованные модули ресурсов в любой версии Windows:
Добавьте новый проект в решение HelloMUI, используя команды меню "Файл", "Добавить" и "Новый проект" со следующими параметрами и значениями:
- Тип проекта: Win32 Project.
- Имя: GuiStep_3.
- Расположение: примите значение по умолчанию.
- В мастере приложений Win32 выберите тип приложения по умолчанию: приложение Windows.
Установите этот проект для запуска из Visual Studio и настройте ее модель потоков. Кроме того, настройте его, чтобы добавить необходимые заголовки и библиотеки.
Заметка
Пути, используемые в этом руководстве, предполагают, что Windows 7 SDK и пакет API нижнего уровня Microsoft NLS установлены в каталоги по умолчанию. Если это не так, измените пути соответствующим образом.
В обозревателе решений щелкните правой кнопкой мыши проект GuiStep_3 и выберите "Задать в качестве проекта запуска".
Щелкните его правой кнопкой мыши и выберите пункт "Свойства".
В диалоговом окне страниц свойств проекта:
В раскрывающемся списке в верхнем левом углу задайте для параметра Configuration значение "Все конфигурации".
В разделе "Свойства конфигурации" разверните C/C++, выберите "Создание кода" и задайте библиотеку среды выполнения: многопоточная отладка (/MTd).
Выберите "Общие" и добавьте в "Дополнительные каталоги включения":
- "C:\Microsoft NLS Downlevel API\Include".
Выберите язык и установите опцию «Обрабатывать wchar_t как встроенный тип»: Нет (/Zc:wchar_t-).
Выберите "Дополнительно" и задайте соглашение о вызовах: _stdcall (/Gz).
В разделе "Свойства конфигурации" разверните линковщик, выберите вкладку "Вход" и добавьте в Дополнительные зависимости:
- "C:\Program Files\Microsoft SDKs\Windows\v7.0\Lib\MUILoad.lib".
- "C:\Microsoft NLS Downlevel API\Lib\x86\Nlsdl.lib".
Замените содержимое GuiStep_3.cpp следующим кодом:
// GuiStep_3.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "GuiStep_3.h" #include <strsafe.h> #include <Nlsdl.h> #include <MUILoad.h> #include "..\HelloModule_en_us\resource.h" #define SUFFICIENTLY_LARGE_STRING_BUFFER (MAX_PATH*2) #define USER_CONFIGURATION_STRING_BUFFER (((LOCALE_NAME_MAX_LENGTH+1)*5)+1) #define SUFFICIENTLY_LARGE_ERROR_BUFFER (1024*2) #define HELLO_MODULE_CONTRIVED_FILE_PATH (L"HelloModule.dll") BOOL GetMyUserDefinedLanguages(WCHAR * langStr, DWORD langStrSize); BOOL ConvertMyLangStrToMultiLangStr(WCHAR * langStr, WCHAR * langMultiStr, DWORD langMultiStrSize); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hInstance); UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); UNREFERENCED_PARAMETER(nCmdShow); // The following code presents a hypothetical, yet common use pattern of MUI technology WCHAR displayBuffer[SUFFICIENTLY_LARGE_ERROR_BUFFER]; // 1. Application starts by applying any user defined language preferences // (language setting is potentially optional for an application that wishes to strictly use OS system language fallback) // 1a. Application looks in pre-defined location for user preferences (registry, file, web, etc.) WCHAR userLanguagesString[USER_CONFIGURATION_STRING_BUFFER*2]; if(!GetMyUserDefinedLanguages(userLanguagesString,USER_CONFIGURATION_STRING_BUFFER*2)) { swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"FAILURE: Unable to find the user defined language configuration, last error = %d.",GetLastError()); MessageBoxW(NULL,displayBuffer,L"HelloMUI ERROR!",MB_OK | MB_ICONERROR); return 1; // exit } // 1b. Application converts the user defined 'readable' languages to the proper multi-string 'less readable' language name format WCHAR userLanguagesMultiString[USER_CONFIGURATION_STRING_BUFFER]; if(!ConvertMyLangStrToMultiLangStr(userLanguagesString,userLanguagesMultiString,USER_CONFIGURATION_STRING_BUFFER)) { swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"FAILURE: Unable to convert the user defined language configuration to multi-string, last error = %d.",GetLastError()); MessageBoxW(NULL,displayBuffer,L"HelloMUI ERROR!",MB_OK | MB_ICONERROR); return 1; // exit } // 1c. Application now attempts to set the fallback list - this is much different for a down-level // shipping application when compared to a Windows Vista or Windows 7 only shipping application BOOL setSuccess = FALSE; DWORD setLangCount = 0; HMODULE hDLL = GetModuleHandleW(L"kernel32.dll"); if( hDLL ) { typedef BOOL (* SET_PREFERRED_UI_LANGUAGES_PROTOTYPE ) ( DWORD, PCWSTR, PULONG ); SET_PREFERRED_UI_LANGUAGES_PROTOTYPE fp_SetPreferredUILanguages = (SET_PREFERRED_UI_LANGUAGES_PROTOTYPE)NULL; fp_SetPreferredUILanguages = (SET_PREFERRED_UI_LANGUAGES_PROTOTYPE) GetProcAddress(hDLL,"SetProcessPreferredUILanguages"); if( fp_SetPreferredUILanguages ) { // call SetProcessPreferredUILanguages if it is available in Kernel32.dll's export table - Windows 7 and later setSuccess = fp_SetPreferredUILanguages(MUI_LANGUAGE_NAME,userLanguagesMultiString,&setLangCount); } else { fp_SetPreferredUILanguages = (SET_PREFERRED_UI_LANGUAGES_PROTOTYPE) GetProcAddress(hDLL,"SetThreadPreferredUILanguages"); // call SetThreadPreferredUILanguages if it is available in Kernel32.dll's export table - Windows Vista and later if(fp_SetPreferredUILanguages) setSuccess = fp_SetPreferredUILanguages(MUI_LANGUAGE_NAME,userLanguagesMultiString,&setLangCount); } } // 2. Application obtains access to the proper resource container // for standard Win32 resource loading this is normally a PE module // LoadMUILibrary is the preferred alternative for loading of resource modules // when the application is potentially run on OS versions prior to Windows Vista // LoadMUILibrary is available via Windows SDK releases in Windows Vista and later // When available, it is advised to get the most up-to-date Windows SDK (e.g., Windows 7) HMODULE resContainer = NULL; if(setSuccess) // Windows Vista and later OS scenario { resContainer = LoadMUILibraryW(HELLO_MODULE_CONTRIVED_FILE_PATH,MUI_LANGUAGE_NAME,0); } else // this block should only be hit on Windows XP and earlier OS platforms as setSuccess will be TRUE on Windows Vista and later { // need to provide your own fallback mechanism such as the implementation below // in essence the application will iterate through the user configured language list WCHAR * next = userLanguagesMultiString; while(!resContainer && *next != L'\0') { // convert the language name to an appropriate LCID // DownlevelLocaleNameToLCID is available via standalone download package // and is contained in Nlsdl.h / Nlsdl.lib LCID nextLcid = DownlevelLocaleNameToLCID(next,DOWNLEVEL_LOCALE_NAME); // then have LoadMUILibrary attempt to probe for the right .mui module resContainer = LoadMUILibraryW(HELLO_MODULE_CONTRIVED_FILE_PATH,MUI_LANGUAGE_NAME,(LANGID)nextLcid); // increment to the next language name in our list size_t nextStrLen = 0; if(SUCCEEDED(StringCchLengthW(next,LOCALE_NAME_MAX_LENGTH,&nextStrLen))) next += (nextStrLen + 1); else break; // string is invalid - need to exit } // if the user configured list did not locate a module then try the languages associated with the system if(!resContainer) resContainer = LoadMUILibraryW(HELLO_MODULE_CONTRIVED_FILE_PATH,MUI_LANGUAGE_NAME,0); } if(!resContainer) { swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"FAILURE: Unable to load the resource container module, last error = %d.",GetLastError()); MessageBoxW(NULL,displayBuffer,L"HelloMUI ERROR!",MB_OK | MB_ICONERROR); return 1; // exit } // 3. Application parses the resource container to find the appropriate item WCHAR szHello[SUFFICIENTLY_LARGE_STRING_BUFFER]; if(LoadStringW(resContainer,HELLO_MUI_STR_0,szHello,SUFFICIENTLY_LARGE_STRING_BUFFER) == 0) { swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"FAILURE: Unable to load the resource string, last error = %d.",GetLastError()); MessageBoxW(NULL,displayBuffer,L"HelloMUI ERROR!",MB_OK | MB_ICONERROR); FreeLibrary(resContainer); return 1; // exit } // 4. Application presents the discovered resource to the user via UI swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"%s MUI",szHello); MessageBoxW(NULL,displayBuffer,L"HelloMUI",MB_OK | MB_ICONINFORMATION); // 5. Application cleans up memory associated with the resource container after this item is no longer needed. if(!FreeMUILibrary(resContainer)) { swprintf_s(displayBuffer,SUFFICIENTLY_LARGE_ERROR_BUFFER,L"FAILURE: Unable to unload the resource container, last error = %d.",GetLastError()); MessageBoxW(NULL,displayBuffer,L"HelloMUI ERROR!",MB_OK | MB_ICONERROR); return 1; // exit } return 0; } BOOL GetMyUserDefinedLanguages(WCHAR * langStr, DWORD langStrSize) { BOOL rtnVal = FALSE; // very simple implementation - assumes that first 'langStrSize' characters of the // L".\\langs.txt" file comprises a string of one or more languages HANDLE langConfigFileHandle = CreateFileW(L".\\langs.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(langConfigFileHandle != INVALID_HANDLE_VALUE) { // clear out the input variables DWORD bytesActuallyRead = 0; if(ReadFile(langConfigFileHandle,langStr,langStrSize*sizeof(WCHAR),&bytesActuallyRead,NULL) && bytesActuallyRead > 0) { rtnVal = TRUE; DWORD nullIndex = (bytesActuallyRead/sizeof(WCHAR) < langStrSize) ? bytesActuallyRead/sizeof(WCHAR) : langStrSize; langStr[nullIndex] = L'\0'; } CloseHandle(langConfigFileHandle); } return rtnVal; } BOOL ConvertMyLangStrToMultiLangStr(WCHAR * langStr, WCHAR * langMultiStr, DWORD langMultiStrSize) { BOOL rtnVal = FALSE; size_t strLen = 0; rtnVal = SUCCEEDED(StringCchLengthW(langStr,USER_CONFIGURATION_STRING_BUFFER*2,&strLen)); if(rtnVal && strLen > 0 && langMultiStr && langMultiStrSize > 0) { WCHAR * langMultiStrPtr = langMultiStr; WCHAR * last = langStr + (langStr[0] == 0xFEFF ? 1 : 0); WCHAR * context = last; WCHAR * next = wcstok_s(last,L",; :",&context); while(next && rtnVal) { // make sure you validate the user input if(SUCCEEDED(StringCchLengthW(last,LOCALE_NAME_MAX_LENGTH,&strLen)) && DownlevelLocaleNameToLCID(next,0) != 0) { langMultiStrPtr[0] = L'\0'; rtnVal &= SUCCEEDED(StringCchCatW(langMultiStrPtr,(langMultiStrSize - (langMultiStrPtr - langMultiStr)),next)); langMultiStrPtr += strLen + 1; } next = wcstok_s(NULL,L",; :",&context); if(next) last = next; } if(rtnVal && (langMultiStrSize - (langMultiStrPtr - langMultiStr))) // make sure there is a double null term for the multi-string { langMultiStrPtr[0] = L'\0'; } else // fail and guard anyone whom might use the multi-string { langMultiStr[0] = L'\0'; langMultiStr[1] = L'\0'; } } return rtnVal; }
Создайте или скопируйте langs.txt в соответствующий каталог, как описано ранее в шаге 4 из : Глобализация "Hello MUI".
Соберите и запустите проект.
Заметка
Если приложение должно работать в версиях Windows до Windows Vista, ознакомьтесь с документами, которые пришли с пакетом API нижнего уровня Microsoft NLS, о том, как распространить Nlsdl.dll. (это больше не доступно в Центре загрузки Майкрософт . Используйте API глобализации ICU в обновлении Windows 10 мая 2019 г. и более поздних версий.)
Дополнительные рекомендации по MUI
Поддержка консольных приложений
Методы, описанные в этом руководстве, также можно использовать в консольных приложениях. Однако, в отличие от большинства стандартных элементов управления ГРАФИЧЕСКИМ интерфейсом, окно командной строки Windows не может отображать символы для всех языков. По этой причине многоязычные консольные приложения требуют особого внимания.
Вызов API SetThreadUILanguage или SetThreadPreferredUILanguages с определенными флагами фильтрации приводит к удалению функций загрузки ресурсов для определенных языков, которые обычно не отображаются в командном окне. Если эти флаги заданы, алгоритмы настройки языка позволяют использовать только те языки, которые будут отображаться правильно в окне команд в резервном списке.
Дополнительные сведения об использовании этих API для создания многоязычного консольного приложения см. в разделах SetThreadUILanguage и SetThreadPreferredUILanguages.
Определение языков для поддержки на этапе Run-Time
Вы можете принять одно из следующих предложений по проектированию, чтобы определить, какие языки ваше приложение должно поддерживать во время выполнения:
во время установки, чтобы пользователь мог выбрать предпочтительный язык из списка поддерживаемых языков
Чтение списка языков из файла конфигурации
Некоторые проекты в этом руководстве содержат функцию, используемую для анализа файла конфигурации langs.txt, содержащего список языков.
Так как эта функция принимает внешние входные данные, проверьте языки, предоставляемые в качестве входных данных. Дополнительные сведения о выполнении этой проверки см. в функциях IsValidLocaleName или DownLevelLocaleNameToLCID.
выполните запрос к операционной системе, чтобы определить, какие языки установлены
Этот подход помогает приложению использовать тот же язык, что и операционная система. Хотя для этого не требуется запрашивать запрос пользователя, если вы выбрали этот параметр, помните, что языки операционной системы можно добавлять или удалять в любое время и изменяться после установки приложения. Кроме того, помните, что в некоторых случаях операционная система устанавливается с ограниченной поддержкой языка, и приложение предлагает большее значение, если оно поддерживает языки, которые операционная система не поддерживает.
Дополнительные сведения о том, как определить установленные языки в операционной системе, см. в функции EnumUILanguages.
Поддержка сложных сценариев в версиях до Windows Vista
Если приложение, поддерживающее определенные сложные скрипты, выполняется в версии Windows до Windows Vista, текст в этом сценарии может не отображаться должным образом в компонентах графического интерфейса. Например, в проекте нижнего уровня в этом руководстве скрипты hi-IN и ta-IN, возможно, не будут отображаться в окне сообщения из-за проблем с обработкой сложных сценариев и отсутствия соответствующих шрифтов. Как правило, проблемы этой природы представляют себя как квадратные коробки в компоненте ГРАФИЧЕСКОго интерфейса.
Дополнительные сведения о включении сложной обработки скриптов см. в разделе Скрипт и поддержка шрифтов в Windows.
Сводка
В этом руководстве продемонстрированы методы глобализации монолингвального приложения и соблюдение следующих лучших практик.
- Создайте приложение, чтобы воспользоваться преимуществами модели ресурсов Win32.
- Используйте разделение MUI ресурсов на вспомогательные двоичные файлы (MUI-файлы).
- Убедитесь, что процесс локализации обновляет ресурсы в ФАЙЛАх MUI, чтобы он соответствовал целевому языку.
- Убедитесь, что упаковка и развертывание приложения, связанные файлы MUI и содержимое конфигурации выполняются правильно, чтобы api загрузки ресурсов могли найти локализованное содержимое.
- Предоставьте конечным пользователям механизм для настройки конфигурации языка приложения.
- Настройте код времени выполнения, чтобы воспользоваться преимуществами языковой конфигурации, чтобы сделать приложение более адаптивным к потребностям конечных пользователей.