Freigeben über


Szenario 1: Generierung einer PRI-Datei aus String-Ressourcen und Asset-Dateien

In diesem Szenario werden wir die package resource indexing (PRI) APIs verwenden, um eine neue Anwendung zu erstellen, die unser benutzerdefiniertes Build-System darstellt. Der Zweck dieses benutzerdefinierten Build-Systems besteht darin, PRI-Dateien für eine UWP-Zielanwendung zu erstellen. Im Rahmen dieses Exkurses erstellen wir also einige Beispiel-Ressourcendateien (die Strings und andere Arten von Ressourcen enthalten), um die Ressourcen der Ziel-UWP-App darzustellen.

Neues Projekt

Erstelle zunächst ein neues Projekt in Microsoft Visual Studio. Erstellen Sie ein Projekt Visual C++ Windows Console Application und nennen Sie es CBSConsoleApp (für „custom build system console app“).

Wählen Sie x64 aus der Dropdown-Liste Lösungsplattformen.

Header, statische Bibliothek und dll

Die PRI-APIs werden in der Header-Datei MrmResourceIndexer.h deklariert (die unter %ProgramFiles(x86)%\Windows Kits\10\Include\<WindowsTargetPlatformVersion>\um\ installiert wird). Öffnen Sie die Datei CBSConsoleApp.cpp und fügen Sie den Header zusammen mit einigen anderen Headern ein, die Sie benötigen werden.

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

Die APIs sind in der Datei MrmSupport.dll implementiert, auf die Sie durch Verknüpfung mit der statischen Bibliothek MrmSupport.lib zugreifen können. Öffnen Sie Ihr Projekt Eigenschaften, klicken Sie auf Linker>Input, bearbeiten Sie AdditionalDependencies und fügen Sie MrmSupport.lib hinzu.

Erstellen Sie die Projektmappe, und kopieren Sie MrmSupport.dll von C:\Program Files (x86)\Windows Kits\10\bin\<WindowsTargetPlatformVersion>\x64\ in den Ausgabeordner für die Projektmappe (wahrscheinlich C:\Users\%USERNAME%\source\repos\CBSConsoleApp\x64\Debug\).

Fügen Sie die folgende Hilfsfunktion zu CBSConsoleApp.cpp hinzu, da wir sie benötigen werden.

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

Fügen Sie in der Funktion main() Aufrufe zum Initialisieren und Deinitialisieren von COM hinzu.

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

Ressourcendateien, die zur Ziel-UWP-Anwendung gehören

Jetzt brauchen wir einige Beispiel-Ressourcendateien (mit Strings und anderen Arten von Ressourcen), um die Ressourcen der Ziel-UWP-Anwendung darzustellen. Diese können sich natürlich überall in Ihrem Dateisystem befinden. Aber für diese Anleitung ist es praktisch, sie in den Projektordner von CBSConsoleApp zu legen, damit alles an einem Ort ist. Sie müssen diese Ressourcendateien nur dem Dateisystem hinzufügen; fügen Sie sie nicht dem CBSConsoleApp-Projekt hinzu.

Fügen Sie im selben Ordner, der CBSConsoleApp.vcxproj enthält, einen neuen Unterordner mit dem Namen UWPAppProjectRootFolder hinzu. Erstellen Sie in diesem neuen Unterordner diese Beispiel-Ressourcendateien.

\UWPAppProjectRootFolder\sample-image.png

Diese Datei kann ein beliebiges PNG-Bild enthalten.

\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>

Indizieren Sie die Ressourcen, und erstellen Sie eine PRI-Datei

In der Funktion main() deklarieren Sie vor dem Aufruf zur Initialisierung von COM einige Zeichenfolgen, die wir benötigen, und erstellen den Ausgabeordner, in dem wir unsere PRI-Datei erzeugen werden.

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);

Unmittelbar nach dem Aufruf von Initialize COM deklarieren Sie einen Ressourcenindexer-Handle und rufen dann MrmCreateResourceIndexer auf, um einen Ressourcenindexer zu erstellen.

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

Hier ist eine Erklärung der Argumente, die an MrmCreateResourceIndexer übergeben werden.

  • Der Name der Paketfamilie unserer UWP-Zielanwendung, der als Name der Ressourcenzuordnung verwendet wird, wenn wir später eine PRI-Datei aus diesem Ressourcenindexer erzeugen.
  • Der Projektstamm unserer UWP-Zielanwendung. Mit anderen Worten, der Pfad zu unseren Ressourcendateien. Wir geben dies an, damit wir in nachfolgenden API-Aufrufen an denselben Ressourcen-Indexer Pfade relativ zu diesem Stamm angeben können.
  • Die Version von Windows, auf die wir abzielen wollen.
  • Eine Liste von Standard-Ressourcenqualifikatoren.
  • Ein Zeiger auf unser Ressourcen-Indexer-Handle, damit die Funktion es setzen kann.

Der nächste Schritt ist das Hinzufügen unserer Ressourcen zu dem soeben erstellten Ressourcen-Indexer. resources.resw ist eine Ressourcendatei (.resw), die die neutralen Strings für unsere UWP-Zielanwendung enthält. Scrollen Sie nach oben (in diesem Thema), wenn Sie den Inhalt sehen wollen. de-DE\resources.resw Enthält unsere deutschen Zeichenketten, und en-US\resources.resw unsere englischen Zeichenketten. Um die String-Ressourcen innerhalb einer Ressourcendatei zu einem Ressourcen-Indexer hinzuzufügen, rufen Sie MrmIndexResourceContainerAutoQualifiers auf. Drittens rufen wir die Funktion MrmIndexFile auf, um eine Datei mit einer neutralen Bildressource an den Ressourcen-Indexer zu übergeben.

::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""));

Im Aufruf von MrmIndexFile ist der Wert L „ms-resource:///Files/sample-image.png“ die Ressourcen-URI. Das erste Pfadsegment ist „Files“, und das wird als Teilbaumname der Ressourcenzuordnung verwendet, wenn wir später eine PRI-Datei aus diesem Ressourcenindexer erzeugen.

Nachdem wir den Ressourcen-Indexer über unsere Ressourcendateien informiert haben, ist es an der Zeit, eine PRI-Datei auf der Festplatte zu erzeugen, indem wir die Funktion MrmCreateResourceFile aufrufen.

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

Zu diesem Zeitpunkt ist eine PRI-Datei mit dem Namen resources.pri in einem Ordner mit dem Namen Generated PRIs erstellt worden. Nun, da wir mit dem Ressourcen-Indexer fertig sind, rufen wir MrmDestroyIndexerAndMessages auf, um seinen Handle zu zerstören und alle von ihm zugewiesenen Maschinenressourcen freizugeben.

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

Da es sich bei einer PRI-Datei um eine binäre Datei handelt, ist es einfacher, die soeben erstellte Datei zu betrachten, wenn wir die binäre PRI-Datei in ihre XML-Entsprechung umwandeln. Ein Aufruf von MrmDumpPriFile bewirkt genau das.

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

Hier ist eine Erklärung der Argumente, die an MrmDumpPriFile übergeben werden.

  • Der Pfad zu der zu sichernden PRI-Datei. Wir verwenden den Ressourcen-Indexer in diesem Aufruf nicht (wir haben ihn gerade zerstört), daher müssen wir einen vollständigen Dateipfad angeben.
  • Keine Schemadatei. Was ein Schema ist, wird später in diesem Thema erläutert.
  • Nur die wichtigsten Informationen.
  • Der Pfad einer zu erstellenden XML-Datei.

Dies ist der Inhalt der PRI-Datei, die hier in XML umgewandelt wurde.

<?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>

Die Info beginnt mit einer Ressourcenzuordnung, die mit dem Namen der Paketfamilie unserer Ziel-UWP-Anwendung benannt ist. Die Ressourcenzuordnung enthält zwei Teilbäume: einen für die indizierten Dateiressourcen und einen für unsere Zeichenfolgenressourcen. Beachten Sie, dass der Name der Paketfamilie in alle Ressourcen-URIs eingefügt wurde.

Die erste String-Ressource ist EnOnlyString von en-US\resources.resw, und es gibt nur einen Kandidaten (der mit dem Qualifier language-en-US übereinstimmt). Als nächstes kommt LocalizedString1 aus resources.resw und en-US\resources.resw. Folglich gibt es zwei Kandidaten: einen, der zu language-en-US passt, und einen neutralen Ersatzkandidaten, der zu jedem Kontext passt. Auch für LocalizedString2 gibt es zwei Kandidaten: language-de-DE und neutral. Und schließlich existiert NeutralOnlyString nur in neutraler Form. Ich habe es so genannt, um zu verdeutlichen, dass es nicht für die Lokalisierung gedacht ist.

Zusammenfassung

In diesem Szenario haben wir gezeigt, wie man die APIs des -Pakets Resource Indexing (PRI) verwendet, um einen Resource Indexer zu erstellen. Wir haben String-Ressourcen und Asset-Dateien in den Ressourcen-Indexer aufgenommen. Anschließend haben wir mit dem Ressourcen-Indexer eine binäre PRI-Datei erzeugt. Und schließlich haben wir die binäre PRI-Datei in Form von XML ausgegeben, damit wir bestätigen können, dass sie die erwarteten Informationen enthält.

Wichtige APIs