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 die Erstellung einer Windows-Runtime Komponente in C++/WinRT.

  • Um den Leistungsvorteil von C++ in komplexen oder rechenintensiven Vorgängen zu genießen.
  • Um standardmäßigen C++-Code wiederzuverwenden, der bereits geschrieben und getestet wurde.
  • Um Win32-Funktionen für eine in Z. B. C# geschriebene Universelle Windows-Plattform -App (UWP) verfügbar zu machen.

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

Im restlichen Teil dieses Themas erfahren Sie, wie Sie eine Windows-Runtime Komponente in C++/WinRT erstellen und dann aus einer Anwendung nutzen können.

Die komponente Windows-Runtime, die Sie in diesem Thema erstellen, enthält eine Laufzeitklasse, die ein Thermometer darstellt. Das Thema zeigt auch eine Core-App, die die Thermometerlaufzeitklasse nutzt, und ruft eine Funktion auf, 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.

Benennung bewährter Methoden für Windows-Runtime Komponenten-DLLs

Wichtig

In diesem Abschnitt wird die Benennungskonvention beschrieben, die Sie für die Datei (DLL) verwenden, in die .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 zu finden, die direkt geladen werden soll. 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 des vollständigen Namespaces zu suchen, der erhalten bleibt. Wenn dies nicht gefunden wird, entfernen Sie den spezifischsten Segmentnamen, und wiederholen Sie den Vorgang.

Wenn die aktivierte Klasse beispielsweise einen vollqualifizierten Namen von Contoso.Instruments.ThermometerWRC.Thermometer aufweist und RoGetActivationFactory fehlschlägt, suchen wir zuerst 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 die Factory direkt abzurufen (und nicht 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 Vorgang ist vollständig automatisch – es ist keine Registrierung oder Werkzeug erforderlich. Wenn Sie eine Windows-Runtime Komponente erstellen, müssen Sie lediglich eine Benennungskonvention für Ihre DLLs verwenden, die mit dem soeben beschriebenen Prozess funktioniert. Und wenn Sie eine Windows-Runtime Komponente verwenden und diese nicht richtig benannt wird, 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(C++/WinRT)-Projekt, und nennen Sie es ThermometerWRC (für "Thermometer Windows-Runtime Komponente"). Stellen Sie 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 bietet 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 zurzeit nicht erstellt, aber das Erstellen ist jetzt hilfreich, da es die Quellcodedateien generiert, in denen Sie die Thermometer-Laufzeitklasse 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. Zu diesen Dateien gehören Stubs, um mit der Implementierung der Thermometer-Laufzeitklasse zu beginnen, 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. Fügen Thermometer.hSie in der Implementierung (nicht der Factoryimplementierung) des Thermometers ein neues privates Mitglied hinzu.

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

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

Thermometer.cppImplementieren Sie in der nachstehenden Auflistung die AdjustTemperature-Methode.

// 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 einer neuen Projektmappe). 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 Lösung 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 ThermometerWRC nicht benennen, befindet sich die 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 Lösung befinden). Klicke auf Hinzufügen und anschließend auf OK. Erstellen Sie jetzt ThermometerCoreApp. Im 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 ( benannt ThermometerWRC.h) wird in den Ordner \ThermometerCoreApp\ThermometerCoreApp\Generated Files\winrt\generiert.

Schließe diesen Header in App.cpp ein.

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

App.cppFügen Sie außerdem den folgenden Code hinzu, um ein Thermometerobjekt zu instanziieren (mithilfe des Standardkonstruktors 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 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 verwendet. Weitere Informationen zu IDL finden Sie in der Einführung in die Microsoft Interface Definition Language 3.0.

Ein Beispiel zum Hinzufügen eines Ereignisses zu Ihrer Windows-Runtime Component finden Sie unter Author-Ereignisse 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.