C++ デスクトップ (Win32) アプリでカスタム WinRT XAML コントロールをホストする

重要

このトピックでは、CommunityToolkit/Microsoft.Toolkit.Win32 GitHub リポジトリの型について使用または言及します。 XAML Islands のサポートに関する重要な情報については、そのリポジトリの XAML Islands に関する通知を参照してください。

この記事では、WinRT XAML ホスティング API を使用して、新しい C++ デスクトップ アプリでカスタム WinRT XAML コントロールをホストする方法について説明します。 C++ デスクトップ アプリ プロジェクトが既にある場合は、以下の手順とコード例をプロジェクトに合わせて調整できます。

カスタム WinRT XAML コントロールをホストするため、このチュートリアルの一部として次のプロジェクトとコンポーネントを作成します。

  • Windows デスクトップ アプリケーション プロジェクト。 このプロジェクトでは、ネイティブの C++ デスクトップ アプリを実装します。 WinRT XAML ホスティング API を使用してカスタム WinRT XAML コントロールをホストするコードを、このプロジェクトに追加します。

  • UWP アプリ プロジェクト (C++/WinRT) 。 このプロジェクトでは、カスタム WinRT XAML コントロールを実装します。 また、カスタム WinRT XAML 型のメタデータをプロジェクトに読み込むためのルート メタデータ プロバイダーも実装します。

要件

  • Visual Studio 2019 バージョン 16.4.3 以降。
  • Windows 10 バージョン 1903 SDK (バージョン 10.0.18362) 以降。
  • Visual Studio と共にインストールされる C++/WinRT Visual Studio Extension (VSIX)。 C++/WinRT は Windows ランタイム (WinRT) API の標準的な最新の C++17 言語プロジェクションで、ヘッダー ファイル ベースのライブラリとして実装され、最新の Windows API への最上位アクセス権を提供するように設計されています。 詳細については、「C++/WinRT」を参照してください。

デスクトップ アプリケーション プロジェクトを作成する

  1. Visual Studio で、MyDesktopWin32App という名前の新しい Windows デスクトップ アプリケーション プロジェクトを作成します。 このプロジェクト テンプレートは、C++Windows、およびデスクトップのプロジェクト フィルターで使用できます。

  2. ソリューション エクスプローラーでソリューション ノードを右クリックして、 [ソリューションの再ターゲット] をクリックし、10.0.18362.0 以降の SDK リリースを選択してから、 [OK] をクリックします。

  3. Microsoft.Windows.CppWinRT NuGet パッケージをインストールして、プロジェクトでの C++/WinRT のサポートを有効にします。

    1. ソリューション エクスプローラーMyDesktopWin32App プロジェクトを右クリックし、 [NuGet パッケージの管理] を選択します。
    2. [参照] タブを選択し、Microsoft.Windows.CppWinRT パッケージを探して、このパッケージの最新バージョンをインストールします。
  4. [NuGet パッケージの管理] ウィンドウで、次の追加の NuGet パッケージをインストールします。

  5. Windows ランタイム メタデータへの参照を追加します。

    1. ソリューション エクスプローラーで、プロジェクトの [参照設定] ノードを右クリックし、 [参照の追加] を選択します。
    2. ページの下部にある [参照] ボタンをクリックし、SDK インストール パスの UnionMetadata フォルダーに移動します。 既定では、SDK は C:\Program Files (x86)\Windows Kits\10\UnionMetadata にインストールされます。
    3. 次に、ターゲットとする Windows バージョン (例: 10.0.18362.0) が名前に含まれるフォルダーを選択して、そのフォルダー内で Windows.winmd ファイルを選びます。
    4. [OK] をクリックし、 [参照の追加] ダイアログを閉じます。
  6. ソリューションをビルドし、正常にビルドされたことを確認します。

UWP アプリ プロジェクトを作成する

次に、UWP (C++/WinRT) アプリ プロジェクトをソリューションに追加し、このプロジェクトの構成にいくつかの変更を行います。 このチュートリアルの後半では、カスタム WinRT XAML コントロールを実装するためのコードをこのプロジェクトに追加し、Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication クラスのインスタンスを定義します。

  1. ソリューション エクスプローラーで、ソリューション ノードを右クリックし、[追加] ->[新しいプロジェクト] を選択します。

  2. ソリューションに空のアプリ (C++/WinRT) プロジェクトを追加します。 プロジェクトの名前を MyUWPApp にして、対象バージョンと最小バージョンの両方が Windows 10 バージョン 1903 以降に設定されていることを確認します。

  3. MyUWPApp プロジェクトに、Microsoft.Toolkit.Win32.UI.XamlApplication NuGet パッケージをインストールします。 このパッケージは、このチュートリアルの後半で使用する Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication クラスを定義します。

    1. MyUWPApp プロジェクトを右クリックし、 [NuGet パッケージの管理] を選択します。
    2. [参照] タブを選択し、Microsoft.Toolkit.Win32.UI.XamlApplication パッケージを見つけて、このパッケージの最新の安定バージョンをインストールします。
  4. MyUWPApp ノードを右クリックし、 [プロパティ] を選択します。 [共通プロパティ] ->[C++/WinRT] ページで、[詳細] プロパティを [通常] に設定して、[適用] をクリックします。 完了すると、プロパティ ページは次のようになります。

    C++/WinRT project properties

  5. プロパティ ウィンドウの [構成プロパティ] ->[全般] ページで、[構成の種類][ダイナミック ライブラリ (.dll)] に設定し、[OK] をクリックしてプロパティ ウィンドウを閉じます。

    General project properties

  6. MyUWPApp プロジェクトに、プレースホルダー実行可能ファイルを追加します。 このプレースホルダー実行可能ファイルは、Visual Studio で必要なプロジェクト ファイルが生成され、プロジェクトが正しくビルドされるために必要です。

    1. ソリューション エクスプローラーで、MyUWPApp プロジェクト ノードを右クリックし、[追加] ->[新しい項目] を選択します。

    2. [新しい項目の追加] ダイアログで、左側のページにある [ユーティリティ] を選択し、 [テキスト ファイル (.txt)] を選択します。 名前に「placeholder.exe」と入力し、 [追加] をクリックします。 Add text file

    3. ソリューション エクスプローラーで、placeholder.exe ファイルを選択します。 [プロパティ] ウィンドウで、 [コンテンツ] プロパティが [True] に設定されていることを確認します。

    4. ソリューション エクスプローラーで、MyUWPApp プロジェクトの Package.appxmanifest ファイルを右クリックし、 [プログラムから開く] を選択し、 [XML (テキスト) エディター] を選択して、 [OK] をクリックします。

    5. <Application> 要素を見つけて、Executable 属性の値を placeholder.exe に変更します。 完了すると、 <Application> 要素は次のようになります。

      <Application Id="App" Executable="placeholder.exe" EntryPoint="MyUWPApp.App">
        <uap:VisualElements DisplayName="MyUWPApp" Description="Project for a single page C++/WinRT Universal Windows Platform (UWP) app with no predefined layout"
          Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" BackgroundColor="transparent">
          <uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png">
          </uap:DefaultTile>
          <uap:SplashScreen Image="Assets\SplashScreen.png" />
        </uap:VisualElements>
      </Application>
      
    6. Package.appxmanifest ファイルを保存して閉じます。

  7. ソリューション エクスプローラーで、MyUWPApp ノードを右クリックして、 [プロジェクトのアンロード] を選択します。

  8. MyUWPApp ノードを右クリックして、 [Edit MyUWPApp.vcxproj](MyUWPApp.vcxproj の編集) を選択します。

  9. <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> 要素を見つけて、次の XML に置き換えます。 この XML では、要素の直前に新しいプロパティがいくつか追加されます。

    <PropertyGroup Label="Globals">
        <WindowsAppContainer>true</WindowsAppContainer>
        <AppxGeneratePriEnabled>true</AppxGeneratePriEnabled>
        <ProjectPriIndexName>App</ProjectPriIndexName>
        <AppxPackage>true</AppxPackage>
    </PropertyGroup>
    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
    
  10. プロジェクト ファイルを保存して閉じます。

  11. ソリューション エクスプローラーで、MyUWPApp ノードを右クリックして、 [プロジェクトの再読み込み] を選択します。

ソリューションを構成する

このセクションでは、両方のプロジェクトが含まれるソリューションを更新して、プロジェクトを正しくビルドするために必要なプロジェクトの依存関係とビルドのプロパティを構成します。

  1. ソリューション エクスプローラーでソリューション ノードを右クリックし、Solution.props という名前の新しい XML ファイルを追加します。

  2. 次の XML を Solution.props ファイルに追加します。

    <?xml version="1.0" encoding="utf-8"?>
    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
        <IntDir>$(SolutionDir)\obj\$(Platform)\$(Configuration)\$(MSBuildProjectName)\</IntDir>
        <OutDir>$(SolutionDir)\bin\$(Platform)\$(Configuration)\$(MSBuildProjectName)\</OutDir>
        <GeneratedFilesDir>$(IntDir)Generated Files\</GeneratedFilesDir>
      </PropertyGroup>
    </Project>
    
  3. [表示] メニューの [プロパティ マネージャー] をクリックします (構成によっては [表示] ->[その他のウィンドウ] の下にある場合があります)。

  4. [プロパティ マネージャー] ウィンドウで MyDesktopWin32App を右クリックし、 [既存のプロパティ シートの追加] を選択します。 先ほど追加した Solution.props ファイルに移動し、 [開く] をクリックします。

  5. 前の手順を繰り返して、 [プロパティ マネージャー] ウィンドウで MyUWPApp プロジェクトに Solution.props ファイルを追加します。

  6. [プロパティ マネージャー] ウィンドウを閉じます。

  7. プロパティ シートの変更が正常に保存されたことを確認します。 ソリューション エクスプローラーMyDesktopWin32App プロジェクトを右クリックし、 [プロパティ] を選択します。 [構成プロパティ] ->[全般] をクリックし、[出力ディレクトリ] および [中間ディレクトリ] プロパティに、Solution.props ファイルに追加した値が設定されていることを確認します。 MyUWPApp プロジェクトでも同じことを確認できます。 Project properties

  8. ソリューション エクスプローラーでソリューション ノードを右クリックし、 [プロジェクトの依存関係] を選択します。 [プロジェクト] ドロップダウンで MyDesktopWin32App が選択されていることを確認し、 [依存先] の一覧で MyUWPApp を選択します。 Project dependencies

  9. [OK] をクリックします。

UWP アプリ プロジェクトにコードを追加する

これで、MyUWPApp プロジェクトにコードを追加し、次のタスクを実行できるようになりました。

  • カスタム WinRT XAML コントロールを実装します。 このチュートリアルでこの後、MyDesktopWin32App プロジェクトでこのコントロールをホストするコードを追加します。
  • Windows Community Toolkit の Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication クラスから派生する型を定義します。

カスタム WinRT XAML コントロールの定義

  1. ソリューション エクスプローラーMyUWPApp を右クリックし、[追加] ->[新しい項目] を選択します。 左側のペインで [Visual C++] ノードを選択して、 [Blank User Control (C++/WinRT)](空のユーザー コントロール (C++/WinRT)) を選択し、MyUserControl という名前を付けて、 [追加] をクリックします。

  2. XAML エディターで、MyUserControl.xaml ファイルの内容を次の XAML に置き換えて、ファイルを保存します。

    <UserControl
        x:Class="MyUWPApp.MyUserControl"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:MyUWPApp"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <StackPanel HorizontalAlignment="Center" Spacing="10" 
                    Padding="20" VerticalAlignment="Center">
            <TextBlock HorizontalAlignment="Center" TextWrapping="Wrap" 
                           Text="Hello from XAML Islands" FontSize="30" />
            <TextBlock HorizontalAlignment="Center" Margin="15" TextWrapping="Wrap"
                           Text="😍❤💋🌹🎉😎�🐱‍👤" FontSize="16" />
            <Button HorizontalAlignment="Center" 
                    x:Name="Button" Click="ClickHandler">Click Me</Button>
        </StackPanel>
    </UserControl>
    

XamlApplication クラスを定義する

次に、MyUWPApp プロジェクトの既定の App クラスを、Windows Community Toolkit によって提供される Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication クラスから派生するように変更します。 このクラスでは、IXamlMetadataProvider インターフェイスがサポートされています。これにより、アプリの実行時に、アプリケーションの現在のディレクトリにある、アセンブリ内のカスタム WinRT XAML コントロールのメタデータを検出して読み込むことができるようになります。 このクラスでは、現在のスレッドの WinRT XAML フレームワークも初期化されます。 このチュートリアルの後の方で、デスクトップ プロジェクトを更新して、このクラスのインスタンスを作成します。

Note

XamlApplication オブジェクトは、XAML Islands を使用する各ソリューション内の 1 つのプロジェクトだけで、定義されている必要があります。 アプリ内のすべてのカスタム WinRT XAML コントロールで、同じ XamlApplication オブジェクトを共有します。

  1. ソリューション エクスプローラーで、MyUWPApp プロジェクトの MainPage.xaml ファイルを右クリックします。 [削除] をクリックした後、 [削除] をクリックして、このファイルをプロジェクトから完全に削除します。

  2. MyUWPApp プロジェクトで、App.xaml ファイルを展開します。

  3. App.xamlApp.cppApp.hApp.idl ファイルの内容を、次のコードに置き換えます。

    • App.xaml:

      <Toolkit:XamlApplication
          x:Class="MyUWPApp.App"
          xmlns:Toolkit="using:Microsoft.Toolkit.Win32.UI.XamlHost"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:local="using:MyUWPApp">
      </Toolkit:XamlApplication>
      
    • App.idl:

      namespace MyUWPApp
      {
           [default_interface]
           runtimeclass App : Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication
           {
              App();
           }
      }
      
    • App.h:

      #pragma once
      #include "App.g.h"
      #include "App.base.h"
      namespace winrt::MyUWPApp::implementation
      {
          class App : public AppT2<App>
          {
          public:
              App();
              ~App();
          };
      }
      namespace winrt::MyUWPApp::factory_implementation
      {
          class App : public AppT<App, implementation::App>
          {
          };
      }
      
    • App.cpp:

      #include "pch.h"
      #include "App.h"
      #include "App.g.cpp"
      using namespace winrt;
      using namespace Windows::UI::Xaml;
      namespace winrt::MyUWPApp::implementation
      {
          App::App()
          {
              Initialize();
              AddRef();
              m_inner.as<::IUnknown>()->Release();
          }
          App::~App()
          {
              Close();
          }
      }
      

      Note

      プロジェクト プロパティの [共通プロパティ] ->[C++/WinRT] ページで [最適化済み] プロパティが [はい] に設定されている場合は、#include "App.g.cpp" ステートメントが必要です、 これは、新しい C++/WinRT プロジェクトの既定値です。 [最適化済み] プロパティの効果の詳細については、こちらのセクションを参照してください。

  4. app.base.h という名前の新しいヘッダー ファイルを、MyUWPApp プロジェクトに追加します。

  5. 次のコードを app.base.h ファイルに追加し、ファイルを保存して閉じます。

    #pragma once
    namespace winrt::MyUWPApp::implementation
    {
        template <typename D, typename... I>
        struct App_baseWithProvider : public App_base<D, ::winrt::Windows::UI::Xaml::Markup::IXamlMetadataProvider>
        {
            using IXamlType = ::winrt::Windows::UI::Xaml::Markup::IXamlType;
            IXamlType GetXamlType(::winrt::Windows::UI::Xaml::Interop::TypeName const& type)
            {
                return _appProvider.GetXamlType(type);
            }
            IXamlType GetXamlType(::winrt::hstring const& fullName)
            {
                return _appProvider.GetXamlType(fullName);
            }
            ::winrt::com_array<::winrt::Windows::UI::Xaml::Markup::XmlnsDefinition> GetXmlnsDefinitions()
            {
                return _appProvider.GetXmlnsDefinitions();
            }
        private:
            bool _contentLoaded{ false };
            winrt::MyUWPApp::XamlMetaDataProvider _appProvider;
        };
        template <typename D, typename... I>
        using AppT2 = App_baseWithProvider<D, I...>;
    }
    
  6. ソリューションをビルドし、正常にビルドされたことを確認します。

カスタム コントロール型を使用するようにデスクトップ プロジェクトを構成する

MyDesktopWin32App アプリの XAML Island でカスタム WinRT XAML コントロールをホストできるようにするには、先に、MyUWPApp プロジェクトのカスタム コントロール型を使用するようにアプリを構成する必要があります。 これを行うには 2 つの方法があり、どちらかのオプションを選択して、このチュートリアルを完了できます。

オプション 1:MSIX を使用してアプリをパッケージ化する

配置用にアプリを MSIX パッケージにパッケージ化できます。 MSIX は、Windows 向けの最新のアプリ パッケージ化テクノロジであり、MSI、.appx、App-V、ClickOnce インストールの各テクノロジの組み合わせが基になっています。

  1. ソリューションに新しい Windows アプリケーション パッケージ プロジェクトを追加します。 プロジェクトを作成するときに、名前を MyDesktopWin32Project にして、 [ターゲット バージョン][最小バージョン] の両方に対して、Windows 10 バージョン 1903 (10.0、ビルド 18362) を選択します。

  2. パッケージ プロジェクトで、 [アプリケーション] ノードを右クリックして [参照の追加] を選択します。 プロジェクトの一覧で、MyDesktopWin32App プロジェクトの横のチェック ボックスをオンにして、 [OK] をクリックします。 Reference project

  3. パッケージの配布/展開の詳細については、「MSIX の展開を管理する」を参照してください。

注意

展開用にアプリケーションを MSIX パッケージにパッケージ化しない場合は、アプリを実行するコンピューターに Visual C++ ランタイムがインストールされている必要があります。

オプション 2:アプリケーション マニフェストを作成する

アプリケーション マニフェストをアプリに追加できます。

  1. MyDesktopWin32App プロジェクトを右クリックし、[追加] ->[新しい項目] を選択します。

  2. [新しい項目の追加] ダイアログで、左側のペインの [Web] をクリックし、 [XML ファイル (.xml)] を選択します。

  3. 新しいファイルに「app.manifest」という名前を指定し、 [追加] をクリックします。

  4. 新しいファイルの内容を次の XML に置き換えます。 この XML では、MyUWPApp プロジェクトにカスタム コントロール型が登録されます。

    <?xml version="1.0" encoding="utf-8"?>
    <assembly
     xmlns="urn:schemas-microsoft-com:asm.v1"
     xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"
     manifestVersion="1.0">
      <asmv3:file name="MyUWPApp.dll">
        <activatableClass
            name="MyUWPApp.App"
            threadingModel="both"
            xmlns="urn:schemas-microsoft-com:winrt.v1" />
        <activatableClass
            name="MyUWPApp.XamlMetadataProvider"
            threadingModel="both"
            xmlns="urn:schemas-microsoft-com:winrt.v1" />
        <activatableClass
            name="MyUWPApp.MyUserControl"
            threadingModel="both"
            xmlns="urn:schemas-microsoft-com:winrt.v1" />
      </asmv3:file>
    </assembly>
    

デスクトップ プロジェクトの追加のプロパティを構成する

次に、MyDesktopWin32App プロジェクトを更新して、追加のインクルード ディレクトリのマクロを定義し、追加のプロパティを構成します。

  1. ソリューション エクスプローラーMyDesktopWin32App プロジェクトを右クリックし、 [プロジェクトのアンロード] を選択します。

  2. MyDesktopWin32App (アンロード済み) を右クリックし、 [MyDesktopWin32App.vcxproj の編集] を選択します。

  3. ファイルの末尾にある終了タグ </Project> の直前に、次の XML を追加します。 ファイルを保存して閉じます。

      <!-- Configure these for your UWP project -->
      <PropertyGroup>
        <AppProjectName>MyUWPApp</AppProjectName>
      </PropertyGroup>
      <PropertyGroup>
        <AppIncludeDirectories>$(SolutionDir)\obj\$(Platform)\$(Configuration)\$(AppProjectName)\;$(SolutionDir)\obj\$(Platform)\$(Configuration)\$(AppProjectName)\Generated Files\;</AppIncludeDirectories>
      </PropertyGroup>
      <ItemGroup>
        <ProjectReference Include="..\$(AppProjectName)\$(AppProjectName).vcxproj" />
      </ItemGroup>
      <!-- End Section-->
    
  4. ソリューション エクスプローラーで、MyDesktopWin32App (アンロード済み) を右クリックして、 [プロジェクトの再読み込み] を選択します。

  5. MyDesktopWin32App プロジェクトを右クリックして [プロパティ] を選択し、左側ペインで [マニフェスト ツール] ->[入力と出力] を展開します。 [DPI 認識] プロパティを [モニターごとの高い DPI 認識] に設定します。 このプロパティを設定しなかった場合、特定の高 DPI シナリオでマニフェスト構成エラーが発生することがあります。

    Screenshot of the C/C++ project settings.

  6. [OK] をクリックして、 [プロパティ ページ] ダイアログを閉じます。

デスクトップ プロジェクトでカスタム WinRT XAML コントロールをホストする

最後に、MyUWPApp プロジェクトで前に定義したカスタム WinRT XAML コントロールをホストするコードを、MyDesktopWin32App プロジェクトに追加します。

  1. MyDesktopWin32App プロジェクトで framework.h ファイルを開き、次のコード行をコメントアウトします。 終わったらファイルを保存します。

    #define WIN32_LEAN_AND_MEAN
    
  2. MyDesktopWin32App.h ファイルを開き、このファイルの内容を次のコードに置き換えて、必要な C++/WinRT ヘッダー ファイルを参照します。 終わったらファイルを保存します。

    #pragma once
    
    #include "resource.h"
    #include <winrt/Windows.Foundation.Collections.h>
    #include <winrt/Windows.system.h>
    #include <winrt/windows.ui.xaml.hosting.h>
    #include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
    #include <winrt/windows.ui.xaml.controls.h>
    #include <winrt/Windows.ui.xaml.media.h>
    #include <winrt/Windows.UI.Core.h>
    #include <winrt/MyUWPApp.h>
    
    using namespace winrt;
    using namespace Windows::UI;
    using namespace Windows::UI::Composition;
    using namespace Windows::UI::Xaml::Hosting;
    using namespace Windows::Foundation::Numerics;
    using namespace Windows::UI::Xaml::Controls;
    
  3. MyDesktopWin32App.cpp ファイルを開き、次のコードを Global Variables: セクションに追加します。

    winrt::MyUWPApp::App hostApp{ nullptr };
    winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource _desktopWindowXamlSource{ nullptr };
    winrt::MyUWPApp::MyUserControl _myUserControl{ nullptr };
    
  4. 同じファイルで、次のコードを Forward declarations of functions included in this code module: セクションに追加します。

    void AdjustLayout(HWND);
    
  5. 同じファイルで、wWinMain 関数の TODO: Place code here. コメントの直後に次のコードを追加します。

    // TODO: Place code here.
    winrt::init_apartment(winrt::apartment_type::single_threaded);
    hostApp = winrt::MyUWPApp::App{};
    _desktopWindowXamlSource = winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource{};
    
  6. 同じファイルで、既定の InitInstance 関数を次のコードに置き換えます。

    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
        hInst = hInstance; // Store instance handle in our global variable
    
        HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
    
        if (!hWnd)
        {
            return FALSE;
        }
    
        // Begin XAML Islands walkthrough code.
        if (_desktopWindowXamlSource != nullptr)
        {
            auto interop = _desktopWindowXamlSource.as<IDesktopWindowXamlSourceNative>();
            check_hresult(interop->AttachToWindow(hWnd));
            HWND hWndXamlIsland = nullptr;
            interop->get_WindowHandle(&hWndXamlIsland);
            RECT windowRect;
            ::GetWindowRect(hWnd, &windowRect);
            ::SetWindowPos(hWndXamlIsland, NULL, 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, SWP_SHOWWINDOW);
            _myUserControl = winrt::MyUWPApp::MyUserControl();
            _desktopWindowXamlSource.Content(_myUserControl);
        }
        // End XAML Islands walkthrough code.
    
        ShowWindow(hWnd, nCmdShow);
        UpdateWindow(hWnd);
    
        return TRUE;
    }
    
  7. 同じファイルで、次の新しい関数をファイルの最後に追加します。

    void AdjustLayout(HWND hWnd)
    {
        if (_desktopWindowXamlSource != nullptr)
        {
            auto interop = _desktopWindowXamlSource.as<IDesktopWindowXamlSourceNative>();
            HWND xamlHostHwnd = NULL;
            check_hresult(interop->get_WindowHandle(&xamlHostHwnd));
            RECT windowRect;
            ::GetWindowRect(hWnd, &windowRect);
            ::SetWindowPos(xamlHostHwnd, NULL, 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, SWP_SHOWWINDOW);
        }
    }
    
  8. 同じファイルで、WndProc 関数を見つけます。 switch ステートメントの既定の WM_DESTROY ハンドラーを、次のコードに置き換えます。

    case WM_DESTROY:
        PostQuitMessage(0);
        if (_desktopWindowXamlSource != nullptr)
        {
            _desktopWindowXamlSource.Close();
            _desktopWindowXamlSource = nullptr;
        }
        break;
    case WM_SIZE:
        AdjustLayout(hWnd);
        break;
    
  9. ファイルを保存します。

  10. ソリューションをビルドし、正常にビルドされたことを確認します。

WinUI 2 ライブラリのコントロールをカスタム コントロールに追加する

従来、WinRT XAML コントロールは Windows OS の一部としてリリースされ、開発者は Windows SDK を通じてそれを使用できました。 WinUI ライブラリ はそれに代わる方法であり、Windows SDK の WinRT XAML コントロールの更新バージョンが、Windows SDK のリリースに関連付けられていない NuGet パッケージで配布されます。 また、このライブラリには、Windows SDK および既定の UWP プラットフォームの一部ではない新しいコントロールも含まれています。

このセクションでは、WinUI 2 ライブラリからユーザー コントロールに WinRT XAML コントロールを追加する方法について説明します。

Note

現在、XAML Islands では、WinUI 2 ライブラリのコントロールのホストのみがサポートされています。 WinUI 3 ライブラリのコントロールのホストは、今後のリリースでサポートされる予定です。

  1. MyUWPApp プロジェクトで、最新のプレリリースまたはリリース バージョンの Microsoft.UI.Xaml NuGet パッケージをインストールします。

    • このチュートリアルの前の手順で MSIX を使用する MyDesktopWin32App プロジェクトのパッケージ化を選択した場合、Microsoft.UI.Xaml NugGet パッケージのプレリリース バージョンまたはリリース バージョンのいずれかをインストールできます。 パッケージ化されたデスクトップ アプリは、このパッケージのプレリリース バージョンまたはリリース バージョンのいずれかを使用できます。
    • MyDesktopWin32App プロジェクトのパッケージ化を選択しなかった場合、Microsoft.UI.Xaml NuGet パッケージのプレリリース バージョンをインストールする必要があります。 パッケージ化されていないデスクトップ アプリは、このパッケージのプレリリース バージョンを使用する必要があります。
  2. このプロジェクトの pch.h ファイルで、次の #include ステートメントを追加し、変更を保存します。 これらのステートメントは、一連の必要なプロジェクション ヘッダーを WinUI ライブラリからプロジェクトに取り込みます。 この手順は、WinUI ライブラリを使用する任意の C++/WinRT プロジェクトに必要です。 詳しくは、こちらの記事をご覧ください。

    #include "winrt/Microsoft.UI.Xaml.Automation.Peers.h"
    #include "winrt/Microsoft.UI.Xaml.Controls.Primitives.h"
    #include "winrt/Microsoft.UI.Xaml.Media.h"
    #include "winrt/Microsoft.UI.Xaml.XamlTypeInfo.h"
    
  3. 同じプロジェクトの App.xaml ファイルで、次の子要素を <xaml:XamlApplication> 要素に追加し、変更を保存します。

    <Application.Resources>
        <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
    </Application.Resources>
    

    この要素を追加した後、このファイルの内容は次のようになります。

    <Toolkit:XamlApplication
        x:Class="MyUWPApp.App"
        xmlns:Toolkit="using:Microsoft.Toolkit.Win32.UI.XamlHost"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:MyUWPApp">
        <Application.Resources>
            <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls"/>
        </Application.Resources>
    </Toolkit:XamlApplication>
    
  4. 同じプロジェクトで、MyUserControl.xaml ファイルを開き、次の名前空間宣言を <UserControl> 要素に追加します。

    xmlns:winui="using:Microsoft.UI.Xaml.Controls"
    
  5. 同じファイルで、<StackPanel> の子として <winui:RatingControl /> 要素を追加し、変更を保存します。 この要素により、WinUI ライブラリの RatingControl クラスのインスタンスが追加されます。 この要素を追加した後の <StackPanel> は、次のようになります。

    <StackPanel HorizontalAlignment="Center" Spacing="10" 
                Padding="20" VerticalAlignment="Center">
        <TextBlock HorizontalAlignment="Center" TextWrapping="Wrap" 
                       Text="Hello from XAML Islands" FontSize="30" />
        <TextBlock HorizontalAlignment="Center" Margin="15" TextWrapping="Wrap"
                       Text="😍❤💋🌹🎉😎�🐱‍👤" FontSize="16" />
        <Button HorizontalAlignment="Center" 
                x:Name="Button" Click="ClickHandler">Click Me</Button>
        <winui:RatingControl />
    </StackPanel>
    
  6. ソリューションをビルドし、正常にビルドされたことを確認します。

アプリをテストする

ソリューションを実行し、次のウィンドウで MyDesktopWin32App が開かれることを確認します。

MyDesktopWin32App app

次のステップ

XAML Islands をホストする多くのデスクトップ アプリケーションでは、スムーズなユーザー エクスペリエンスを提供するために処理する必要があるシナリオが他にもあります。 たとえば、デスクトップ アプリケーションでは、XAML Islands でのキーボード入力、XAML Islands と他の UI 要素の間でのフォーカス ナビゲーション、およびレイアウトの変更を処理することが、必要になる場合があります。

これらのシナリオの処理に関する詳細、および関連するコード サンプルへのリンクについては、C++ デスクトップ アプリでの XAML Islands の高度なシナリオに関する記事を参照してください。