Поделиться через


Сценарий 1. Создание файла PRI из строковых ресурсов и файлов ресурсов

В этом сценарии мы будем использовать API индексирования ресурсов пакета (PRI), чтобы создать новое приложение для представления пользовательской системы сборки. Цель этой пользовательской системы сборки, помните, заключается в создании файлов PRI для целевого приложения UWP. Таким образом, в рамках этого пошагового руководства мы создадим некоторые примеры файлов ресурсов (содержащих строки и другие виды ресурсов), чтобы представить эти целевые ресурсы приложения UWP.

Новый проект

Начните с создания проекта в Microsoft Visual Studio. Создайте проект консольного приложения Windows Visual C++ и назовите его CBSConsoleApp (для пользовательского консольного приложения сборки).

Выберите x64 в раскрывающемся списке "Платформы решений".

Заголовки, статическая библиотека и dll

API-интерфейсы PRI объявляются в файле заголовка MrmResourceIndexer.h (который установлен в %ProgramFiles(x86)%\Windows Kits\10\Include\<WindowsTargetPlatformVersion>\um\). Откройте файл CBSConsoleApp.cpp и добавьте заголовок вместе с другими нужными заголовками.

#include <string>
#include <windows.h>
#include <MrmResourceIndexer.h>

API реализованы в MrmSupport.dll, доступ к которому осуществляется путем связывания со статической библиотекой MrmSupport.lib. Откройте свойства проекта, нажмите кнопку "Входные данные компоновщика>", измените дополнительныеdependencies и добавьте.MrmSupport.lib

Создайте решение, а затем скопируйте MrmSupport.dll из C:\Program Files (x86)\Windows Kits\10\bin\<WindowsTargetPlatformVersion>\x64\ папки выходных данных сборки (вероятно C:\Users\%USERNAME%\source\repos\CBSConsoleApp\x64\Debug\).

Добавьте следующую вспомогающую функцию CBSConsoleApp.cpp, так как нам потребуется.

inline void ThrowIfFailed(HRESULT hr)
{
	if (FAILED(hr))
	{
		// Set a breakpoint on this line to catch Win32 API errors.
		throw new std::exception();
	}
}

main() В функции добавьте вызовы для инициализации и неинициализации COM.

int main()
{
	::ThrowIfFailed(::CoInitializeEx(nullptr, COINIT_MULTITHREADED));
	
	// More code will go here.
	
	::CoUninitialize();
}

Файлы ресурсов, принадлежащие целевому приложению UWP

Теперь нам потребуется несколько примеров файлов ресурсов (содержащих строки и другие виды ресурсов) для представления ресурсов целевого приложения UWP. Конечно, они могут находиться в любом месте файловой системы. Но для этого пошагового руководства будет удобно поместить их в папку проекта CBSConsoleApp, чтобы все было в одном месте. Эти файлы ресурсов необходимо добавить только в файловую систему; Не добавляйте их в проект CBSConsoleApp.

В той же папке, содержащейся CBSConsoleApp.vcxproj, добавьте новую вложенную папку с именем UWPAppProjectRootFolder. В этой вложенной папке создайте эти примеры файлов ресурсов.

\UWPAppProjectRootFolder\sample-image.png

Этот файл может содержать любое изображение PNG.

\UWPAppProjectRootFolder\resources.resw

<?xml version="1.0"?>
<root>
	<data name="LocalizedString1">
		<value>LocalizedString1-neutral</value>
	</data>
	<data name="LocalizedString2">
		<value>LocalizedString2-neutral</value>
	</data>
	<data name="NeutralOnlyString">
		<value>NeutralOnlyString-neutral</value>
	</data>
</root>

\UWPAppProjectRootFolder\de-DE\resources.resw

<?xml version="1.0"?>
<root>
	<data name="LocalizedString2">
		<value>LocalizedString2-de-DE</value>
	</data>
</root>

\UWPAppProjectRootFolder\en-US\resources.resw

<?xml version="1.0"?>
<root>
	<data name="LocalizedString1">
		<value>LocalizedString1-en-US</value>
	</data>
	<data name="EnOnlyString">
		<value>EnOnlyString-en-US</value>
	</data>
</root>

Индексирование ресурсов и создание файла PRI

main() В функции перед вызовом инициализации COM объявите некоторые строки, которые нам потребуются, а также создайте выходную папку, в которой мы создадим наш PRI-файл.

std::wstring projectRootFolderUWPApp{ L"UWPAppProjectRootFolder" };
std::wstring generatedPRIsFolder{ projectRootFolderUWPApp + L"\\Generated PRIs" };
std::wstring filePathPRI{ generatedPRIsFolder + L"\\resources.pri" };
std::wstring filePathPRIDumpBasic{ generatedPRIsFolder + L"\\resources-pri-dump-basic.xml" };

::CreateDirectory(generatedPRIsFolder.c_str(), nullptr);

Сразу после вызова com инициализации объявите дескриптор индексатора ресурсов, а затем вызовите mrmCreateResourceIndexer для создания индексатора ресурсов.

MrmResourceIndexerHandle indexer;
::ThrowIfFailed(::MrmCreateResourceIndexer(
	L"OurUWPApp",
	projectRootFolderUWPApp.c_str(),
	MrmPlatformVersion::MrmPlatformVersion_Windows10_0_0_0,
	L"language-en_scale-100_contrast-standard",
	&indexer));

Ниже приведено объяснение аргументов, передаваемых в MrmCreateResourceIndexer.

  • Имя семейства пакетов целевого приложения UWP, которое будет использоваться в качестве имени карты ресурсов при последующем создании файла PRI из этого индексатора ресурсов.
  • Корневой каталог проекта целевого приложения UWP. Другими словами, путь к файлам ресурсов. Мы указываем это, чтобы затем можно было указать пути относительно этого корня в последующих вызовах API к тому же индексатору ресурсов.
  • Целевая версия Windows.
  • Список квалификаторов ресурсов по умолчанию.
  • Указатель на дескриптор индексатора ресурсов, чтобы она была настроена.

Следующим шагом является добавление ресурсов в только что созданный индексатор ресурсов. resources.resw — это файл ресурсов (RESW), содержащий нейтральные строки для целевого приложения UWP. Прокрутите страницу вверх (в этом разделе), если хотите просмотреть его содержимое. de-DE\resources.resw содержит наши немецкие строки и en-US\resources.resw наши английские строки. Чтобы добавить строковые ресурсы в файл ресурсов в индексатор ресурсов, вызовите mrmIndexResourceContainerAutoQualifiers. В-третьих, мы вызываем функцию MrmIndexFile в файл, содержащий нейтральный ресурс изображения индексатору ресурсов.

::ThrowIfFailed(::MrmIndexResourceContainerAutoQualifiers(indexer, L"resources.resw"));
::ThrowIfFailed(::MrmIndexResourceContainerAutoQualifiers(indexer, L"de-DE\\resources.resw"));
::ThrowIfFailed(::MrmIndexResourceContainerAutoQualifiers(indexer, L"en-US\\resources.resw"));
::ThrowIfFailed(::MrmIndexFile(indexer, L"ms-resource:///Files/sample-image.png", L"sample-image.png", L""));

В вызове MrmIndexFile значение L"ms-resource:///Files/sample-image.png" — это универсальный код ресурса ресурса. Первый сегмент пути — "Файлы", и это то, что будет использоваться в качестве имени поддерев карты ресурсов при последующем создании файла PRI из этого индексатора ресурсов.

Познакомившись с индексатором ресурсов о файлах ресурсов, пришло время создать файл PRI на диске, вызвав функцию MrmCreateResourceFile.

::ThrowIfFailed(::MrmCreateResourceFile(indexer, MrmPackagingModeStandaloneFile, MrmPackagingOptionsNone, generatedPRIsFolder.c_str()));

На этом этапе в папке с именем resources.priGenerated PRIsPRI-файл был создан. Теперь, когда мы закончим с индексатором ресурсов, мы называем mrmDedexerIndexerAndMessages , чтобы уничтожить его дескриптор и освободить все выделенные им ресурсы компьютера.

::ThrowIfFailed(::MrmDestroyIndexerAndMessages(indexer));

Так как файл PRI является двоичным, это будет проще просматривать то, что мы только что создали, если мы дампам двоичный ФАЙЛ PRI в его XML-эквивалент. Вызов mrmDumpPriFile делает это.

::ThrowIfFailed(::MrmDumpPriFile(filePathPRI.c_str(), nullptr, MrmDumpType::MrmDumpType_Basic, filePathPRIDumpBasic.c_str()));

Ниже приведено объяснение аргументов, передаваемых в MrmDumpPriFile.

  • Путь к файлу PRI для дампа. Мы не используем индексатор ресурсов в этом вызове (мы просто уничтожили его), поэтому нам нужно указать полный путь к файлу.
  • Файл схемы отсутствует. Рассмотрим схему далее в этом разделе.
  • Просто основные сведения.
  • Путь к создаваемому XML-файлу.

Это то, что PRI-файл, дампаемый в XML здесь, содержит.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<PriInfo>
	<ResourceMap name="OurUWPApp" version="1.0" primary="true">
		<Qualifiers>
			<Language>en-US,de-DE</Language>
		</Qualifiers>
		<ResourceMapSubtree name="Files">
			<NamedResource name="sample-image.png" uri="ms-resource://OurUWPApp/Files/sample-image.png">
				<Candidate type="Path">
					<Value>sample-image.png</Value>
				</Candidate>
			</NamedResource>
		</ResourceMapSubtree>
		<ResourceMapSubtree name="resources">
			<NamedResource name="EnOnlyString" uri="ms-resource://OurUWPApp/resources/EnOnlyString">
				<Candidate qualifiers="Language-en-US" isDefault="true" type="String">
					<Value>EnOnlyString-en-US</Value>
				</Candidate>
			</NamedResource>
			<NamedResource name="LocalizedString1" uri="ms-resource://OurUWPApp/resources/LocalizedString1">
				<Candidate qualifiers="Language-en-US" isDefault="true" type="String">
					<Value>LocalizedString1-en-US</Value>
				</Candidate>
				<Candidate type="String">
					<Value>LocalizedString1-neutral</Value>
				</Candidate>
			</NamedResource>
			<NamedResource name="LocalizedString2" uri="ms-resource://OurUWPApp/resources/LocalizedString2">
				<Candidate qualifiers="Language-de-DE" type="String">
					<Value>LocalizedString2-de-DE</Value>
				</Candidate>
				<Candidate type="String">
					<Value>LocalizedString2-neutral</Value>
				</Candidate>
			</NamedResource>
			<NamedResource name="NeutralOnlyString" uri="ms-resource://OurUWPApp/resources/NeutralOnlyString">
				<Candidate type="String">
					<Value>NeutralOnlyString-neutral</Value>
				</Candidate>
			</NamedResource>
		</ResourceMapSubtree>
	</ResourceMap>
</PriInfo>

Информация начинается с карты ресурсов, которая называется с именем семейства пакетов нашего целевого приложения UWP. Заключимые картой ресурсов являются двумя поддеревами карты ресурсов: одна для файловых ресурсов, индексированных и другая для строковых ресурсов. Обратите внимание, что имя семейства пакетов вставляется во все URI ресурсов.

Первый строковый ресурс — EnOnlyString из en-US\resources.resw, и он имеет только одного кандидата (который соответствует квалификатору language-en-US ). Далее происходит LocalizedString1 из обоих resources.resw и en-US\resources.resw. Следовательно, он имеет двух кандидатов: один соответствующий язык-en-US, и резервный нейтральный кандидат, который соответствует любому контексту. Аналогичным образом LocalizedString2 имеет двух кандидатов: language-de-DE и нейтральных. И, наконец, NeutralOnlyString существует только в нейтральной форме. Я дал ему это имя, чтобы ясно, что он не предназначен для локализации.

Итоги

В этом сценарии мы показали, как использовать API индексирования ресурсов пакета (PRI) для создания индексатора ресурсов. Мы добавили строковые ресурсы и файлы ресурсов в индексатор ресурсов. Затем мы использовали индексатор ресурсов для создания двоичного файла PRI. Наконец, мы дампы двоичного файла PRI в виде XML, чтобы убедиться, что он содержит ожидаемые сведения.

Важные API