アプリケーション ライフサイクル機能の移行

このトピックでは、アプリケーション ライフサイクル領域の移行ガイダンスについて説明します。

重要な API

API と機能の違いの概要

ユニバーサル Windows プラットフォーム (UWP) アプリは既定で単一インスタンス化され、Windows App SDK (WinUI 3) アプリは既定でマルチインスタンス化されます。

UWP アプリには、アプリがどのようにアクティブ化されたかを暗黙的に知らせる OnFileActivatedOnSearchActivatedOnActivatedOnBackgroundActivated などの App メソッドがあります。Windows App SDK アプリでは、App.OnLaunched (または任意のメソッド) 内で、(AppInstance.GetActivatedEventArgs) を呼び出してアクティブ化されたイベント引数を取得して確認し、アプリがどのようにアクティブ化されたかを判定します。

また、「UWP から WinUI 3 への移行時にサポートされる機能」のトピックにある表の "バックグラウンド タスク" 行も参照してください。

単一インスタンス化されたアプリ

ユニバーサル Windows プラットフォーム (UWP) アプリは既定で単一インスタンス化されます (マルチ インスタンスをサポートするように設定することも可能です。「Create a multi-instance UWP app」(マルチインスタンス UWP アプリを作成する) を参照してください)。

単一インスタンス化された UWP アプリの動作として、2 回目 (およびそれ以降) に起動すると、現在のインスタンスがアクティブ化されます。 たとえば、UWP アプリでファイルの種類の関連付け機能を実装したとします。 アプリが既に実行されている時に、エクスプローラーから (アプリでファイルの種類の関連付けに登録した種類の) ファイルを開くと、既に実行されているインスタンスがアクティブ化されます。

Windows App SDK (WinUI 3) アプリは、既定でマルチインスタンス化されます。 そのため、既定では 2 回目 (またはそれ以降) に Windows App SDK (WinUI 3) アプリを起動すると、アプリの新しいインスタンスが起動します。 たとえば、Windows App SDK (WinUI 3) アプリがファイルの種類の関連付けを実装していて、そのアプリが起動している間にエクスプローラーから (正しい種類の) ファイルを開くと、既定ではアプリの新しいインスタンスが起動します。

Windows App SDK (WinUI 3) アプリを、UWP アプリと同じように単一インスタンス化したい場合、上記の既定の動作をオーバーライドすることができます。 AppInstance.FindOrRegisterForKeyAppInstance.IsCurrent を使用すると、現在のインスタンスがメイン インスタンスかどうかを判定できます。 そうでない場合、AppInstance.RedirectActivationToAsync を呼び出してアクティブ化を既に実行されているメイン インスタンスにリダイレクトし、現在のインスタンスを終了します (メイン ウィンドウを作成したりアクティブ化したりする必要はありません)。

詳細については、「App instancing with the app lifecycle API」(アプリのライフサイクル API によるアプリのインスタンス化) を参照してください。

重要

次のコードは、ターゲットが x64 アーキテクチャである場合にのみ正常に動作します。 これは C# と C++/WinRT の両方に適用されます。

Main または wWinMain での単一インスタンス化

アプリ実行時のできる限り早いタイミングで、アクティブ化をリダイレクトする必要があるかを確認するのが最善です。 そのため、アプリの Main (C++/WinRT の場合は wWinMain) 関数で、単一インスタンス化ロジックを実行することを推奨します。 このセクションでは、その方法を説明します。

通常、アプリの Main 関数はビルド システムによって自動生成され、隠しファイルに配置されます。 それで最初の手順は、プロジェクトがその関数を自動生成しないように構成することです。 そのために、プロジェクトの [プロパティ] でシンボル DISABLE_XAML_GENERATED_MAIN を定義します。

C# の手順

[プロパティ]> ([すべての構成][すべてのプラットフォーム] を選択) >[ビルド]>[条件付きコンパイル シンボル] に移動し、シンボル DISABLE_XAML_GENERATED_MAIN を貼り付けます。

プロジェクトが Main 関数を自動生成しないように設定したので、プロジェクトはまだビルドされません。 2 番目かつ最後の手順は、ソース コード ファイルに独自の Main 関数を実装することです。

プロジェクトに、種類が Class の新しいプロジェクト項目を追加して、Program.cs という名前を付けます。 Program.cs の内側で、コード class Program {} を独自の実装に置き換えます。 使用するコードの例については、AppLifecycle サンプルProgram.cs を参照してください。

C++/WinRT の手順

[プロパティ]> ([すべての構成][すべてのプラットフォーム] を選択) >[構成プロパティ]>[C/C++]>[プリプロセッサ]>[プリプロセッサの定義] に移動して値を編集し、シンボル DISABLE_XAML_GENERATED_MAIN を追加します。

プロジェクトが wWinMain 関数を自動生成しないように設定したので、プロジェクトはまだビルドされません。 2 番目かつ最後の手順は、ソース コード ファイルに独自の Main 関数を実装することです。

Microsoft.Windows.ImplementationLibrary NuGet パッケージへの参照を追加し、プロジェクト pch.hApp.xaml.cpp のソース コード ファイルを更新します。 使用するコードの例については、AppLifecycle サンプルを参照してください。 winrt::CppWinUiDesktopInstancing::implementation::App の名前空間は、必ず特定のプロジェクトに合わせて変更してください。

"error C2872: 'Microsoft': あいまいなシンボルです" を解決するために、using namespace Microsoft::UI::Xaml;using namespace winrt::Microsoft::UI::Xaml; に変更します。 using ディレクティブに対して、同様の追加の変更を行います。

Application.OnLaunched での単一インスタンス化

Main または wWinMain を使用する代わりに、App クラスの Application.OnLaunched メソッドで、単一インスタンス化ロジックを実行することもできます。

重要

この作業を Application.OnLaunched で行うと、アプリを簡素化できます。 ただし、アプリがほかに何をするかによって大きく異なります。 最終的にリダイレクトを行ってから現在のインスタンスを終了する場合、使い捨ての作業 (または元に戻す必要がある作業) を行いたくはないでしょう。 そのような場合、Application.OnLaunched では遅すぎるので、アプリの Main または wWinMain 関数で行うほうがよいかもしれません。

// App.xaml.cs in a Windows App SDK (WinUI 3) app
...
protected override async void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
    // If this is the first instance launched, then register it as the "main" instance.
    // If this isn't the first instance launched, then "main" will already be registered,
    // so retrieve it.
    var mainInstance = Microsoft.Windows.AppLifecycle.AppInstance.FindOrRegisterForKey("main");

    // If the instance that's executing the OnLaunched handler right now
    // isn't the "main" instance.
    if (!mainInstance.IsCurrent)
    {
        // Redirect the activation (and args) to the "main" instance, and exit.
        var activatedEventArgs =
            Microsoft.Windows.AppLifecycle.AppInstance.GetCurrent().GetActivatedEventArgs();
        await mainInstance.RedirectActivationToAsync(activatedEventArgs);
        System.Diagnostics.Process.GetCurrentProcess().Kill();
        return;
    }

    m_window = new MainWindow();
    m_window.Activate();
}
// pch.h in a Windows App SDK (WinUI 3) app
...
#include <winrt/Microsoft.Windows.AppLifecycle.h>
...

// App.xaml.h
...
struct App : AppT<App>
{
    ...
    winrt::fire_and_forget OnLaunched(Microsoft::UI::Xaml::LaunchActivatedEventArgs const&);
    ...
}

// App.xaml.cpp
...
using namespace winrt;
using namespace Microsoft::Windows::AppLifecycle;
...
winrt::fire_and_forget App::OnLaunched(LaunchActivatedEventArgs const&)
{
    // If this is the first instance launched, then register it as the "main" instance.
    // If this isn't the first instance launched, then "main" will already be registered,
    // so retrieve it.
    auto mainInstance{ AppInstance::FindOrRegisterForKey(L"main") };

    // If the instance that's executing the OnLaunched handler right now
    // isn't the "main" instance.
    if (!mainInstance.IsCurrent())
    {
        // Redirect the activation (and args) to the "main" instance, and exit.
        auto activatedEventArgs{ AppInstance::GetCurrent().GetActivatedEventArgs() };
        co_await mainInstance.RedirectActivationToAsync(activatedEventArgs);
        ::ExitProcess(0);
        co_return;
    }

    window = make<MainWindow>();
    window.Activate();
}

または、AppInstance.GetInstances を呼び出して、実行中の AppInstance オブジェクトのコレクションを取得できます。 そのコレクションの要素数が 1 よりも大きい場合、メイン インスタンスは既に実行中なので、それにリダイレクトする必要があります。

ファイルの種類の関連付け

Windows App SDK プロジェクトで、ファイルの種類の関連付けの拡張ポイントを指定するために、UWP プロジェクトでするのと同じ設定を、Package.appxmanifest ファイルで行います。 その設定は次の通りです。

Package.appxmanifest を開きます。 [宣言] で、[ファイルの種類の関連付け] を選択して、[追加] をクリックします。 次のプロパティを設定します。

表示名: MyFile 名前: myfile ファイルの種類: .myf

ファイルの種類の関連付けを登録するには、アプリをビルドして起動し、閉じます。

違いは命令型コードに現れます。 UWP アプリでは、ファイルのアクティブ化を処理するために App::OnFileActivated を実装します。 Windows App SDK アプリの場合は、App::OnLaunched でコーディングして、アクティブ化されたイベント引数 (AppInstance.GetActivatedEventArgs) の拡張されたアクティブ化の種類 (ExtendedActivationKind) をチェックし、そのアクティブ化がファイルのアクティブ化かどうかを確認します。

Note

アクティブ化の種類を判定するために、App::OnLaunched に渡される Microsoft.UI.Xaml.LaunchActivatedEventArgs オブジェクトを使用しないでください。無条件で "Launch" を報告するからです。

アプリにナビゲーションがある場合、App::OnLaunched にナビゲーション コードがあるはずなので、そのロジックを再利用することができます。 詳細については、「Do I need to implement page navigation?」(ページ ナビゲーションを実装する必要がありますか?) を参照してください。

// App.xaml.cs in a Windows App SDK app
...
using Microsoft.Windows.AppLifecycle;
...
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
    var activatedEventArgs = Microsoft.Windows.AppLifecycle.AppInstance.GetCurrent().GetActivatedEventArgs();
    if (activatedEventArgs.Kind == Microsoft.Windows.AppLifecycle.ExtendedActivationKind.File)
    {
        ...
    }
    ...
}
// pch.h in a Windows App SDK app
...
#include <winrt/Microsoft.Windows.AppLifecycle.h>

// App.xaml.cpp
...
using namespace Microsoft::Windows::AppLifecycle;
...
void App::OnLaunched(LaunchActivatedEventArgs const&)
{
    auto activatedEventArgs{ AppInstance::GetCurrent().GetActivatedEventArgs() };
    if (activatedEventArgs.Kind() == ExtendedActivationKind::File)
    {
        ...
    }
    ...
}

OnActivated、OnBackgroundActivated、その他のアクティブ化処理メソッド

UWP アプリで、アプリをアクティブ化するさまざまな手段をオーバーライドするために、App クラスで OnFileActivatedOnSearchActivated、またはより一般的な OnActivated などの対応するメソッドをオーバーライドできます。

Windows App SDK アプリでは、App.OnLaunched で (または任意のタイミングで)、(AppInstance.GetActivatedEventArgs) を呼び出して、アクティブ化されたイベント引数を取得して確認し、アプリがどのようにアクティブ化されたかを判定できます。

詳細とコード例については、上記の「ファイルの種類の関連付け」セクションを参照してください。 同じ手法は、ExtendedActivationKind 列挙値で指定されているすべてのアクティブ化の種類に適用できます。