Windows-Runtime-Komponenten mit C++/WinRT

In diesem Thema wird gezeigt, wie Sie mit C++/WinRT eine Windows-Runtime-Komponente erstellen und nutzen – eine Komponente, die von einer universellen Windows-App aufgerufen werden kann, die mit einer beliebigen Windows-Runtime Sprache erstellt wurde.

Es gibt mehrere Gründe für das Erstellen einer Windows-Runtime-Komponente in C++/WinRT.

  • Um den Leistungsvorteil von C++ in komplexen oder rechenintensiven Vorgängen zu nutzen.
  • Um C++-Standardcode wiederzuverwenden, der bereits geschrieben und getestet wurde.
  • So machen Sie win32-Funktionen für eine Universelle Windows-Plattform-App (UWP) verfügbar, die in geschrieben wurde, z. B. C#.

Im Allgemeinen können Sie beim Erstellen Ihrer C++/WinRT-Komponente Typen aus der C++-Standardbibliothek und integrierte Typen verwenden, außer an der ABI-Grenze (Application Binary Interface), an der Sie Daten an und aus Code in einem anderen .winmd Paket übergeben. Verwenden Sie an der ABI Windows-Runtime Typen. Verwenden Sie in Ihrem C++/WinRT-Code außerdem Typen wie Delegat und Ereignis, um Ereignisse zu implementieren, die von Ihrer Komponente ausgelöst und in einer anderen Sprache behandelt werden können. Weitere Informationen zu C++/WinRT finden Sie unter C++/WinRT .

Im weiteren Verlauf dieses Themas erfahren Sie, wie Sie eine Windows-Runtime-Komponente in C++/WinRT erstellen und diese dann von einer Anwendung nutzen können.

Die Windows-Runtime Komponente, die Sie in diesem Thema erstellen, enthält eine Laufzeitklasse, die ein Thermometer darstellt. Das Thema zeigt auch eine Core-App, die die Laufzeitklasse des Thermometers nutzt und eine Funktion aufruft, um die Temperatur anzupassen.

Hinweis

Informationen zum Installieren und Verwenden der Visual Studio-Erweiterung (VSIX) C++/WinRT und des NuGet-Pakets (die zusammen die Projektvorlage und Buildunterstützung bereitstellen) findest du unter Visual Studio support for C++/WinRT, XAML, the VSIX extension, and the NuGet package (Visual Studio-Unterstützung für C++/WinRT, XAML, die VSIX-Erweiterung und das NuGet-Paket).

Wichtig

Wichtige Konzepte und Begriffe im Zusammenhang mit der Nutzung und Erstellung von Laufzeitklassen mit C++/WinRT findest du unter Verwenden von APIs mit C++/WinRT sowie unter Erstellen von APIs mit C++/WinRT.

Bewährte Methode zum Benennen von Windows-Runtime Komponenten-DLLs

Wichtig

In diesem Abschnitt wird die Benennungskonvention beschrieben, die für die Datei (DLL) empfohlen wird, in der .dll Sie Ihre Windows-Runtime-Komponente erstellen. Es geht um die Aktivierungssequenz, die C++/WinRT folgt, wenn Sie eine Laufzeitklasse aus einer Windows-Runtime-Komponente nutzen.

Beim Aktivieren einer Klassenfactory versucht C++/WinRT zunächst einen Aufruf von RoGetActivationFactory. Wenn dies fehlschlägt, versucht C++/WinRT, eine DLL zum direkten Laden zu finden. Windows-Runtime Aktivierung basiert immer auf einem vollqualifizierten Klassennamen. Die Logik besteht darin, den Klassennamen (aus diesem vollqualifizierten Klassennamen) zu entfernen und dann nach einer DLL mit dem Namen für den vollständigen Namespace zu suchen, der verbleibt. Wenn dies nicht gefunden wird, entfernen Sie den spezifischen Segmentnamen, und wiederholen Sie dies.

Wenn die aktivierte Klasse beispielsweise den vollqualifizierten Namen Contoso.Instruments.ThermometerWRC.Thermometer aufweist und RoGetActivationFactory fehlschlägt, suchen wir zunächst nach einem Contoso.Instruments.ThermometerWRC.dll. Wenn dies nicht gefunden wird, suchen Contoso.Instruments.dllwir nach , und dann nach Contoso.dll.

Wenn eine DLL gefunden wird (in dieser Sequenz), verwenden wir den DllGetActivationFactory-Einstiegspunkt dieser DLL, um zu versuchen, die Factory direkt abzurufen (anstatt indirekt über die RoGetActivationFactory-Funktion , die wir zuerst versucht haben). Dennoch ist das Endergebnis für den Aufrufer und die DLL nicht zu unterscheiden.

Dieser Prozess erfolgt vollständig automatisch – es sind keine Registrierung oder Tools erforderlich. Wenn Sie eine Windows-Runtime Komponente erstellen, müssen Sie nur eine Benennungskonvention für Ihre DLLs verwenden, die mit dem soeben beschriebenen Prozess funktioniert. Wenn Sie eine Windows-Runtime Komponente verwenden und diese nicht richtig benannt ist, haben Sie die Möglichkeit, sie wie beschrieben umzubenennen.

Erstellen einer Windows-Runtime-Komponente (ThermometerWRC)

Erstelle zunächst ein neues Projekt in Microsoft Visual Studio. Erstellen Sie ein Windows-Runtime Component-Projekt (C++/WinRT), und nennen Sie es ThermometerWRC (für "Thermometer Windows-Runtime Komponente"). Stelle sicher, dass Platzieren Sie die Projektmappe und das Projekt im selben Verzeichnis deaktiviert ist. Die neueste allgemein verfügbare Version von Windows SDK (d. h. keine Vorschauversion). Die Benennung des Projekts ThermometerWRC ermöglicht Ihnen die einfachste Erfahrung mit den restlichen Schritten in diesem Thema.

Führen Sie noch keinen Buildvorgang für das Projekt aus.

Das neu erstellte Projekt enthält eine Datei namens Class.idl. Ändern Sie im Projektmappen-Explorer den Namen der Datei Thermometer.idl. (Durch die Umbenennung der Datei vom Typ .idl werden automatisch auch die abhängigen Dateien .h und .cpp umbenannt.) Ersetze den Inhalt von Thermometer.idl durch das folgende Listing:

// Thermometer.idl
namespace ThermometerWRC
{
    runtimeclass Thermometer
    {
        Thermometer();
        void AdjustTemperature(Single deltaFahrenheit);
    };
}

Speichern Sie die Datei. Das Projekt wird derzeit nicht bis zum Abschluss erstellt, aber das Erstellen von jetzt ist eine nützliche Sache, da die Quellcodedateien generiert werden, in denen Sie die Thermometer-Runtimeklasse implementieren. Erstelle daher als Nächstes das Projekt. (Die in dieser Phase zu erwartenden Buildfehler sind darauf zurückzuführen, dass Class.h und Class.g.h nicht gefunden wurden.)

Während des Buildprozesses wird das Tool midl.exe ausgeführt, um die Windows-Runtime-Metadatendatei (\ThermometerWRC\Debug\ThermometerWRC\ThermometerWRC.winmd) deiner Komponente zu erstellen. Danach wird das Tool cppwinrt.exe (mit der Option -component) ausgeführt, um Quellcodedateien zu generieren, die dich bei der Erstellung deiner Komponente unterstützen. Diese Dateien enthalten Stubs, die Ihnen die Implementierung der Thermometer-Laufzeitklasse erleichtern, die Sie in Ihrer IDL deklariert haben. Diese Stubs sind \ThermometerWRC\ThermometerWRC\Generated Files\sources\Thermometer.h und Thermometer.cpp.

Klicke mit der rechten Maustaste auf den Projektknoten, und klicke auf Ordner in Datei-Explorer öffnen. Dadurch wird der Projektordner im Datei-Explorer geöffnet. Kopiere dort die Stub-Dateien Thermometer.h und Thermometer.cpp aus dem Ordner \ThermometerWRC\ThermometerWRC\Generated Files\sources\ in den Ordner mit deinen Projektdateien (\ThermometerWRC\ThermometerWRC\), und ersetze die Dateien am Ziel. Als Nächstes öffnen wir Thermometer.h und Thermometer.cpp und implementieren unsere Laufzeitklasse. Thermometer.hFügen Sie in der Implementierung (nicht der Factoryimplementierung) von Thermometer ein neues privates Element hinzu.

// Thermometer.h
...
namespace winrt::ThermometerWRC::implementation
{
    struct Thermometer : ThermometerT<Thermometer>
    {
        ...

    private:
        float m_temperatureFahrenheit { 0.f };
    };
}
...

Implementieren Thermometer.cppSie in die AdjustTemperature-Methode , wie in der folgenden Liste dargestellt.

// Thermometer.cpp
...
namespace winrt::ThermometerWRC::implementation
{
    void Thermometer::AdjustTemperature(float deltaFahrenheit)
    {
        m_temperatureFahrenheit += deltaFahrenheit;
    }
}

Du siehst eine static_assert-Deklaration am Anfang von Thermometer.h und Thermometer.cpp, die du entfernen musst. Jetzt wird das Projekt erstellt.

Sollte die Erstellung aufgrund von Warnungen nicht möglich sein, behebe entweder die Ursachen, oder lege die Projekteigenschaft C/C++>Allgemein>Warnungen als Fehler behandeln auf Nein (/WX-) fest, und erstelle das Projekt erneut.

Erstellen einer Core-App (ThermometerCoreApp) zum Testen der Windows-Runtime Komponente

Erstellen Sie nun ein neues Projekt (entweder in Ihrer ThermometerWRC-Lösung oder in einem neuen Projekt). Erstellen Sie ein Core App-Projekt (C++/WinRT), und nennen Sie es ThermometerCoreApp. Legen Sie ThermometerCoreApp als Startprojekt fest, wenn sich die beiden Projekte in derselben Projektmappe befinden.

Hinweis

Wie bereits erwähnt, wird die Windows-Runtime Metadatendatei für Ihre Windows-Runtime-Komponente (deren Projekt Sie ThermometerWRC genannt haben) im Ordner \ThermometerWRC\Debug\ThermometerWRC\erstellt. Das erste Segment dieses Pfads ist der Name des Ordners, der die Projektmappendatei enthält, das nächste Segment ist dessen Unterverzeichnis namens Debug, das letzte Segment ist das Unterverzeichnis, das nach der Komponente für Windows-Runtime benannt ist. Wenn Sie Ihr Projekt nicht ThermometerWRC nennen, befindet sich Ihre Metadatendatei im Ordner \<YourProjectName>\Debug\<YourProjectName>\.

Fügen Sie nun in Ihrem Core-App-Projekt (ThermometerCoreApp) einen Verweis hinzu, und navigieren Sie zu \ThermometerWRC\Debug\ThermometerWRC\ThermometerWRC.winmd (oder fügen Sie einen Projekt-zu-Projekt-Verweis hinzu, wenn sich die beiden Projekte in derselben Projektmappe befinden). Klicke auf Hinzufügen und anschließend auf OK. Erstellen Sie jetzt ThermometerCoreApp. In dem unwahrscheinlichen Fall, dass ein Fehler angezeigt wird, dass die Nutzlastdatei readme.txt nicht vorhanden ist, schließen Sie diese Datei aus dem Windows-Runtime Komponentenprojekt aus, erstellen Sie sie neu, und erstellen Sie dann ThermometerCoreApp neu.

Während des Buildprozesses wird das Tool cppwinrt.exe ausgeführt, um die referenzierte Datei vom Typ .winmd zu Quellcodedateien mit projizierten Typen zu verarbeiten, die dich bei der Nutzung deiner Komponente unterstützen. Der Header für die projizierten Typen für die Laufzeitklassen Ihrer Komponente – genannt ThermometerWRC.h– wird im Ordner \ThermometerCoreApp\ThermometerCoreApp\Generated Files\winrt\generiert.

Schließe diesen Header in App.cpp ein.

// App.cpp
...
#include <winrt/ThermometerWRC.h>
...

Fügen Sie auch in App.cppden folgenden Code hinzu, um ein Thermometer-Objekt zu instanziieren (mit dem Standardkonstruktor des projizierten Typs), und rufen Sie eine Methode für das Thermometerobjekt auf.

struct App : implements<App, IFrameworkViewSource, IFrameworkView>
{
    ThermometerWRC::Thermometer m_thermometer;
    ...
    
    void OnPointerPressed(IInspectable const &, PointerEventArgs const & args)
    {
        m_thermometer.AdjustTemperature(1.f);
        ...
    }
    ...
};

Jedes Mal, wenn Sie auf das Fenster klicken, erhöhen Sie die Temperatur des Thermometerobjekts. Sie können Haltepunkte festlegen, wenn Sie den Code schrittweise durchlaufen möchten, um zu bestätigen, dass die Anwendung tatsächlich die Windows-Runtime-Komponente aufruft.

Nächste Schritte

Um Ihrer C++/WinRT- Windows-Runtime-Komponente noch mehr Funktionalität oder neue Windows-Runtime-Typen hinzuzufügen, können Sie die oben gezeigten Muster befolgen. Verwenden Sie zunächst IDL, um die Funktionalität zu definieren, die Sie verfügbar machen möchten. Erstellen Sie dann das Projekt in Visual Studio, um eine Stubimplementierung zu generieren. Und schließen Sie dann die Implementierung nach Bedarf ab. Alle Methoden, Eigenschaften und Ereignisse, die Sie in IDL definieren, sind für die Anwendung sichtbar, die Ihre Windows-Runtime-Komponente nutzt. Weitere Informationen zu IDL finden Sie unter Einführung in die Microsoft-Schnittstellendefinitionssprache 3.0.

Ein Beispiel zum Hinzufügen eines Ereignisses zu Ihrer Windows-Runtime-Komponente finden Sie unter Erstellen von Ereignissen in C++/WinRT.

Problembehandlung

Symptom Problembehandlung
Wenn in einer C++/WinRT-App eine C#-Komponente für Windows-Runtime, die XAML verwendet, verarbeitet wird, erzeugt der Compiler einen Fehler der Form „'MyNamespace_XamlTypeInfo': is not a member of 'winrt::MyNamespace'“, wobei MyNamespace der Name des Namespace der Windows Runtime-Komponente ist. Fügen Sie in pch.h in der verarbeitenden C++/WinRT-App #include <winrt/MyNamespace.MyNamespace_XamlTypeInfo.h> hinzu, und ersetzen Sie MyNamespace entsprechend.