シナリオ 1: 文字列リソースとアセット ファイルから PRI ファイルを生成する

このシナリオでは、パッケージ リソース インデックス (PRI) API を使用してカスタム ビルド システムを表す新しいアプリを作成します。 このカスタム ビルド システムの目的は、対象の UWP アプリの PRI ファイルを作成することです。 そのため、このチュートリアルの一部として、その対象とする UWP アプリのリソースを表す、(文字列、およびその他の種類のリソースを含む) サンプルのリソース ファイルを作成します。

新しいプロジェクト

まず、Microsoft Visual Studio で、新しいプロジェクトを作成します。 Visual C++ Windows コンソール アプリケーション プロジェクトを作成し、CBSConsoleApp ("カスタム ビルド システムのコンソール アプリ" を表す) という名前を付けます。

[ソリューション プラットフォーム] ドロップダウンから [x64] を選択します。

ヘッダー、静的ライブラリ、dll

PRI API は、MrmResourceIndexer.h ヘッダー ファイル (%ProgramFiles(x86)%\Windows Kits\10\Include\<WindowsTargetPlatformVersion>\um\ にインストールされます) で宣言されています。 ファイル CBSConsoleApp.cpp を開き、そのヘッダーと、その他の必要になるいくつかのヘッダーを含めます。

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

API は MrmSupport.dll に実装されています。MrmSupport.dll には、静的ライブラリ MrmSupport.lib にリンクすることでアクセスします。 プロジェクトの [プロパティ] を開き、[リンカー]>[入力] の順にクリックし、AdditionalDependencies を編集して MrmSupport.lib を追加します。

ソリューションをビルドし、MrmSupport.dllC:\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 アプリのリソースを表す、(文字列、およびその他の種類のリソースを含む) サンプルのリソース ファイルが必要になります。 これらは、もちろん、ファイル システム上の任意の場所に配置することができます。 ただし、このチュートリアルでは、すべてを 1 か所にまとめるために、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 に渡される引数について、以下に示します。

  • 後でこのリソース インデクサーから PRI ファイルを生成したときにリソース マップ名として使用する、対象の UWP アプリのパッケージ ファミリ名です。
  • 対象の UWP アプリのプロジェクト ルートです。 つまり、リソース ファイルのパスです。 これは、同じリソース インデクサーへの以降の API 呼び出しでそのルートの相対パスを指定できるようにするために指定します。
  • 対象にする Windows のバージョンです。
  • 既定のリソース修飾子の一覧です。
  • 関数で設定できるようにするための、リソース インデクサー ハンドルへのポインターです。

次の手順では、先ほど作成したリソース インデクサーにリソースを追加します。 resources.resw は、対象の UWP アプリの中立的な文字列が含まれているリソース ファイル (.resw) です。 その内容を表示する場合は、(このトピック内で) 上方向にスクロールします。 de-DE\resources.resw にはドイツ語の文字列が、en-US\resources.resw には英語の文字列が含まれています。 リソース ファイル内の文字列リソースをリソース インデクサーに追加するには、MrmIndexResourceContainerAutoQualifiers を呼び出します。 3 番目に、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" はリソース uri です。 最初のパス セグメントは "Files" で、これが後でこのリソース インデクサーから PRI ファイルを生成したときにリソース マップのサブツリー名として使用されます。

リソース ファイルに関するリソース インデクサーの概要を説明したので、MrmCreateResourceFile 関数を呼び出してディスクに PRI ファイルを自動的に生成できるようにしましょう。

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

この時点で、resources.pri という名前の PRI ファイルが Generated PRIs という名前のフォルダー内に作成されました。 これで、リソース インデクサーの作業が完了したので、MrmDestroyIndexerAndMessages を呼び出して、そのハンドルを破棄し、割り当てられたマシン リソースをリリースします。

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

PRI ファイルはバイナリであるため、バイナリ PRI ファイルをそれに対応する XML にダンプすると、先ほど生成したものを表示するのが簡単になります。 MrmDumpPriFile を呼び出すだけでそれが行われます。

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

MrmDumpPriFile に渡される引数について、以下に示します。

  • ダンプする PRI ファイルのパス。 この呼び出しでリソース インデクサーは使用しません (先ほどそれを破棄しました)。そのため完全なファイル パスを指定する必要があります。
  • スキーマ ファイルはありません。 スキーマの概要については、後のトピックで説明します。
  • 単なる基本情報です。
  • 作成する XML ファイルのパスです。

これは、ここで XML にダンプされる PRI ファイルに含まれる内容です。

<?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 アプリのパッケージ ファミリ名が付いたリソース マップから始まります。 リソース マップで囲まれているのは 2 つのリソース マップ サブツリーです。1 つはインデックスを作成したファイル リソース用で、もう 1 つは文字列リソース用です。 パッケージ ファミリ名がすべてのリソース URI に挿入されているのがわかります。

最初の文字列リソースは、en-US\resources.reswEnOnlyString で候補が 1 つだけあります (その候補は language-en-US 修飾子に一致します)。 次のリソースは、resources.resw および en-US\resources.reswLocalizedString1 です。 そのため、language-en-US に一致する候補と、任意のコンテキストに一致するフォールバックの中立の候補の 2 つの候補があります。 同様に、LocalizedString2 には、language-de-DE と中立の 2 つの候補があります。 最後に、NeutralOnlyString は中立の形式だけに存在します。 その名前を指定して、そのリソースがローカライズされるものではないということを明確にしています。

まとめ

このシナリオでは、パッケージ リソース インデックス (PRI) API を使用してリソース インデクサーを作成する方法を示しました。 文字列リソースとアセット ファイルをリソース インデクサーに追加しました。 次に、リソース インデクサーを使用してバイナリ PRI ファイルを生成しました。 最後に、期待した情報が含まれていることを確認できるように、XML の形式でバイナリ PRI ファイルをダンプしました。

重要な API