重要
このチュートリアルでは C++/CX を使います。 Microsoft は C++/WinRT をリリースしました。これは、Windows ランタイム (WinRT) API 用に完全に標準化された、最新の C++17 言語プロジェクションです。 この言語の詳細については、「C++/WinRT」をご覧ください。
Microsoft Visual Studio では、Extensible Application Markup Language (XAML) で定義されている UI を使い、Windows で動作するアプリを C++/CX を使って開発できます。
注
このチュートリアルでは、Visual Studio Community 2019 を使います。 異なるバージョンの Visual Studio を使っている場合には、見た目が多少異なることがあります。
開始する前に
- このチュートリアルを完了するには、Windows が実行されているコンピューターで、Visual Studio Community、または Community バージョン以外のいずれかの Visual Studio を使う必要があります。 ダウンロード方法については、ツールの入手を参照してください。
- 進めるには、C++/CX、XAML、そして「XAML の概要」で説明されている概念についての基本的な知識が必要です。
- 進めるには、Visual Studio の既定のウィンドウ レイアウトを使用する必要があります。 既定のレイアウトに戻すには、メニュー バーで [ウィンドウ]>[ウィンドウ レイアウトのリセット] の順に選択します。
C++ デスクトップ アプリと UWP アプリの比較
C++ を使った Windows デスクトップのプログラミングに関する経験がある場合、UWP 用アプリのプログラミングには、通常の C++ プログラミングと同じ部分もありますが、新しい知識が必要になる部分もあります。
何が同じですか?
Windows ランタイム環境からアクセスできる Windows 関数のみをコードから呼び出す場合に限り、STL と CRT (一部例外あり)、さらに他のあらゆる C++ ライブラリを使うことができます。
ビジュアル デザイン サーフェスに慣れている場合は、Microsoft Visual Studio に組み込まれたデザイナーを引き続き使うことができます。また、より多機能な Blend for Visual Studio を使うこともできます。 手動で UI のコーディングを行うことに慣れている場合は、XAML を手動で記述できます。
ユーザーは今でも、Windows のオペレーティング システムの種類や独自のカスタム型を使用するアプリを作成しています。
Visual Studio のデバッガー、プロファイラー、その他開発ツールを引き続き使用しています。
Visual C++ コンパイラでネイティブ マシン コードにコンパイルされるアプリを引き続き作成している。 C++/CX で作成された UWP アプリは、マネージド ランタイム環境では実行されません。
新機能
UWP アプリの設計原則は、デスクトップ アプリの設計原則とは大きく異なります。 ウィンドウの境界線、ラベル、ダイアログ ボックスなどは目立たなくなります。 コンテンツが最優先です。 優れた UWP アプリには、こうした原則が計画段階の初期から活かされています。
XAML を使って UI 全体を定義します。 UWP アプリでは、MFC または Win32 アプリよりもはるかに明確に UI とコア プログラム ロジックが分離されています。 XAML を使った UI の見た目の調整と、コード ファイルでの動作のプログラミングを、異なる担当者が並行して行うことができます。
プログラミングの対象は主に Windows ランタイム (操作しやすい、オブジェクト指向の新しい API) ですが、Windows デバイス上で一部の機能にこれまでどおり Win32 を使うこともできます。
Windows ランタイムのオブジェクトを利用したり作成したりするには C++/CX を使います。 C++/CX は、C++ の例外処理、デリゲート、イベントのほか、動的に作成されるオブジェクトの自動参照カウントに対応しています。 C++/CX を使うとき、ベースの COM と Windows アーキテクチャの詳細は、アプリ コードからは見えません。 詳しくは、「C++/CX 言語のリファレンス」をご覧ください。
アプリは、そのアプリ自体に含まれる型、アプリで使うリソース、必要な機能 (ファイル アクセス、インターネット アクセス、カメラ アクセスなど) に関するメタデータも含むパッケージにコンパイルされます。
Microsoft Storeでは、アプリは認定プロセスによって安全であると検証され、何百万人もの潜在的な顧客に見つけてもらえるようになります。
C++/CX を使った Hello World ストア アプリ
最初のアプリは、インタラクティビティ、レイアウト、スタイルの基本的な機能を示す "Hello World" アプリです。 アプリは、Windows ユニバーサル アプリ プロジェクト テンプレートを使って作成します。 ユニバーサル Windows プラットフォーム (UWP) を使用すると、アプリのコードと XAML を単一のプロジェクトにまとめ、Windows のデスクトップ PC、ノート PC、タブレットでアプリを実行することができます。
それでは、基礎から始めましょう。
Visual Studio でユニバーサル Windows プロジェクトを作成する方法。
作成されるプロジェクトとファイルを把握する方法。
Visual C++ コンポーネント拡張機能 (C++/CX) の拡張機能を把握する方法と、それを使うタイミング。
まず Visual Studio でソリューションを作成する
Visual Studio のメニュー バーから [ファイル]>[新規]>[プロジェクト...] の順に選択します。
[新しいプロジェクトの作成] ダイアログ ボックスで、[空白のアプリ (ユニバーサル Windows - C++/CX)] を選択します。 このオプションが見つからない場合は、ユニバーサル Windows アプリ開発ツールがインストールされていることを確認してください。 詳しくは、「セットアップを行う」をご覧ください。
[次へ] を選択し、プロジェクトの名前を入力します。 ここでは、名前を "HelloWorld" とします。
[作成] を選択します。
注
Visual Studio を初めて使う場合は、[設定] ダイアログ ボックスが表示され、開発者モードを有効にするよう求められることがあります。 開発者モードは、アプリをストアからだけではなく、直接実行するためのアクセス許可など、特定の機能を有効にする特別な設定です。 詳しくは、「デバイスを開発用に有効にする」をご覧ください。 このガイドを続けるには、 [開発者モード] を選択し、 [はい] をクリックしてダイアログ ボックスを閉じます。
プロジェクト ファイルが作成されました。
先に進む前に、ソリューションの構成内容を調べてみましょう。
プロジェクト ファイルについて
プロジェクト フォルダー内のすべての .xaml ファイルには、対応する .xaml.h ファイルと .xaml.cpp ファイルが同じフォルダーに、.g ファイルと .g.hpp ファイルが [生成されたファイル] フォルダーにそれぞれ存在します。このフォルダーはプロジェクト内ではなく、ディスク上にあります。 UI 要素を作成してデータ ソースに接続 (DataBinding) するには、XAML ファイルに変更を加えます。 イベント ハンドラーにカスタム ロジックを追加するには、.h ファイルと .cpp ファイルに変更を加えます。 自動生成ファイルは、XAML マークアップから C++/CX への変換を表します。 これらのファイルは変更しないでください。ただし、ファイルを観察すると、コードビハインドの働きをより深く理解できます。 基本的に、生成されたファイルには、XAML ルート要素の部分クラスの定義が記述されています。このクラスは、*.xaml.h ファイルや .cpp ファイルで変更するクラスと同じです。 生成されたファイルには、XAML UI の子要素がクラスのメンバーとして宣言されており、開発者がコードの中で参照することができます。 ビルド時には、生成されたコードと自分で記述したコードとがマージされてクラス定義が完成し、コンパイルされます。
まずプロジェクト ファイルを見てみましょう。
- App.xaml、App.xaml.h、App.xaml.cpp: アプリのエントリ ポイントとなる Application オブジェクトを表します。 App.xaml に、ページ固有の UI マークアップは含まれませんが、UI のスタイルなど、任意のページからアクセスできるようにしたい要素を追加することができます。 分離コード ファイルには、OnLaunched イベントと OnSuspending イベントのハンドラーが含まれます。 通常、ここには、起動時にアプリを初期化したり、中断または終了時にクリーンアップ処理を実行したりするためのカスタム コードを追加します。
- MainPage.xaml、MainPage.xaml.h、MainPage.xaml.cpp: アプリの既定の "スタート" ページに関する XAML マークアップと分離コードが含まれます。 ナビゲーション サポートやビルトイン コントロールはありません。
- pch.h、pch.cpp: プリコンパイル済みヘッダー ファイルと、それをプロジェクト内でインクルードするファイルです。 pch.h には、変更頻度が低く、ソリューション内の他のファイルにインクルードされるヘッダーを含めることができます。
- Package.appxmanifest: アプリが必要とするデバイスの機能、そしてアプリのバージョン情報やその他のメタデータを表す XML ファイルです。 このファイルをダブルクリックすると、マニフェスト デザイナーで開くことができます。
- HelloWorld_TemporaryKey.pfx: Visual Studio からこのコンピューターにアプリを展開するためのキーです。
コードをはじめて使用する
共有プロジェクト内の App.xaml.h と App.xaml.cpp のコードをよく見ると、ほとんどが、見覚えのある ISO C++ コードであることがわかります。 ただし、Windows ランタイム アプリの開発が初めての場合や、これまで C++/CLI で作業を行ってきた場合は、あまり馴染みのない構文要素も中には存在します。 C++/CX でよく使われる標準的ではない構文要素を以下に示します。
Ref クラス
Windows ランタイムのほぼすべてのクラスは、Windows API のすべての型 (XAML コントロール、アプリ内のページ、App クラス自体、すべてのデバイス オブジェクトとネットワーク オブジェクト、すべてのコンテナー型) を含んでおり、ref クラス として宣言されます (value class または value struct の Windows 型もわずかに存在します)。 ref クラスはどの言語からでも利用できます。 C++/CX では、これらの型の有効期間が (ガベージ コレクションではなく) 自動参照カウントによって制御されるため、それらのオブジェクトを明示的に削除する必要がありません。 ref クラスは独自に作成することもできます。
namespace HelloWorld
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public ref class MainPage sealed
{
public:
MainPage();
};
}
Windows ランタイムのすべての型は名前空間内で宣言する必要があり、ISO C++ とは異なり、型そのものがアクセシビリティ修飾子を持ちます。 public 修飾子を持つクラスは、その名前空間の外部にある Windows ランタイム コンポーネントからアクセス可能になります。 sealed キーワードは、そのクラスが他のクラスの基底クラスとして使用できないことを意味します。 ほとんどの ref クラスは sealed です。クラスの継承は、JavaScript が認識しないため、あまり広くは使われません。
ref new と ^ (ハット)
ref クラスの変数は ^ (ハット) 演算子を使って宣言します。ref new キーワードでオブジェクトをインスタンス化することができます。 それ以降、オブジェクトのインスタンス メソッドにアクセスする際は、C++ のポインターと同様の -> 演算子を使います。 静的メソッドにアクセスする場合は、ISO C++ と同様、:: 演算子を使います。
次のコードでは、完全修飾名を使ってオブジェクトをインスタンス化し、-> 演算子を使ってインスタンス メソッドを呼び出しています。
Windows::UI::Xaml::Media::Imaging::BitmapImage^ bitmapImage =
ref new Windows::UI::Xaml::Media::Imaging::BitmapImage();
bitmapImage->SetSource(fileStream);
通常、.cpp ファイルには using namespace Windows::UI::Xaml::Media::Imaging ディレクティブと auto キーワードを追加するため、同じコードは次のように記述されます:
auto bitmapImage = ref new BitmapImage();
bitmapImage->SetSource(fileStream);
プロパティ
ref クラスはプロパティを持つことができます。プロパティは、マネージ言語のプロパティと同様、それを利用する側のコードからはフィールドとして見える特殊なメンバー関数です。
public ref class SaveStateEventArgs sealed
{
public:
// Declare the property
property Windows::Foundation::Collections::IMap<Platform::String^, Platform::Object^>^ PageState
{
Windows::Foundation::Collections::IMap<Platform::String^, Platform::Object^>^ get();
}
...
};
...
// consume the property like a public field
void PhotoPage::SaveState(Object^ sender, Common::SaveStateEventArgs^ e)
{
if (mruToken != nullptr && !mruToken->IsEmpty())
{
e->PageState->Insert("mruToken", mruToken);
}
}
デリゲート
マネージ言語と同様、デリゲートは、特定のシグニチャの関数をカプセル化する参照型です。 ほとんどの場合、イベントとそのハンドラーに使われます。
// Delegate declaration (within namespace scope)
public delegate void LoadStateEventHandler(Platform::Object^ sender, LoadStateEventArgs^ e);
// Event declaration (class scope)
public ref class NavigationHelper sealed
{
public:
event LoadStateEventHandler^ LoadState;
};
// Create the event handler in consuming class
MainPage::MainPage()
{
auto navigationHelper = ref new Common::NavigationHelper(this);
navigationHelper->LoadState += ref new Common::LoadStateEventHandler(this, &MainPage::LoadState);
}
アプリへのコンテンツの追加
それでは、アプリにコンテンツを追加しましょう。
手順 1: スタート ページを変更する
ソリューション エクスプローラーで、MainPage.xaml を開きます。
ルート Grid の終了タグの直前に次の XAML を追加して、UI に使うコントロールを作成します。 このコントロールには、StackPanel が含まれており、その中には、ユーザーに名前を入力するよう求める TextBlock、ユーザー名を入力するための TextBox 要素、Button、そして別の TextBlock 要素が含まれています。
<StackPanel x:Name="contentPanel" Margin="120,30,0,0"> <TextBlock HorizontalAlignment="Left" Text="Hello World" FontSize="36"/> <TextBlock Text="What's your name?"/> <StackPanel x:Name="inputPanel" Orientation="Horizontal" Margin="0,20,0,20"> <TextBox x:Name="nameInput" Width="300" HorizontalAlignment="Left"/> <Button x:Name="inputButton" Content="Say "Hello""/> </StackPanel> <TextBlock x:Name="greetingOutput"/> </StackPanel>ここまでの作業で、ごく基本的なユニバーサル Windows アプリが作成されました。 UWP アプリの動作や外観を確かめるには、F5 キーを押してデバッグ モードでアプリをビルド、展開、起動します。
最初に、既定のスプラッシュ画面が表示されます。 これには、アプリのマニフェスト ファイルに指定された画像 (Assets\SplashScreen.scale-100.png) と背景色があります。 スプラッシュ画面をカスタマイズする方法については、「スプラッシュ画面の追加」をご覧ください。
スプラッシュ画面が消えると、アプリが表示されます。 アプリのメインページが表示されます。
特別な機能はありませんが、ともかくこれで、初めてのユニバーサル Windows プラットフォーム アプリの作成は完了です。
アプリのデバッグを停止して閉じるには、Visual Studio に戻り、Shift+F5 キーを押します。
詳しくは、「Visual Studio からのストア アプリの実行」をご覧ください。
アプリの TextBox に文字を入力することはできますが、この時点では Button をクリックしても何も起こりません。 この後の手順で、ユーザーに合わせたあいさつを表示する、ボタンの Click イベント用のイベント ハンドラーを作成します。
手順 2: イベント ハンドラーを作成する
MainPage.xaml (XAML ビューまたはデザイン ビュー) で、先に追加した StackPanel 内の "Say Hello" Button を選びます。
F4 キーを押してプロパティ ウィンドウを開き、[イベント] ボタン (
) を選択します。Click イベントを探します。 このテキスト ボックスに、Click イベントを処理する関数の名前を入力します。 この例では、「Button_Click」と入力します。
Enter キーを押してください。 MainPage.xaml.cpp にイベント ハンドラー メソッドが作成され、イベントの発生時に実行されるコードを追加できるように開かれます。
同時に、MainPage.xaml で、Button の XAML が更新されて、次のように Click イベント ハンドラーが宣言されます。
<Button Content="Say "Hello"" Click="Button_Click"/>
これを XAML コードに手動で追加することも可能ですが、デザイナーが読み込まれない場合には、この方法が役立つことがあります。 手動で入力する場合は、「Click」と入力すると、IntelliSense で新しいハンドラーを追加するオプションが表示されます。 このように、Visual Studio によって必要なメソッド宣言とスタブが作成されます。
デザイナーは、レンダリング中にハンドルされない例外が発生すると、読み込みに失敗します。 デザイナーでのレンダリングには、ページのデザイン時のバージョンを実行することが含まれます。 これは、ユーザー コードの実行を無効にする場合に便利です。 これを行うには、ツール、オプションダイアログボックスの設定を変更してください。 [XAML デザイナー] で、 [プロジェクト コードを XAML デザイナーで実行する (サポートされている場合)] チェック ボックスをオフにします。
- MainPage.xaml.cpp で、先ほど作成した Button_Click イベント ハンドラーに次のコードを追加します。 このコードは、
nameInputTextBox コントロールからユーザー名を取得し、それを使ってあいさつを作ります。 結果は、greetingOutputTextBlock に表示されます。
void HelloWorld::MainPage::Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
greetingOutput->Text = "Hello, " + nameInput->Text + "!";
}
- プロジェクトをスタートアップ プロジェクトとして設定し、F5 キーを押してアプリをビルド、実行します。 テキスト ボックスに名前を入力してボタンをクリックすると、パーソナライズされたあいさつが表示されます。
手順 3: スタート ページのスタイル設定
テーマを選ぶ
アプリの外観は簡単にカスタマイズできます。 既定では、アプリは淡色スタイルのリソースを使います。 システム リソースには、淡色テーマも含まれています。 試しにそれを使って、どのように表示されるか見てみましょう。
濃色テーマに切り替えるには
App.xaml を開きます。
Application の開始タグで、RequestedTheme プロパティを編集し、その値を Dark に設定します:
RequestedTheme="Dark"ダーク テーマを含む Application タグ全体を次に示します。
<Application x:Class="HelloWorld.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:HelloWorld" RequestedTheme="Dark">F5 キーを押して、ビルドして実行します。 濃色テーマが使われていることに注目してください。
どのテーマを使えばいいでしょうか。 好きなほうを選んでください。 お勧めするとすれば、主に画像やビデオを表示するアプリには濃色テーマ、テキストが大量に含まれるアプリには淡色テーマです。 カスタム配色を使う場合は、アプリの外観に最もよく合ったテーマを使ってください。 このチュートリアルの残りの部分では、スクリーンショットで淡色テーマを使います。
注 テーマは、アプリの起動時に適用されます。アプリの実行中にテーマを変更することはできません。
システム スタイルの使用
現時点では、Windows アプリ内のテキストが小さすぎて判読困難です。 システム スタイルを適用してこの点を修正してみましょう。
要素のスタイルを変更するには
Windows プロジェクトで、MainPage.xaml を開きます。
XAML ビューまたはデザイン ビューで、前に追加した "What's your name?"TextBlock を選びます。
[プロパティ] ウィンドウ (F4) の右上にある [プロパティ] ボタン (
) を選択します。[Text] グループを展開し、フォント サイズを 18px に設定します。
その他 グループを展開し、スタイル プロパティを探します。
プロパティ マーカー (Style プロパティの右にある緑色のボックス) をクリックし、その後、メニューから [システム リソース]>[BaseTextBlockStyle] の順に選択します。
BaseTextBlockStyle は、<root\Program Files\Windows Kits\10\Include\winrt\xaml\design\generic.xaml 内の ResourceDictionary で定義されているリソースです。
XAML デザイン サーフェイスで、テキストの外観が変化します。 XAML エディターで、TextBlock の XAML が更新されます。
<TextBlock Text="What's your name?" Style="{ThemeResource BaseTextBlockStyle}"/>
このプロセスを繰り返してフォント サイズを設定し、BaseTextBlockStyle を
greetingOutputTextBlock 要素に割り当てます。ヒント この TextBlock にはテキストはありませんが、マウス ポインターを XAML デザイン サーフェイスの上に移動すると、対応する位置に青色の輪郭が表示されて、選択できます。
XAML は次のようになります。
<StackPanel x:Name="contentPanel" Margin="120,30,0,0">
<TextBlock Style="{ThemeResource BaseTextBlockStyle}" FontSize="18" Text="What's your name?"/>
<StackPanel x:Name="inputPanel" Orientation="Horizontal" Margin="0,20,0,20">
<TextBox x:Name="nameInput" Width="300" HorizontalAlignment="Left"/>
<Button x:Name="inputButton" Content="Say "Hello"" Click="Button_Click"/>
</StackPanel>
<TextBlock Style="{ThemeResource BaseTextBlockStyle}" FontSize="18" x:Name="greetingOutput"/>
</StackPanel>
- F5 キーを押して、アプリをビルドし、実行します。 次のように表示されます。
手順 4:異なるウィンドウ サイズに合わせて UI を調整する
次に、モバイル デバイスで適切に表示されるように、さまざまな画面サイズに合わせて UI を調整します。 これを行うには、VisualStateManager を追加して、さまざまな表示状態に適用されるプロパティを設定します。
UI レイアウトを調整するには
- XAML エディターで、ルートの Grid 要素の開始タグの後に、この XAML ブロックを追加します。
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="wideState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="641" />
</VisualState.StateTriggers>
</VisualState>
<VisualState x:Name="narrowState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="contentPanel.Margin" Value="20,30,0,0"/>
<Setter Target="inputPanel.Orientation" Value="Vertical"/>
<Setter Target="inputButton.Margin" Value="0,4,0,0"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
- ローカル マシンでアプリをデバッグします。 UI は、ウィンドウが 641 DIP (デバイスに依存しないピクセル) より狭くならない限り、前と同じように表示されることに注意してください。
- モバイル デバイス エミュレーターでアプリをデバッグします。
narrowStateで定義したプロパティが UI に使用され、小さい画面で適切に表示されていることに注意してください。
以前のバージョンの XAML で VisualStateManager を使ったことがある場合は、この XAML では簡素化された構文が使用されていることに気付くかもしれません。
wideState という名前の VisualState には、AdaptiveTrigger があり、その MinWindowWidth プロパティが 641 に設定されています。 つまり、この状態は、ウィンドウの幅が 641 DIP 以上の場合にのみ適用されることを意味します。 この状態には Setter オブジェクトを定義していないため、XAML でページのコンテンツに対して定義したレイアウト プロパティが使用されます。
2 つ目の VisualState である narrowState で、AdaptiveTrigger の MinWindowWidth プロパティが 0 に設定されています。 この状態は、ウィンドウの幅が 0 より大きく 641 DIP より小さい場合に適用されます (DIP が 641 の時点で、wideState が適用されます。) この状態では、UI 内のコントロールのレイアウトプロパティを変更するために、いくつかの Setter オブジェクトを定義します:
-
contentPanelの左側の余白を 120 から 20 に減らします。 -
inputPanel要素の Orientation を、Horizontal から Vertical に変更します。 -
inputButton要素に、4 DIP の上余白を追加します。
要約
これで、最初のチュートリアルは終わりです。 ここでは、Windowsユニバーサル アプリにコンテンツを追加する方法、アプリにインタラクティブ機能を追加する方法、外観を変更する方法について解説しました。
次の手順
古い Windows ランタイム アプリ プロジェクトを Windows 10 または Windows 11 に移植するには、新しい Windows ユニバーサル プロジェクトから開始して、最新のプロジェクト システム構造とマニフェスト ファイルを取得し、コード ファイルをプロジェクトのディレクトリ構造にコピーし、プロジェクトに項目を追加し、このトピックのガイダンスに従って VisualStateManager を使用して XAML を書き換えます。 詳しくは、「Windows ランタイム 8 プロジェクトのユニバーサル Windows プラットフォーム (UWP) プロジェクトへの移植」と「ユニバーサル Windows プラットフォームへの移植 (C++)」をご覧ください。
UWP アプリと統合したい既存の C++ コードがある場合、たとえば、既存のアプリケーション用に新しい UWP UI を作成する場合、ユニバーサル Windows プロジェクトでの既存の C++ コードの使用に関するページをご覧ください。