|
| 1 | +--- |
| 2 | +title: Application lifecycle functionality migration |
| 3 | +description: This topic contains migration guidance in the application lifecycle area. |
| 4 | +ms.topic: article |
| 5 | +ms.date: 09/20/2021 |
| 6 | +keywords: Windows, App, SDK, migrate, migrating, migration, port, porting, application lifecycle, applifecycle, application, lifecycle |
| 7 | +ms.author: stwhi |
| 8 | +author: stevewhims |
| 9 | +ms.localizationpriority: medium |
| 10 | +dev_langs: |
| 11 | + - csharp |
| 12 | + - cppwinrt |
| 13 | +--- |
| 14 | + |
| 15 | +# Application lifecycle functionality migration |
| 16 | + |
| 17 | +This topic contains migration guidance in the application lifecycle area. |
| 18 | + |
| 19 | +## Important APIs |
| 20 | + |
| 21 | +* [**AppInstance**](/windows/windows-app-sdk/api/winrt/microsoft.windows.applifecycle.appinstance) class |
| 22 | +* [**Application.OnLaunched**](/windows/winui/api/microsoft.ui.xaml.application.onlaunched) method |
| 23 | +* [**AppInstance.GetActivatedEventArgs**](/windows/windows-app-sdk/api/winrt/microsoft.windows.applifecycle.appinstance.getactivatedeventargs) method |
| 24 | +* [**ExtendedActivationKind**](/windows/windows-app-sdk/api/winrt/microsoft.windows.applifecycle.extendedactivationkind) enum |
| 25 | + |
| 26 | +## Single-instanced apps |
| 27 | + |
| 28 | +Universal Windows Platform (UWP) apps are single-instanced by default (you can opt in to support multiple instances—see [Create a multi-instance UWP app](/windows/uwp/launch-resume/multi-instance-uwp)). |
| 29 | + |
| 30 | +So the way a single-instanced UWP app behaves is that the second (and subsequent) time you launch, your current instance is activated. Let's say for example that in your UWP app you've implemented the file type association feature. If from File Explorer you open a file (of the type for which the app has registered a file type association)—and your app is already running—then that already-running instance is activated. |
| 31 | + |
| 32 | +Windows App SDK (WinUI 3) apps, on the other hand, are multi-instanced by default. So, by default, the second (and subsequent) time you launch a Windows App SDK (WinUI 3) app, a new instance of the app is launched. If for example a Windows App SDK (WinUI 3) app implements file type association, and from File Explorer you open a file (of the right type) while that app is already running, then by default a new instance of the app is launched. |
| 33 | + |
| 34 | +If you want your Windows App SDK (WinUI 3) app to be single-instanced like your UWP app is, then you can override the default behavior described above. You can do that in the [**Application.OnLaunched**](/windows/winui/api/microsoft.ui.xaml.application.onlaunched) method of your **App** class. |
| 35 | + |
| 36 | +> [!NOTE] |
| 37 | +> Adding the code shown below to **Application.OnLaunched** can simplify your app. However, a lot depends on what else your app is doing. If you're going to end up redirecting, and then terminating the current instance, then you'll want to avoid doing any throwaway work (or even work that needs explicitly undoing). In cases like that, **Application.OnLaunched** might be too late, and you might prefer to do the work in your app's **main** function (or equivalent). |
| 38 | +
|
| 39 | +In **OnLaunched**, use [**AppInstance.FindOrRegisterForKey**](/windows/windows-app-sdk/api/winrt/microsoft.windows.applifecycle.appinstance.findorregisterforkey) and [**AppInstance.IsCurrent**](/windows/windows-app-sdk/api/winrt/microsoft.windows.applifecycle.appinstance.iscurrent) to determine whether the current instance is the main instance. If it isn't, then call [**AppInstance.RedirectActivationToAsync**](/windows/windows-app-sdk/api/winrt/microsoft.windows.applifecycle.appinstance.redirectactivationtoasync) to redirect activation to the already-running main instance, and then exit from the current instance (without creating nor activating its main window). |
| 40 | + |
| 41 | +For more info, see [App instancing in AppLifecycle](/windows/apps/windows-app-sdk/applifecycle/applifecycle-instancing). |
| 42 | + |
| 43 | +```csharp |
| 44 | +// App.xaml.cs in a Windows App SDK (WinUI 3) app |
| 45 | +... |
| 46 | +protected override async void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args) |
| 47 | +{ |
| 48 | + // If this is the first instance launched, then register it as the "main" instance. |
| 49 | + // If this isn't the first instance launched, then "main" will already be registered, |
| 50 | + // so retrieve it. |
| 51 | + var mainInstance = Microsoft.Windows.AppLifecycle.AppInstance.FindOrRegisterForKey("main"); |
| 52 | + |
| 53 | + // If the instance that's executing the OnLaunched handler right now |
| 54 | + // isn't the "main" instance. |
| 55 | + if (!mainInstance.IsCurrent) |
| 56 | + { |
| 57 | + // Redirect the activation (and args) to the "main" instance, and exit. |
| 58 | + var activatedEventArgs = |
| 59 | + Microsoft.Windows.AppLifecycle.AppInstance.GetCurrent().GetActivatedEventArgs(); |
| 60 | + await mainInstance.RedirectActivationToAsync(activatedEventArgs); |
| 61 | + System.Diagnostics.Process.GetCurrentProcess().Kill(); |
| 62 | + return; |
| 63 | + } |
| 64 | + |
| 65 | + m_window = new MainWindow(); |
| 66 | + m_window.Activate(); |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +```cppwinrt |
| 71 | +// pch.h in a Windows App SDK (WinUI 3) app |
| 72 | +... |
| 73 | +#include <winrt/Microsoft.Windows.AppLifecycle.h> |
| 74 | +... |
| 75 | +
|
| 76 | +// App.xaml.h |
| 77 | +... |
| 78 | +struct App : AppT<App> |
| 79 | +{ |
| 80 | + ... |
| 81 | + winrt::fire_and_forget OnLaunched(Microsoft::UI::Xaml::LaunchActivatedEventArgs const&); |
| 82 | + ... |
| 83 | +} |
| 84 | +
|
| 85 | +// App.xaml.cpp |
| 86 | +... |
| 87 | +using namespace winrt; |
| 88 | +using namespace Microsoft::Windows::AppLifecycle; |
| 89 | +... |
| 90 | +winrt::fire_and_forget App::OnLaunched(LaunchActivatedEventArgs const&) |
| 91 | +{ |
| 92 | + // If this is the first instance launched, then register it as the "main" instance. |
| 93 | + // If this isn't the first instance launched, then "main" will already be registered, |
| 94 | + // so retrieve it. |
| 95 | + auto mainInstance{ AppInstance::FindOrRegisterForKey(L"main") }; |
| 96 | +
|
| 97 | + // If the instance that's executing the OnLaunched handler right now |
| 98 | + // isn't the "main" instance. |
| 99 | + if (!mainInstance.IsCurrent()) |
| 100 | + { |
| 101 | + // Redirect the activation (and args) to the "main" instance, and exit. |
| 102 | + auto activatedEventArgs{ AppInstance::GetCurrent().GetActivatedEventArgs() }; |
| 103 | + co_await mainInstance.RedirectActivationToAsync(activatedEventArgs); |
| 104 | + ::ExitProcess(0); |
| 105 | + co_return; |
| 106 | + } |
| 107 | +
|
| 108 | + window = make<MainWindow>(); |
| 109 | + window.Activate(); |
| 110 | +} |
| 111 | +``` |
| 112 | + |
| 113 | +Alternatively, you can call [**AppInstance.GetInstances**](/windows/windows-app-sdk/api/winrt/microsoft.windows.applifecycle.appinstance.getinstances) to retrieve a collection of running [**AppInstance**](/windows/windows-app-sdk/api/winrt/microsoft.windows.applifecycle.appinstance) objects. If the number of elements in that collection is greater than 1, then your main instance is already running, and you should redirect to that. |
| 114 | + |
| 115 | +## File type association |
| 116 | + |
| 117 | +In a Windows App SDK project, to specify the extension point for a file type association, you make the same settings in your `Package.appxmanifest` file as you would for a UWP project. Here are those settings. |
| 118 | + |
| 119 | +Open `Package.appxmanifest`. In **Declarations**, choose **File Type Associations**, and click **Add**. Set the following properties. |
| 120 | + |
| 121 | +**Display name**: MyFile |
| 122 | +**Name**: myfile |
| 123 | +**File type**: .myf |
| 124 | + |
| 125 | +To register the file type association, build the app, launch it, and close it. |
| 126 | + |
| 127 | +The difference comes in the imperative code. In a UWP app, you implement **App::OnFileActivated** in order to handle file activation. But in a Windows App SDK app, you write code in **App::OnLaunched** to check the extended activation kind ([**ExtendedActivationKind**](/windows/windows-app-sdk/api/winrt/microsoft.windows.applifecycle.extendedactivationkind)) of the activated event args ([**AppInstance.GetActivatedEventArgs**](/windows/windows-app-sdk/api/winrt/microsoft.windows.applifecycle.appinstance.getactivatedeventargs)), and see whether the activation is a file activation. |
| 128 | + |
| 129 | +> [!NOTE] |
| 130 | +> Don't use the [**Microsoft.UI.Xaml.LaunchActivatedEventArgs**](/windows/winui/api/microsoft.ui.xaml.launchactivatedeventargs) object passed to **App::OnLaunched** to determine the activation kind, because it reports "Launch" unconditionally. |
| 131 | +
|
| 132 | +If your app has navigation, then you'll already have navigation code in **App::OnLaunched**, and you might want to re-use that logic. For more info, see [Do I need to implement page navigation?](winui3.md#do-i-need-to-implement-page-navigation). |
| 133 | + |
| 134 | +```csharp |
| 135 | +// App.xaml.cs in a Windows App SDK app |
| 136 | +... |
| 137 | +using Microsoft.Windows.AppLifecycle; |
| 138 | +... |
| 139 | +protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args) |
| 140 | +{ |
| 141 | + var activatedEventArgs = Microsoft.Windows.AppLifecycle.AppInstance.GetCurrent().GetActivatedEventArgs(); |
| 142 | + if (activatedEventArgs.Kind == Microsoft.Windows.AppLifecycle.ExtendedActivationKind.File) |
| 143 | + { |
| 144 | + ... |
| 145 | + } |
| 146 | + ... |
| 147 | +} |
| 148 | +``` |
| 149 | + |
| 150 | +```cppwinrt |
| 151 | +// pch.h in a Windows App SDK app |
| 152 | +... |
| 153 | +#include <winrt/Microsoft.Windows.AppLifecycle.h> |
| 154 | +
|
| 155 | +// App.xaml.cpp |
| 156 | +... |
| 157 | +using namespace Microsoft::Windows::AppLifecycle; |
| 158 | +... |
| 159 | +void App::OnLaunched(LaunchActivatedEventArgs const&) |
| 160 | +{ |
| 161 | + auto activatedEventArgs{ AppInstance::GetCurrent().GetActivatedEventArgs() }; |
| 162 | + if (activatedEventArgs.Kind() == ExtendedActivationKind::File) |
| 163 | + { |
| 164 | + ... |
| 165 | + } |
| 166 | + ... |
| 167 | +} |
| 168 | +``` |
| 169 | + |
| 170 | +## OnActivated, OnBackgroundActivated, and other activation-handling methods |
| 171 | + |
| 172 | +In a UWP app, to override the various means by which your app can be activated, you can override corresponding methods on your **App** class, such as **OnFileActivated**, **OnSearchActivated**, or the more general **OnActivated**. |
| 173 | + |
| 174 | +In a Windows App SDK app, in **App.OnLaunched** (or in fact at any time) you can call ([**AppInstance.GetActivatedEventArgs**](/windows/windows-app-sdk/api/winrt/microsoft.windows.applifecycle.appinstance.getactivatedeventargs)) to retrieve the activated event args, and check them to determine how the app was activated. |
| 175 | + |
| 176 | +See the [File type association](#file-type-association) section above for more details and a code example. You can apply the same technique for any activation kind specified by the [**ExtendedActivationKind**](/windows/windows-app-sdk/api/winrt/microsoft.windows.applifecycle.extendedactivationkind) enum. |
| 177 | + |
| 178 | +## Related topics |
| 179 | + |
| 180 | +* [App instancing in AppLifecycle](/windows/apps/windows-app-sdk/applifecycle/applifecycle-instancing) |
| 181 | +* [Do I need to implement page navigation?](winui3.md#do-i-need-to-implement-page-navigation) |
0 commit comments