Windows-Runtime-APIs in Desktop-Apps aufrufen

In diesem Thema wird beschrieben, wie Sie Ihre Desktop-App-Projekte für die Verwendung der vom Windows-Betriebssystem bereitgestellten Windows-Runtime-APIs (WinRT) einrichten und Ihren Desktop-Apps moderne Windows 11- und Windows 10-Erfahrungen hinzufügen.

Einige Windows-Runtime-APIs (WinRT) werden in Desktop-Apps nicht unterstützt. Weitere Informationen finden Sie unter In Desktop-Apps nicht unterstützte Windows-Runtime-APIs.

Ändern eines .NET-Projekts für die Verwendung von Windows Runtime-APIs

Für .NET-Projekte bestehen mehrere Optionen:

  • Ab .NET 6 können Sie den Target Framework Moniker (TFM) in Ihrer Projektdatei angeben, um auf WinRT-APIs zuzugreifen. Diese Option wird in Projekten unterstützt, die auf Windows 10, Version 1809 oder höher, ausgerichtet sind.
  • Für frühere .NET-Versionen können Sie das NuGet-Paket Microsoft.Windows.SDK.Contracts installieren, um alle notwendigen Referenzen zu Ihrem Projekt hinzuzufügen. Diese Option wird in Projekten unterstützt, die auf Windows 10, Version 1803 oder höher, ausgerichtet sind.
  • Wenn Ihr Projekt auf mehrere Ziele ausgerichtet ist – .NET 6 (oder höher) und frühere Versionen von .NET – können Sie die Projektdatei so konfigurieren, dass beide Optionen verwendet werden (Multi-Targeting).

.NET 6 und höher: Verwenden der Option Target Framework Moniker

Diese Option wird nur in Projekten unterstützt, die .NET 6 (oder höher) verwenden und auf Windows 10, Version 1809, oder ein späteres Release des Betriebssystems ausgerichtet sind. Durch Angeben eines für eine Windows-Betriebssystemversion spezifischen TFM in der Projektdatei wird dem entsprechenden Windows SDK-Zielpaket ein Verweis hinzugefügt. Weitere Hintergrundinformationen zu diesem Szenario finden Sie im Blogbeitrag Aufrufen von Windows APIs in .NET.

  1. Klicken Sie bei in Visual Studio geöffnetem Projekt mit der rechten Maustaste im Projektmappen-Explorer auf das Projekt, und wählen Sie Projektdatei bearbeiten aus. Ihre Projektdatei sieht etwa wie folgt aus.

    Hinweis

    Das folgende Beispiel zeigt einen Ausgabetyp (OutputType) von WinExe, der eine ausführbare Windows-GUI-Datei angibt (und verhindert, dass ein Konsolenfenster geöffnet wird, wenn die App ausgeführt wird). Wenn Ihre App über keine grafische Benutzeroberfläche verfügt, weist Ihr OutputType-Objekt einen anderen Wert auf. Sie können WinRT-APIs über Windows GUI-Apps, Konsolen-Apps und Bibliotheken aufrufen. Außerdem stimmt ihr Wert für TargetFramework möglicherweise nicht exakt mit dem folgenden Beispiel überein.

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>net5.0</TargetFramework>
      </PropertyGroup>
    </Project>
    
  2. Lassen Sie alle anderen Einstellungen unverändert, und ersetzen Sie nur den Wert des TargetFramework-Elements durch eine der folgenden Zeichenfolgen:

    • net6.0-windows10.0.17763.0: Wenn das Ziel Ihrer App Windows 10, Version 1809, ist.
    • net6.0-windows10.0.18362.0: Wenn das Ziel Ihrer App Windows 10, Version 1903, ist.
    • net6.0-windows10.0.19041.0: Wenn das Ziel Ihrer App Windows 10, Version 2004, ist.
    • net6.0-windows10.0.22000.0: Wenn das Ziel Ihrer App Windows 11 ist.

    Das folgende Element ist zum Beispiel für ein Projekt bestimmt, das auf Windows 10, Version 2004, ausgerichtet ist.

    <TargetFramework>net6.0-windows10.0.19041.0</TargetFramework>
    

    In späteren Versionen von .NET können Sie den Wert durch die entsprechende Version ersetzen, z. B. net6.0-windows10.0.19041.0.

  3. Speichern Sie Ihre Änderungen, und schließen Sie die Projektdatei.

In .NET 6 oder höher nicht unterstützte WinRT-APIs

In .NET 6 und höher gibt es mehrere WinRT-APIs (Windows Runtime) im Namespace Windows.UI, die nicht unterstützt werden. Für die unten aufgeführten APIs gibt es entsprechende Versionen der APIs im WinUI-Namespace (Microsoft.UI): z. B. Microsoft.UI.Text. Die folgenden WinRT-APIs werden in .NET 6 und höher nicht unterstützt:

Unterstützen mehrerer Windows-Betriebssystemversionen

Die für die Windows-Betriebssystemversion spezifische TargetFramework-Eigenschaft bestimmt, mit welcher Windows SDK-Version Ihre App kompiliert wird. Diese Eigenschaft bestimmt den Satz der verfügbaren APIs zur Buildzeit und stellt Standardwerte für TargetPlatformVersion und TargetPlatformMinVersion (sofern nicht explizit festgelegt) zur Verfügung. Die Eigenschaft TargetPlatformVersion muss nicht explizit in der Projektdatei definiert werden, da sie automatisch von der TargetFramework-Eigenschaft der Betriebssystemversion festgelegt wird.

TargetPlatformMinVersion kann auf einen kleineren Wert als targetPlatformVersion überschrieben werden (bestimmt durch die Version in der TargetFramework-Eigenschaft). Dadurch kann eine App unter früheren Betriebssystemversionen ausgeführt werden. Sie können z. B. Folgendes in Ihrer Projektdatei festlegen, damit Ihre App die Vorgängerversion Windows 10, Version 1809, unterstützt.

<Project Sdk="Microsoft.NET.Sdk">
 <PropertyGroup>
   <OutputType>WinExe</OutputType>
   <TargetFramework>net6.0-windows10.0.19041.0</TargetFramework>
   <TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
 </PropertyGroup>
</Project>

Beachten Sie, dass durch das Festlegen von TargetPlatformMinVersion auf eine Version unter TargetPlatformVersion die Möglichkeit entsteht, nicht verfügbare APIs aufzurufen. Beim Aufrufen von WinRT-APIs, die nicht in allen unterstützten Betriebssystemversionen verfügbar sind, wird empfohlen, diese Aufrufe mit ApiInformation-Überprüfungen zu schützen. Weitere Informationen finden Sie unter Versionsadaptive Apps.

Frühere .NET-Versionen: Installieren Sie das NuGet-Paket „Microsoft.Windows.SDK.Contracts“.

Verwenden Sie diese Option, wenn Ihre Anwendung .NET Core 3.x oder .NET Framework verwendet. Diese Option wird in Projekten unterstützt, die auf Windows 10, Version 1803 oder höher, ausgerichtet sind.

  1. Vergewissern Sie sich, dass Paketverweise aktiviert sind:

    1. Klicken Sie in Visual Studio auf Extras > NuGet-Paket-Manager > Paket-Manager-Einstellungen.
    2. Achten Sie darauf, dass die Einstellung Standardformat für Paketverwaltung auf PackageReference festgelegt ist.
  2. Klicken Sie bei in Visual Studio geöffnetem Projekt mit der rechten Maustaste im Projektmappen-Explorer auf das Projekt, und wählen Sie NuGet-Pakete verwalten aus.

  3. Wählen Sie im Fenster NuGet-Paket-Manager die Registerkarte Durchsuchen aus, und suchen Sie nach Microsoft.Windows.SDK.Contracts.

  4. Nachdem Sie das Microsoft.Windows.SDK.Contracts-Paket gefunden haben, wählen Sie im rechten Bereich des NuGet-Paket-Manager-Fensters die Version des Pakets aus, das Sie installieren möchten, ausgehend von der Windows 10-Version, die Sie als Zielplattform festlegen möchten:

    • 10.0.19041.xxxx: Wählen Sie dies für Windows 10, Version 2004.
    • 10.0.18362.xxxx: Wählen Sie dies für Windows 10, Version 1903.
    • 10.0.17763.xxxx: Wählen Sie dies für Windows 10, Version 1809.
    • 10.0.17134.xxxx: Wählen Sie dies für Windows 10, Version 1803.
  5. Klicken Sie auf Installieren.

Konfigurieren von Projekten, die auf verschiedene Versionen von .NET ausgerichtet sind (Multi-Targeting)

Wenn Ihr Projekt auf mehrere Ziele ausgerichtet ist – .NET 6 (oder höher) sowie frühere Versionen (beispielweise .NET Core 3.x und .NET Framework) – können Sie die Projektdatei so konfigurieren, dass der Target Framework Moniker (TFM) verwendet wird, um die WinRT-API-Referenzen für .NET 6 (oder höher) automatisch per Pull abzurufen und das Microsoft.Windows.SDK.ContractsNuGet-Paket für frühere Versionen zu verwenden.

  1. Klicken Sie bei in Visual Studio geöffnetem Projekt mit der rechten Maustaste im Projektmappen-Explorer auf das Projekt, und wählen Sie Projektdatei bearbeiten aus. Das folgende Beispiel zeigt eine Projektdatei für eine App, die .NET Core 3.1 verwendet.

    Hinweis

    Das folgende Beispiel zeigt einen Ausgabetyp (OutputType) von WinExe, der eine ausführbare Windows-GUI-Datei angibt (und verhindert, dass ein Konsolenfenster geöffnet wird, wenn die App ausgeführt wird). Wenn Ihre App über keine grafische Benutzeroberfläche verfügt, weist Ihr OutputType-Objekt einen anderen Wert auf. Sie können WinRT-APIs über Windows GUI-Apps, Konsolen-Apps und Bibliotheken aufrufen. Außerdem stimmt ihr Wert für TargetFramework möglicherweise nicht exakt mit dem folgenden Beispiel überein.

    <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
      <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>netcoreapp3.1</TargetFramework>
        <UseWindowsForms>true</UseWindowsForms>
      </PropertyGroup>
    </Project>
    
  2. Ersetzen Sie das TargetFramework-Element in der Datei durch ein TargetFrameworks-Element (beachten Sie den Plural). Geben Sie in diesem Element die Zielframeworkmoniker (TFMs) für alle Versionen von .NET an, die Sie als Ziel verwenden möchten, getrennt durch Semikolons.

    • Für .NET 6 oder höher verwenden Sie einen der folgenden Target Framework Monikers (TFMs):
      • net6.0-windows10.0.17763.0: Wenn das Ziel Ihrer App Windows 10, Version 1809, ist.
      • net6.0-windows10.0.18362.0: Wenn das Ziel Ihrer App Windows 10, Version 1903, ist.
      • net6.0-windows10.0.19041.0: Wenn das Ziel Ihrer App Windows 10, Version 2004, ist.
    • Verwenden Sie für .NET Core 3.x netcoreapp3.0 oder netcoreapp3.1.
    • Verwenden Sie für .NET Framework net46.

    Das folgende Beispiel veranschaulicht, wie .NET Core 3.1 und .NET 6 (für Windows 10, Version 2004) auf mehrere Ziele ausgerichtet werden können.

    <TargetFrameworks>netcoreapp3.1;net6.0-windows10.0.19041.0</TargetFrameworks>
    
  3. Fügen Sie nach dem PropertyGroup-Element ein PackageReference-Element hinzu, das eine bedingte Anweisung enthält, die das NuGet-Paket Microsoft.Windows.SDK.Contracts für alle Versionen von .NET Core 3.x oder .NET Framework installiert, auf die Ihre App ausgerichtet ist. Das PackageReference-Element muss ein untergeordnetes Element des ItemGroup-Elements sein. Das folgende Beispiel veranschaulicht die Vorgehensweise für .NET Core 3.1.

    <ItemGroup>
      <PackageReference Condition="'$(TargetFramework)' == 'netcoreapp3.1'"
                        Include="Microsoft.Windows.SDK.Contracts"
                        Version="10.0.19041.0" />
    </ItemGroup>
    

    Wenn Sie fertig sind, sollte Ihre Projektdatei etwa wie folgt aussehen.

    <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
      <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFrameworks>netcoreapp3.1;net6.0-windows10.0.19041.0</TargetFrameworks>
        <UseWPF>true</UseWPF>
      </PropertyGroup>
      <ItemGroup>
        <PackageReference Condition="'$(TargetFramework)' == 'netcoreapp3.1'"
                         Include="Microsoft.Windows.SDK.Contracts"
                         Version="10.0.19041.0" />
      </ItemGroup>
    </Project>
    
  4. Speichern Sie Ihre Änderungen, und schließen Sie die Projektdatei.

Ändern eines C++-Desktop (Win32)-Projekts für die Verwendung von Windows-Runtime-APIs

Verwenden Sie C++/WinRT, um WinRT-APIs zu nutzen. C++/WinRT ist eine vollständig standardisierte, moderne C++17-Programmiersprache für WinRT-APIs, die als headerdateibasierte Bibliothek implementiert ist und Ihnen einen erstklassigen Zugriff auf die moderne Windows-API bietet.

Konfigurieren Ihres Projekts für C++/WinRT:

Weitere Informationen zu diesen Optionen finden Sie unter Visual Studio-Unterstützung für C++/WinRT und VSIX.

Hinzufügen von Windows 10-Funktionen

Jetzt sind Sie bereit, moderne Funktionen hinzuzufügen, die sichtbar werden, wenn Benutzer Ihre Anwendung unter Windows 10 ausführen. Verwenden Sie diesen Entwurfsablauf.

Entscheiden Sie zunächst, welche Funktionen Sie hinzufügen möchten

Es stehen viele zur Auswahl. Beispielsweise können Sie mithilfe von Monetisierungs-APIs den Kaufablauf vereinfachen oder mehr Aufmerksamkeit für Ihre Anwendung generieren, wenn Sie etwas Interessantes zu teilen haben, etwa ein neues Bild, das ein anderer Benutzer gepostet hat.

Toast notification

Auch dann, wenn Benutzer Ihre Nachricht ignorieren oder schließen, können sie diese im Info-Center anzeigen und dann auf die Nachricht klicken, um Ihre App zu öffnen. Dies erhöht die Interaktion mit Ihrer Anwendung und hat den zusätzlichen Vorteil, das Sie die Anwendung tief in das Betriebssystem integrieren. Wir zeigen Ihnen den Code für diese Funktion weiter unten in diesem Artikel.

Weitere Ideen finden Sie in der UWP-Dokumentation.

Entscheiden Sie, ob Sie die App verbessern oder erweitern möchten

Wir verwenden häufig die Begriffe verbessern und erweitern. Daher möchten wir erklären, was diese Begriffe bedeuten.

Wir verwenden den Begriff verbessern, um WinRT-APIs zu beschreiben, die Sie direkt über Ihre Desktop-App aufrufen können, unabhängig davon, ob es sich um ein App-Paket handelt. Wenn Sie eine Windows 10-Funktion ausgewählt haben, identifizieren Sie die APIs, die Sie benötigen, um sie zu erstellen. Überprüfen Sie dann, ob die API in dieser Liste aufgeführt wird. Hierbei handelt es sich um eine Liste der APIs, die Sie direkt aus Ihrer Desktopanwendung aufrufen können. Wenn Ihre API nicht in dieser Liste aufgeführt ist, kann die Funktionalität der zugeordneten API nur in einem UWP-Prozess ausgeführt werden. Oftmals sind dies APIs, die UWP XAML rendern, etwa ein UWP-Kartensteuerelement oder eine Windows Hello-Sicherheitsaufforderung.

Hinweis

Zwar können APIs, die UWP XAML rendern, normalerweise nicht direkt aus Ihrer Desktopanwendung aufgerufen werden, möglicherweise können Sie aber alternative Vorgehensweisen verwenden. Wenn Sie UWP-XAML-Steuerelemente oder andere benutzerdefinierte visuelle Funktionen hosten möchten, können Sie XAML Islands (ab Windows 10, Version 1903) und die visuelle Ebene (ab Windows 10, Version 1803) verwenden. Diese Features können in verpackten oder unverpackten Desktop-Apps verwendet werden.

Wenn Sie sich dafür entschieden haben, Ihre Desktop-App zu verpacken, besteht eine weitere Möglichkeit darin, die Anwendung zu erweitern, indem Sie Ihrer Projektmappe ein UWP-Projekt hinzufügen. Das Desktop-Projekt bildet immer noch den Einstiegspunkt der Anwendung, aber das UWP-Projekt ermöglicht den Zugriff auf alle APIs, die nicht in dieser Liste aufgeführt sind. Die Desktopanwendung kann mithilfe eines App-Diensts mit dem UWP-Prozess kommunizieren. Wir stellen zahlreiche Anleitungen zum Einrichten dieser Kommunikation bereit. Wenn Sie eine Funktion hinzufügen möchten, die ein UWP-Projekt erfordert, finden Sie unter Erweitern mit UWP-Komponenten weitere Informationen.

Verweisen auf API-Verträge

Wenn Sie die API direkt aus Ihrer Desktopanwendung aufrufen können, öffnen Sie einen Browser, und suchen Sie nach dem Verweisthema für diese API. Unterhalb der Zusammenfassung der API finden Sie eine Tabelle, die den API-Vertrag für diese API beschreibt. Hier sehen Sie ein Beispiel für diese Tabelle:

API contract table

Wenn Sie eine .NET-basierte Desktop-App haben, fügen Sie einen Verweis auf den API-Vertrag hinzu, und legen Sie dann die Eigenschaft Lokale Kopie dieser Datei auf Falsch fest. Wenn Sie ein C++-basiertes Projekt haben, fügen Sie Ihren Zusätzlichen Include-Verzeichnissen einen Pfad zu dem Ordner hinzu, der diesen Vertrag enthält.

Aufrufen der APIs, um die Funktion hinzuzufügen

Dies ist der Code, den Sie verwenden würden, um das Benachrichtigungsfenster anzuzeigen, das wir weiter oben behandelt haben. Diese APIs werden in dieser Liste aufgeführt, d. h. Sie können Ihrer Desktopanwendung diesen Code hinzufügen und ihn sofort ausführen.

using Windows.Foundation;
using Windows.System;
using Windows.UI.Notifications;
using Windows.Data.Xml.Dom;
...

private void ShowToast()
{
    string title = "featured picture of the day";
    string content = "beautiful scenery";
    string image = "https://picsum.photos/360/180?image=104";
    string logo = "https://picsum.photos/64?image=883";

    string xmlString =
    $@"<toast><visual>
       <binding template='ToastGeneric'>
       <text>{title}</text>
       <text>{content}</text>
       <image src='{image}'/>
       <image src='{logo}' placement='appLogoOverride' hint-crop='circle'/>
       </binding>
      </visual></toast>";

    XmlDocument toastXml = new XmlDocument();
    toastXml.LoadXml(xmlString);

    ToastNotification toast = new ToastNotification(toastXml);

    ToastNotificationManager.CreateToastNotifier().Show(toast);
}
#include <sstream>
#include <winrt/Windows.Data.Xml.Dom.h>
#include <winrt/Windows.UI.Notifications.h>

using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::System;
using namespace winrt::Windows::UI::Notifications;
using namespace winrt::Windows::Data::Xml::Dom;

void UWP::ShowToast()
{
    std::wstring const title = L"featured picture of the day";
    std::wstring const content = L"beautiful scenery";
    std::wstring const image = L"https://picsum.photos/360/180?image=104";
    std::wstring const logo = L"https://picsum.photos/64?image=883";

    std::wostringstream xmlString;
    xmlString << L"<toast><visual><binding template='ToastGeneric'>" <<
        L"<text>" << title << L"</text>" <<
        L"<text>" << content << L"</text>" <<
        L"<image src='" << image << L"'/>" <<
        L"<image src='" << logo << L"'" <<
        L" placement='appLogoOverride' hint-crop='circle'/>" <<
        L"</binding></visual></toast>";

    XmlDocument toastXml;

    toastXml.LoadXml(xmlString.str().c_str());

    ToastNotificationManager::CreateToastNotifier().Show(ToastNotification(toastXml));
}
using namespace Windows::Foundation;
using namespace Windows::System;
using namespace Windows::UI::Notifications;
using namespace Windows::Data::Xml::Dom;

void UWP::ShowToast()
{
	Platform::String ^title = "featured picture of the day";
	Platform::String ^content = "beautiful scenery";
	Platform::String ^image = "https://picsum.photos/360/180?image=104";
	Platform::String ^logo = "https://picsum.photos/64?image=883";

	Platform::String ^xmlString =
		L"<toast><visual><binding template='ToastGeneric'>" +
		L"<text>" + title + "</text>" +
		L"<text>"+ content + "</text>" +
		L"<image src='" + image + "'/>" +
		L"<image src='" + logo + "'" +
		L" placement='appLogoOverride' hint-crop='circle'/>" +
		L"</binding></visual></toast>";

	XmlDocument ^toastXml = ref new XmlDocument();

	toastXml->LoadXml(xmlString);

	ToastNotificationManager::CreateToastNotifier()->Show(ref new ToastNotification(toastXml));
}

Weitere Informationen zu Benachrichtigungen finden Sie unter Adaptive und interaktive Popupbenachrichtigungen.

Unterstützung der Windows XP-, Windows Vista- und Windows 7/8-Installationsbasis

Sie können Ihre Anwendung für Windows 10 modernisieren, ohne einen neuen Branch zu erstellen und eine separate Codebasis verwalten zu müssen.

Wenn Sie separate Binärdateien für Windows 10-Benutzer erstellen möchten, verwenden Sie bedingte Kompilierung. Wenn Sie einen Satz von Binärdateien für alle Windows-Benutzer erstellen möchten, verwenden Sie Laufzeitprüfungen.

Sehen wir uns beide Optionen kurz an.

Bedingte Kompilierung

Sie können eine Codebasis beibehalten und einen Satz Binärdateien nur für Windows 10-Benutzer kompilieren.

Fügen Sie Ihrem Projekt zunächst eine neue Buildkonfiguration hinzu.

Build Configuration

Erstellen Sie für diese Buildkonfiguration eine Konstante, um den Code zu identifizieren, der WinRT-APIs aufruft.

Bei .NET-basierten Projekten heißt die Konstante Bedingte Kompilierungskonstante.

Conditional Compilation constant

Für C++ basierte Projekte wird die Konstante als Präprozessordefinition bezeichnet.

Preprocessor Definition constant

Fügen Sie diese Konstante vor jedem UWP-Codeblock hinzu.

[System.Diagnostics.Conditional("_UWP")]
private void ShowToast()
{
 ...
}
#if _UWP
void UWP::ShowToast()
{
 ...
}
#endif

Der Compiler erstellt den Code nur dann, wenn die Konstante in der aktiven Buildkonfiguration definiert ist.

Laufzeitüberprüfungen

Sie können einen Satz von Binärdateien für alle Windows-Benutzer kompilieren, unabhängig davon, welche Version von Windows sie ausführen. Ihre Anwendung ruft WinRT-APIs nur dann auf, wenn der Benutzer Ihre Anwendung als verpackte Anwendung unter Windows 10 ausführt.

Die einfachste Methode zum Hinzufügen von Laufzeitprüfungen zum Code ist die Installation des Nuget-Pakets Desktop Bridge Helpers und die Verwendung der IsRunningAsUWP()-Methode, um den ganzen Code abzugrenzen, der WinRT-APIs aufruft. Weitere Informationen finden Sie in diesem Blogbeitrag: Desktop Bridge: Identifizieren des Anwendungskontexts.

Antworten auf Ihre Fragen

Haben Sie Fragen? Frage uns auf Stack Overflow. Unser Team überwacht diese Tags. Sie können Ihre Fragen auch in unseren Foren stellen.