デスクトップ アプリで Windows ランタイム API を呼び出す

このトピックでは、Windows OS によって提供される Windows ランタイム (WinRT) API を使用するようにデスクトップ アプリ プロジェクトを設定し、最新の Windows 11 および Windows 10 エクスペリエンスをデスクトップ アプリに追加する方法について説明します。

一部の Windows ランタイム (WinRT) API は、デスクトップ アプリでサポートされていません。 詳しくは、「デスクトップ アプリで使用できる Windows ランタイム API」をご覧ください。

Windows ランタイム API を使用するように .NET プロジェクトを変更する

.NET プロジェクトには、次のいくつかのオプションがあります。

  • .NET 6 以降では、プロジェクト ファイルのターゲット フレームワーク モニカー (TFM) を指定して、WinRT API にアクセスできます。 このオプションは、Windows 10 Version 1809 以降をターゲットとするプロジェクトでサポートされています。
  • それ以前のバージョンの .NET では、Microsoft.Windows.SDK.Contracts NuGet パッケージをインストールして、プロジェクトに必要なすべての参照を追加できます。 このオプションは、Windows 10 Version 1803 以降をターゲットとするプロジェクトでサポートされています。
  • プロジェクトが、.NET 6 以降とそれより前のバージョンの .NET の両方をターゲットとする場合は、両方のオプションを使用するようにプロジェクト ファイルを構成できます。

.NET 6 以降: ターゲット フレームワーク モニカー オプションの使用

このオプションは、.NET 6 以降を使用し、Windows 10 バージョン 1809 以降の OS リリースをターゲットとするプロジェクトでのみサポートされています。 プロジェクト ファイルに Windows OS バージョン固有の TFM を指定すると、適切な Windows SDK ターゲット パッケージに参照が追加されます。 このシナリオの詳細な背景情報については、ブログ記事「.NET での Windows API の呼び出し」を参照してください。

  1. Visual Studio 上でプロジェクトを開いた状態で、ソリューション エクスプローラーでプロジェクトを右クリックし、 [プロジェクト ファイルの編集] を選択します。 プロジェクト ファイルの内容は次のようになります。

    Note

    次の例は、WinExeOutputType を示しています。これにより、Windows GUI 実行可能ファイルが指定されます (アプリが実行されるときにコンソール ウィンドウが開かないようにします)。 アプリに GUI がない場合、OutputType は別の値になります。 Windows GUI アプリ、コンソール アプリ、およびライブラリから WinRT API を呼び出すことができます。 また、TargetFramework の値は以下の例と完全に一致しない場合もあります。

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>net5.0</TargetFramework>
      </PropertyGroup>
    </Project>
    
  2. 他のすべての設定はそのままにして、TargetFramework 要素の値を、次のいずれかの文字列に置き換えます。

    • net6.0-windows10.0.17763.0: アプリが Windows 10 バージョン 1809 をターゲットとしている場合。
    • net6.0-windows10.0.18362.0: アプリが Windows 10 バージョン 1903 をターゲットとしている場合。
    • net6.0-windows10.0.19041.0: アプリが Windows 10 バージョン 2004 をターゲットとしている場合。
    • net6.0-windows10.0.22000.0: アプリが Windows 11 をターゲットとしている場合。

    たとえば、次の要素は Windows 10 Version 2004 をターゲットとするプロジェクト用です。

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

    .NET の今後のバージョンでは、値を net6.0-windows10.0.19041.0 など、該当するバージョンに置き換えることができます。

  3. 変更を保存し、プロジェクト ファイルを閉じます。

.NET 6 以降ではサポートされていない WinRT API

.NET 6 以降では、Windows.UI 名前空間のいくつかの Windows ランタイム (WinRT) API がサポートされていません。 以下に示す API の場合、同等のバージョンの API が WinUI (Microsoft.UI) 名前空間に存在します ( Microsoft.UI.Text など)。 次の WinRT API は、.NET 6 以降ではサポートされて "いません"。

  • Windows.UI.Colors クラス
  • Windows.UI.ColorHelper クラス
  • Windows.UI.Text (Windows.UI.Text.FontStretchWindows.UI.Text.FontStyleWindows.UI.Text.FontWeightWindows.UI.Text.UnderlineType除くこの名前空間のすべてのクラス、および Windows.UI.Text.Core 名前空間のすべてのクラス)
  • Windows.UI.Xaml (この名前空間のすべてのクラス)

複数の Windows OS バージョンのサポート

Windows OS バージョン固有の TargetFramework プロパティによって、アプリのコンパイルに使用する Windows SDK のバージョンが決まります。 このプロパティは、ビルド時にアクセス可能な一連の API を決定し、TargetPlatformVersion および TargetPlatformMinVersion の両方に既定値を指定します (明示的に設定されない場合)。 TargetPlatformVersion プロパティは、TargetFramework OS バージョンによって自動的に設定されるため、プロジェクト ファイル内で明示的に定義する必要はありません。

TargetPlatformMinVersion は、オーバーライドして、TargetPlatformVersion よりも小さくすることができます (TargetFramework プロパティでのバージョンによって決定)。 これにより、アプリを以前のバージョンの OS で実行できるようになります。 たとえば、プロジェクト ファイルで次のように設定して、アプリの Windows 10 Version 1809 へのダウンレベルに対応することができます。

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

TargetPlatformMinVersionTargetPlatformVersion より下のバージョンに設定すると、利用できない API を呼び出す可能性があることに注意してください。 サポートされているすべての OS バージョンで使用できない WinRT API を呼び出す場合は、ApiInformation チェックを使用してこれらの呼び出しを防ぐことをお勧めします。 詳しくは、「バージョン アダプティブ アプリ」をご覧ください。

以前のバージョンの .NET:Microsoft.Windows.SDK.Contracts NuGet パッケージをインストールする

このオプションは、アプリで .NET Core 3.x または .NET Framework を使用する場合に使用します。 このオプションは、Windows 10 Version 1803 以降をターゲットとするプロジェクトでサポートされています。

  1. パッケージ参照が有効になっていることを確認します。

    1. Visual Studio で、[ツール] -> [NuGet パッケージ マネージャー] -> [パッケージ マネージャー設定] の順にクリックします。
    2. [既定のパッケージ管理形式][PackageReference] が選択されていることを確認します。
  2. Visual Studio 上でプロジェクトを開いた状態で、ソリューション エクスプローラーでプロジェクトを右クリックし、 [NuGet パッケージの管理] を選択します。

  3. [NuGet パッケージ マネージャー] ウィンドウで、 [参照] タブを選択して、Microsoft.Windows.SDK.Contracts を検索します。

  4. Microsoft.Windows.SDK.Contracts パッケージが見つかったら、 [NuGet パッケージ マネージャー] ウィンドウの右側のペインで、ターゲットにする Windows 10 のバージョンに基づいて、インストールするパッケージのバージョンを選択します。

    • 10.0.19041.xxxx:Windows 10 Version 2004 の場合は、これを選択します。
    • 10.0.18362.xxxx:Windows 10 バージョン 1903 の場合は、これを選択します。
    • 10.0.17763.xxxx:Windows 10 バージョン 1809 の場合は、これを選択します。
    • 10.0.17134.xxxx:Windows 10 バージョン 1803 の場合は、これを選択します。
  5. [インストール] をクリックします。

複数の異なるバージョンの .NET をターゲットとするプロジェクトを構成する

プロジェクトが、.NET 6 以降とそれより前のバージョン (.NET Core 3.x と .NET Framework を含む) の両方をターゲットとする場合は、ターゲット フレームワーク モニカー (TFM) を使用することにより、.NET 6 以降には WinRT API 参照を自動的に取り込み、それより前のバージョンには Microsoft.Windows.SDK.Contracts NuGet パッケージを使用するようにプロジェクト ファイルを構成できます。

  1. Visual Studio 上でプロジェクトを開いた状態で、ソリューション エクスプローラーでプロジェクトを右クリックし、 [プロジェクト ファイルの編集] を選択します。 次に、.NET Core 3.1 を使用するアプリ用のプロジェクト ファイルの例を示します。

    Note

    次の例は、WinExeOutputType を示しています。これにより、Windows GUI 実行可能ファイルが指定されます (アプリが実行されるときにコンソール ウィンドウが開かないようにします)。 アプリに GUI がない場合、OutputType は別の値になります。 Windows GUI アプリ、コンソール アプリ、およびライブラリから WinRT API を呼び出すことができます。 また、TargetFramework の値は以下の例と完全に一致しない場合もあります。

    <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
      <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>netcoreapp3.1</TargetFramework>
        <UseWindowsForms>true</UseWindowsForms>
      </PropertyGroup>
    </Project>
    
  2. ファイルの TargetFramework 要素を、TargetFrameworks 要素 (複数形であることに注意) に置き換えます。 この要素では、ターゲットとするすべてのバージョンの .NET について、ターゲット フレームワーク モニカー (TFM) をセミコロンで区切って指定します。

    • .NET 6 以降の場合は、次のいずれかのターゲット フレームワーク モニカー (TFM) を使用します。
      • net6.0-windows10.0.17763.0: アプリが Windows 10 バージョン 1809 をターゲットとしている場合。
      • net6.0-windows10.0.18362.0: アプリが Windows 10 バージョン 1903 をターゲットとしている場合。
      • net6.0-windows10.0.19041.0: アプリが Windows 10 バージョン 2004 をターゲットとしている場合。
    • .NET Core 3.x の場合は、netcoreapp3.0 または netcoreapp3.1 を使用します。
    • .NET Framework の場合は、net46 を使用します。

    次に、.NET Core 3.1 と .NET 6 の両方をターゲットとする方法の例を示します (Windows 10 バージョン 2004 の場合)。

    <TargetFrameworks>netcoreapp3.1;net6.0-windows10.0.19041.0</TargetFrameworks>
    
  3. PropertyGroup 要素の後ろに PackageReference 要素を追加します。ここには、アプリがターゲットとする任意のバージョンの .NET Core 3.x または .NET Framework 用の Microsoft.Windows.SDK.Contracts NuGet パッケージをインストールする条件付きステートメントを含めます。 PackageReference 要素は、ItemGroup 要素の子である必要があります。 次に、.NET Core 3.1 でこれを行う方法の例を示します。

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

    完了すると、プロジェクト ファイルの内容は次のようになります。

    <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. 変更を保存し、プロジェクト ファイルを閉じます。

Windows ランタイム API を使用するように C++ デスクトップ (Win32) プロジェクトを変更する

WinRT API を使用するには、C++/WinRT を使います。 C++/WinRT は WinRT API の標準的な最新の C++17 言語プロジェクションで、ヘッダー ファイル ベースのライブラリとして実装され、最新の Windows API への最上位アクセス権を提供するように設計されています。

C++/WinRT 用にプロジェクトを構成するには:

  • 新しいプロジェクトの場合は、C++/WinRT Visual Studio 拡張機能 (VSIX) をインストールして、その拡張機能に含まれているいずれかの C++/WinRT プロジェクト テンプレートを使用できます。
  • 既存のプロジェクトの場合は、Microsoft.Windows.CppWinRT NuGet パッケージをプロジェクトにインストールできます。

これらのオプションについての詳細は、「C++/WinRT の Visual Studio サポートと VSIX」をご覧ください。

Windows 10 エクスペリエンスの追加

これで、Windows 10 でアプリケーションをユーザーが実行する際に便利になる最新のエクスペリエンスを追加する準備ができました。 次の設計フローを使用します。

最初に、追加するエクスペリエンスを決定する

選択肢はたくさんあります。 たとえば、収益化 API を使用して発注フローを簡略化できます。また、別のユーザーが投稿した新しい写真など、共有すべき興味深いコンテンツがある場合に、アプリケーションへの注目を促すことができます。

Toast notification

ユーザーがメッセージを無視したり、非表示にした場合でも、ユーザーはアクション センターで再度メッセージを表示し、クリックすることで、アプリを開くことができます。 これにより、アプリケーションの利用度が高まります。さらに、アプリケーションがオペレーティング システムと密接に統合されているように見えるというメリットがあります。 この記事では、そのエクスペリエンスのコードについて後で少し紹介します。

詳細については、UWP のドキュメントを参照してください。

強化するのか、拡張するのかを決定する

マイクロソフトでは "強化" と "拡張" という用語をよく使用しています。ここで、少し時間を使って、これらの各用語が厳密にはどのような意味なのかを説明しましょう。

マイクロソフトでは、(アプリケーションを MSIX パッケージにパッケージ化することを選択したかどうかにかかわらず) デスクトップ アプリから直接呼び出すことができる WinRT API を表すために、"強化" という用語を使用します。 Windows 10 エクスペリエンスを選択した場合、その作成に必要な API を特定して、該当の API がこちらの一覧に示されているかどうかを確認します。 これは、デスクトップ アプリから直接呼び出すことができる API の一覧です。 API がこの一覧に表示されていない場合、その API に関連付けられている機能が UWP プロセス内でしか実行できないことが理由です。 多くの場合、これらには、UWP マップ コントロールや Windows Hello のセキュリティの確認など、UWP XAML をレンダリングする API が含まれます。

Note

UWP XAML をレンダリングする API は通常、デスクトップから直接呼び出すことはできませんが、別の方法を使用できる場合があります。 UWP XAML コントロールまたはその他のカスタム ビジュアル エクスペリエンスをホストする場合は、XAML Islands (Windows 10 バージョン 1903 以降) と ビジュアル レイヤー (Windows 10 バージョン 1803 以降) を使用できます。 これらの機能は、パッケージ化されているデスクトップ アプリでも、パッケージ化されていないデスクトップ アプリでも使用できます。

デスクトップ アプリを MSIX パッケージにパッケージ化することを選択した場合、別の方法として、UWP プロジェクトをソリューションに追加することで、アプリケーションを "拡張" することができます。 引き続きデスクトップ プロジェクトがアプリケーションのエントリ ポイントになりますが、UWP プロジェクトがあることで、こちらの一覧に示されていないすべての API を利用できるようになります。 デスクトップ アプリでは、アプリ サービスを利用して UWP プロセスと通信できます。そのセットアップ方法については、多数のガイダンスが用意されています。 UWP プロジェクトを必要とするエクスペリエンスを追加するには、UWP コンポーネントによる拡張に関する記事を参照してください。

API コントラクトを参照する

デスクトップ アプリから API を直接呼び出すことができる場合は、ブラウザーを開いて、その API のリファレンス トピックを検索します。 API の概要の下に、その API の API コントラクトを説明する表があります。 以下に表の例を示します。

API contract table

.NET ベースのデスクトップ アプリの場合、その API コントラクトへの参照を追加します。その後、そのファイルの [ローカルにコピー] プロパティを [False] に設定します。 C++ ベースのプロジェクトの場合、 [追加のインクルード ディレクトリ] に、このコントラクトを含むフォルダーのパスを追加します。

エクスペリエンスを追加するための API を呼び出す

以下に、前述の通知ウィンドウの表示に使用するコードを示します。 これらの API はこちらの一覧に示されているので、このコードをデスクトップ アプリに追加してすぐに実行できます。

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

通知の詳細については、「アダプティブ トースト通知と対話型トースト通知」を参照してください。

Windows XP、Windows Vista、および Windows 7/8 インストール ベースのサポート

新しいブランチを作成して個別のコード ベースを保守しなくても、Windows 10 向けにアプリケーションを最新化できます。

Windows 10 ユーザー向けに個別のバイナリをビルドする場合は、条件付きコンパイルを使用します。 すべての Windows ユーザーに対して 1 組のバイナリをビルドして展開する場合は、ランタイム チェックを使用します。

各オプションを簡単に見ていきましょう。

条件付きコンパイル

1 つのコードベースを維持して、Windows 10 ユーザー向けだけに一連のバイナリをコンパイルします。

最初に、新しいビルド構成をプロジェクトに追加します。

Build Configuration

このビルド構成に対して、WinRT API を呼び出すコードを識別する定数を作成します。

.NET ベースのプロジェクトの場合、この定数は条件付きコンパイル定数と呼ばれます。

Conditional Compilation constant

C++ ベースのプロジェクトの場合、この定数はプリプロセッサ定義と呼ばれます。

Preprocessor Definition constant

この定数を、任意の UWP コードのブロックの前に追加します。

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

この定数がアクティブなビルド構成で定義されている場合のみ、コンパイラでこのコードがビルドされます。

ランタイム チェック

ユーザーが実行する Windows のバージョンに関係なく、1 組のバイナリをすべての Windows ユーザー向けにコンパイルできます。 アプリケーションにより、ユーザーが Windows 10 上でアプリケーションをパッケージ化されたアプリケーションとして実行している場合にのみ、WinRT API が呼び出されます。

コードにランタイム チェックを追加する最も簡単な方法は、Desktop Bridge Helpers という Nuget パッケージをインストールしてから、IsRunningAsUWP() メソッドを使用して、WinRT API を呼び出すすべてのコードを利用することです。 詳細については、こちらのブログ投稿を参照してください。「デスクトップ ブリッジ - アプリケーションのコンテキストの識別」を参照してください。

質問に対する回答を見つける

ご質問があるでしょうか。 Stack Overflow でお問い合わせください。 Microsoft のチームでは、これらのタグをチェックしています。 フォーラムで質問することもできます。