microsoft / WindowsAppSDK

The Windows App SDK empowers all Windows desktop apps with modern Windows UI, APIs, and platform features, including back-compat support, shipped via NuGet.
https://docs.microsoft.com/windows/apps/windows-app-sdk/
MIT License
3.84k stars 320 forks source link

App Lifecycle #111

Closed andreww-msft closed 3 years ago

andreww-msft commented 4 years ago
Summary Status

Customer / job-to-be-done: App developers using WPF, WinForms, or Win32 C++ need to register for certain activation types like file associations and startup activation, need to selectively single-instance their apps, and need to use power states to selectively suspend their apps.

Problem: Non-packaged apps use a different set of APIs to achieve all of the above, and they also don't have access to power state notifications

How does our solution make things easier? All types of apps will benefit from the same single API regardless of app type, apps can now listen to power states, and WIn32 apps have a built-in easy way to single instance.

βœ… Problem validation
❌ Docs
πŸ”„ Dev spec
❌ Solution validation
❌ Implementation
❌ Samples

Summary

Provide a core set of functionality related to app activation and lifecycle. The initial release focuses on the following 4 main feature areas:

  1. Activation.
  2. Selective Multi-instancing.
  3. Restart and Recovery.
  4. Power/State Notifications.

Rationale

This aligns with Project Reunion's roadmap:

Scope

Capability Priority
This proposal will allow developers to use the same mechanism to register for different activation kinds regardless of app technology (classic Win32, Windows Forms, WPF, UWP or WinUI). Must
This proposal will allow developers to use the same mechanism to get rich activation event arguments regardless of app technology. Must
This proposal will allow users to activate any app by double-clicking it in file explorer, or typing in a path in a command window. Must
This proposal will allow developers to use a consistent mechanism to single-instance or multi-instance their apps, based on app-defined logic. Must
This proposal will allow developers to use a consistent mechanism to take part in app and system restart and recovery. Must
This proposal will allow developers to use a consistent mechanism to get power and system state notifications. Must
This proposal will allow apps to better tune their operations to improve power/battery usage. Must
This proposal will allow developers to take part in system resource management Could
This proposal will allow developers to take part in app suspend/resume behavior Could

Important Notes

Rich Activation Behaviors

The activation part of the AppLifecycle component is focused on the following 4 functional requirements:

CreateProcess activation

In the Win32 world, it is normal to activate an app by calling CreateProcess (or ShellExecute), specifying the filesystem path to the executable file. When the user double-clicks an executable file in File Explorer, this uses that same mechanism. When the user types in an executable file name into a command window, the same thing happens. In contrast, up until now, when a UWP or Desktop Bridge app is activated, this is done via the app's Application User Model ID (AUMID). For example, when an app calls Launcher.LaunchUriAsync, it specifies the target AUMID -- or a file or protocol, which causes the platform to look up registered AUMIDs in its State Repository database, before activating the app.

The Windows a-la-carte features introduced in 2004 include the ability to activate an app via CreateProcess on its path, as well as by the UWP AUMID lookup. The gap here is that the CreateProcess mechanism only works for Win32 apps -- as part of Reunion, we will bring this to packaged (Desktop Bridge and UWP) apps also.

With this, you will be able to CreateProcess a UWP app by specifying the path to its executable, or navigate to the filesystem location and double-click it there.

Activation kinds

UWP supports \~40 different activation kinds. Traditional Win32 apps have a much smaller set available -- the most common being file-type associations and protocol handling. In UWP both of these are formalized into specific activation contracts (ActivationKind.File and ActivationKind.Protocol) and when the app is activated in this way, the platform passes in rich FileActivatedEventArgs or ProtocolActivatedEventArgs. The same applies for command-line activation, activation at user login (startup activation), and so on.

Of the many different kinds of activation that UWP supports, 6 of the most commonly-used kinds are also supported for Desktop Bridge apps, and almost the same set is supported for Windows a-la-carte apps. We will support this core set of activation kinds for unpackaged Win32 apps also, plus command-line and restart activation. So the initial list is as follows:

How should we ask developers to specify their registrations for the various activation kinds? For the activation kinds that are supported in Win32 -- such as file and protocol -- apps commonly write registry keys. Conversely, UWP apps write morally equivalent extension entries in their regular MSIX manifest.

Apps that write regkeys on install sometimes don't clean them up on uninstall, and this is a primary source of winrot. This is one of the main benefits of MSIX. Therefore, the proposal is to encourage app developers to specify their activation registrations in an XML manifest rather than in the registry.

An additional advantage of the manifest approach is that it also provides an easy way for the app to get identity. The proposal is that we ask an app to craft some subset of an MSIX manifest -- sufficient for the activation extension registrations, plus identity. We will not require that the app is MSIX-packaged, merely that they have a simple manifest. While this will be a subset of the full MSIX manifest, it must use the same schemas. The platform can then use the same Deployment Extension Handlers (DEHs) on deployment to register these extensions.

Activation and ActivatedEventArgs

Traditional Win32 apps expect to get their arguments passed into WinMain in the form of a string array. Windows Forms apps expect to call Environment.GetCommandLineArgs to return a string array. ulti-instanced UWP and Desktop Bridge apps can call the AppInstance.GetActivatedEventArgs API to return strongly-typed objects for each activation kind. We will provide a converged GetActivatedEventArgs which will get all args, regardless of activation kind -- including both traditional command-line activation and also the richer UWP activation objects. This will be available to all apps.

Activation broker

Two of the proposed activation kinds present particular problems: ToastNotification and ShareTarget. Both of these will likely require some additional component at runtime to act as a broker between the source and target of the activation.

The a-la-carte model has paved the way for apps of all kinds to get a system-recognized identity. This then provides several benefits when using modern features -- including the activation kinds under consideration for the undocked AppLifecycle component. We would like to use the a-la-carte model for undocked activation. However, there are a few issues:

Identity

Both UWP and Desktop Bridge apps have an identity that is registered on the platform, and on which multiple APIs in the platform rely. Unpackaged Win32 apps do not have such an identity, and therefore cannot use any of the APIs that require identity.

In the Windows a-la-carte model, the app creates an XML manifest specifying its identity, and registers this with the system during install (or at runtime) via new PackageManager APIs.

There is an initiative in the Cobalt timeframe to enable the Store to serve up unpackaged Win32 apps in addition to UWP and Desktop Bridge apps. This is part of a general strategy of de-fragmenting the user experience of apps. Right now, there are several places where packaged apps are treated differently from unpackaged apps. A user experience example is the Apps & features page, where the options are differentiated. A more critical example is in the API surface where many WinRT APIs require the caller to have identity.

Crucially, some WinRT APIs behave differently depending on whether or not the caller has identity. Given that even unpackaged Win32 apps are already using WinRT APIs, we cannot apply identity unless the app specifically registers for identity. Instead, if an app wants to call an API, we should simply document whether or not that API requires identity, and guide the app developer to creating the appropriate manifest if they need it.

Single/Multi-Instancing

In the Win32 world, apps are multi-instance by default. That is, if the user launches Notepad 3 times in a row, they get 3 separate instances of the app. Conversely, in the UWP world, apps are single-instance by default: if the user launches Maps times in a row, the first request causes the Maps app to launch, and the second and subsequent requests cause the platform to make another activation call into the first (and only) instance.

Since Windows OS version 1803, a UWP app can opt in to multi-instancing via a manifest declaration. This feature also includes APIs to allow an app to declare itself to be multi-instanced, and yet to choose dynamically for each instance that is activated whether in fact it wants to redirect that activation to an existing instance instead. In this way, the app has the freedom to choose among several options:

Win32 apps have existing mechanisms (most commonly, named mutexes and named pipes) which they can use to achieve single-instancing in this context. There's also a Visual Basic Application Model which Windows Forms apps (whether written in Visual Basic or not) can use for single-instancing. The undocked AppLifecycle component will include a consistent, platform-supported API for selective multi/single-instancing. This updates the UWP mechanism and enables it for use by Desktop Bridge and unpackaged Win32 apps.

The specific multi-instance redirection APIs that we will provide for all apps are all based on the existing WinRT AppInstance class. The proposal is to expose equivalents to almost all AppInstance methods and properties from the new AppLifecycle class.

The existing APIs allow an app to intercept each activation, find any other running instances, and choose which instance to handle the new activation (either the current instance, or any other). The app doesn't control the activation event args -- these are simply directed to the chosen instance. In the Win32 world, apps have the opportunity to intercept the args, and therefore have the opportunity to modify/suppress/replace these args before forwarding them on. So, we propose to enhance the existing WinRT APIs to allow each activation to pass in additional payload to the target instance (at a lower priority, possibly deferred to a later release). This payload is in addition to the ActivatedEventArgs that the system originally passed in, and which the system will pass on to the target activated instance.

The multi-instancing part of the AppLifecycle component is focused on the following functional requirements:

App Restart and Recovery

The CoreApplication WinRT class exposes the RequestRestartAsync method, which allows a UWP app to terminate and restart itself immediately, on request, and to provide an arbitrary command-line string for the restarted instance.

A related API exists in the Win32 world: RegisterApplicationRestart and the matching UnregisterApplicationRestart API. This is intended for an app to register itself to be restarted if it was running when a system update occurs, or if it crashed or hung. This behavior is currently not available to UWP apps.

The use-cases for these 2 APIs are different, but related enough that it makes sense to offer both from the same place in the undocked AppLifecycle.

Related to RegisterApplicationRestart, there are 2 further Win32 APIs that enable an app to save state or perform other clean-up operations prior to termination. As part of this recovery, the app can choose to update the command-line to be used when the app is restarted:

These APIs will also be included in the Converged AppLifecycle component.

Improved Power Usage

For UWP apps, a major factor in improving device power usage and battery life is that the platform can suspend an app if the user is not actively engaged in it. UWP apps are familiar with the suspend/resume aspects of app lifecycle. That said, the suspend/resume behavior is not without problems. Power usage and battery life is an important factor for users, and there are 2 main aspects in this spec:

  1. System state changes: notifications that the system sends to an app when interesting battery/power changes occur (eg, switching between AC and DC, critical power level changes, critical battery level changes, etc). In addition to power state, we'll send notifications for other interesting events such as user inactive, screen off, and so on -- since these can also be used by an app to better tune its work. All of these are simply informative notifications: the app can do whatever it likes with the information.

  2. Suspend/resume or resource throttling: for UWP apps, the platform has heuristics to determine when to suspend or resume an app, including whether the main window is minimized, whether certain critical background triggers are fired, and so on. The pattern here is more than a simple notification, specifically: a. There is a notification that suspension is imminent. b. There is an opportunity for the app to defer suspension for a finite period so that it can complete some arbitrary work. After this period, the app will be suspended. c. There is a notification that the app is being resumed from suspension.

Note: it will likely be difficult for many Win32 apps to adopt UWP-style suspend/resume, but more apps might want to take part in resource throttling, and all apps could listen for interesting power/system-state notifications if they wish.

The proposed features for this part of the AppLifecycle component are as follows:

Power state changes

There are several existing APIs which apps can use to detect changes in battery/power status, in order to participate in improved battery life.

These APIs cover most if not all of the battery/power state change scenarios that apps would care about -- but there's no single API that is consumable by all app types. There's also no single API that's undocked from the OS. The proposal is to incorporate a clone of the W.S.P.PowerManager API in the undocked AppLifecycle component, and augment it with additional notifications based on the Win32 PowerSettingRegisterNotification API.

Suspend/resume and throttling

In UWP-style suspend/resume behavior, the constraints of the UWP app-container allow the system to suspend the app safely. Conversely, traditional Win32 apps can't always reliably be suspended because they might be using system-wide resources (file handles, named pipes, etc), so suspending the app would lock these resources, and the platform has no mechanism to deal with this scenario. Such apps would not opt in to UWP suspend/resume.

What does suspend/resume actually mean? When an app is suspended it remains in memory, but its threads are not scheduled to run -- this allows the system to restore it quickly when needed.

When does an app get suspended? In the UWP world, the most obvious manifestation is when the app's main window is minimized this is usually (but not always) following by the app getting suspended. The system can use its own heuristics and policies to decide when is a good time to suspend an app, including (but not limited to) when the app has no foreground, un-obscured or un-minimized windows.

What should an app do in its suspending handler? The key reason an app wants to know when it is about to be suspended is that there's no guarantee that the system will ever resume it, and might terminate the app at any time while it is suspended -- therefore the suspending event is the app's opportunity to save state such that it can pick up again seamlessly when it is next activated. If a suspended UWP app is holding a file open, the system can terminate the app if necessary to release the lock.

Even some UWP apps have found that the suspend/resume behavior can be difficult to work with. One mitigation that the platform offers is the option to take a SuspendingDeferral in the Suspending event handler. The app is given a SuspendingEventArgs which includes a method to request a deferral. On top of that, beyond a simple deferral, an app can request an ExtendedExecution -- including potentially an indefinite extension (although this is rarely granted, by policy).

Given the difficulties that UWP apps experience with suspend/resume, and the added complexities of Win32 apps which perform operations outside the control or awareness of an app-container context, it is most likely that very few complex Win32 apps would be able to use UWP-style suspend/resume, and a trivially simply Win32 app is unlikely to be a significant resource-hog. However, there are likely more apps that could take part in some form of throttling -- and especially if the throttling is under app control. Exactly how this throttling might work is TBD.

Recognition for good citizens

Apps will want to opt in to lifecycle and resource management because they want to be good citizens. To further incentivize apps, we should also surface this to the user in some way. One approach would be to add a "battery-aware" or "good resource citizen" badge in the Apps & features list in Settings, similar to the badge used in the traditional TaskManager (although this badge is conferred simply whenever the app is suspended).

We could apply the badge for any app that opts in to throttling and/or suspension. Note: simply registering for power state change notifications is not enough to qualify: the app could respond to low power/battery states by doing less work -- or it could respond by doing more work.

It has been pointed out that neither TaskManager nor the Apps & Features page in Settings are highly visible, especially to a non-technical user. Two other options present for consideration:

Final implementation TBD.

Open Questions

mdtauk commented 4 years ago

Would this be a good place to consider how the app behaves when an App Update is installed from the store, to prevent apps restarting in the middle of the user working on an unsaved document?

Also could this allow WinUI Desktop apps to opt-in to the UWP Permissions system?

jesbis commented 4 years ago

Should #9 be closed in favor of this?

ptorr-msft commented 4 years ago

@mdtauk permissions are mostly relevant only within the context of an AppContainer, so this proposal alone won't do anything to enable Win32 apps to have the same experience as UWP apps. We're interested in doing more here but it should be a separate issue.

dremin commented 4 years ago

As a part of these changes, it would be great if UWP app activation no longer relied upon explorer.exe running!

jonwis commented 4 years ago

@dremin - we're definitely aware of that! Is there a specific use case you're looking for that it'd enable for you?

dremin commented 4 years ago

@jonwis For me, that would be fantastic to allow for alternate shells (such as one I maintain) to continue to exist in the future. As more functionality moves into UWP applications, alternate shells have unfortunately become far less feasible (and running an alternate shell atop Explorer brings its own set of issues).

riverar commented 4 years ago

Feedback

  1. The proposal uses some internal jargon that requires definition:

    • Windows a-la-carte
    • Cobalt timeframe
  2. The proposal has spacing issues that need correction and would greatly improve readability.

Questions

  1. With regards to CreateProcess activation of modern apps, the proposal suggests "you will be able to CreateProcess a UWP app by [...navigating to the] filesystem location and double-click". With most modern apps being delivered via the Microsoft Store, this puts apps in an un-browsable location on disk. How will users double-click these app executables? What if the package manifest has multiple applications specified?

  2. With regards to activation, the proposal suggests that apps should have a "simple manifest", perhaps "a subset of the full MSIX manifest". The proposal, however, leaves the location of this manifest open-ended. Will this manifest sit side-by-side with the executable? Can it be embedded, a la fusion manifests?

Answers to open questions

Should we include the broker model in v1 of Reunion so that apps can target down to 1809, or do we defer support for ShareTarget -- and avoid the need for a broker -- until a later release when apps might be OK with targeting only down to 2004?

Target 1809. 1809 EOL is May 11, 2021. Users will not be able to min-target 2004 until ~May 10, 2022.

Can we provide a way for unpackaged apps to have identity without undocking the whole of Windows a-la-carte?

It's not clear what "undocking the whole of Windows a-la-carte" refers to. But I suggest re-using the appxmanifest approach as outlined in Activation kinds above. Beware of certain areas in Windows that perform caller identity checking as a security mechanism.

Is there any suspend/resume or resource (CPU, network) throttling behavior that would actually be useful for a traditional Win32 app to take part in, or is this just too difficult to work with?

Would be great if desktop applications could opt-into behaviors that realized connection costs/limits/metering (e.g. a la Windows.Networking.Connectivity.ConnectionCost).

riverar commented 4 years ago

@jonwis Sometimes I have the need to kill File Explorer via Task Manager. Or update an app that restarts the shell to update a shell extension. When I do these things, app modern apps often terminate.

weltkante commented 4 years ago

@riverar FYI clean shutdown of explorer is possible when its not hung, in the shutdown dialog (e.g. click the taskbar and Alt+F4) hold ctrl+alt+shift and press cancel. This is documented for shell extension authors to test their extensions without rebooting.

(for anyone else coming across this in the future: to restart it run explorer from task manager)

Never tested this before so I don't know if its consistent across versions but UWP apps seem to stay open and stop rendering when you close explorer this way, when you restart explorer they all seem to close. In general very poor behavior.

riverar commented 4 years ago

@weltkante TIP: Ctrl+Shift then right-clicking Taskbar also offers a Exit Explorer option.

Where is this officially documented? It doesn't work properly on Windows 10 Version 2004. My Mail app terminated. Further, starting a new File Explorer process resulted in a shell load/crash loop that I had to resolve manually.

weltkante commented 4 years ago

Thanks, wasn't aware.

Where is this officially documented?

That was years ago when I had to write an explorer extension, seems the docs are updated to use the method you mentioned, but they still list the other method as well, even if not recommending it. [edit] here is the version in the new doc system

I mostly just chime in when someone speaks of "killing explorer" because clean shutdown is often preferrable to killing processes. Will mention your method in the future since it seems preferable.

riverar commented 4 years ago

@stevewri I see the "needs-triage" tag was removed. Can you provide more details as to what that means for proposals as such? I have unanswered questions above.

stevewri commented 4 years ago

Needs-triage is the bot-assigned label for new issues; triage is just the process of routing it to the right area label and owner.

lukeblevins commented 4 years ago

@andreww-msft Reading this proposal made me think about Microsoft Edge's use of sparse MSIX to register PWAs/better integrate with Windows. (Currently behind a flag)

When you say any "app technology", are you referring to scenarios like this? In other words, is it possible for sparse MSIX packages registered by Edge to take advantage of the WinRT app lifecycle improvements?

VagueGit commented 4 years ago

Would it be possible for an app to declare, as a UWP app declares capabilities, it's need to remain open until the user shuts it down? This is important for business apps. I know most of these currently are Win32/Web, but moving forward this capability should be available I think.

ptorr-msft commented 4 years ago

Hi @VagueGit, can you be more specific? Apps can already use confirmAppClose to implement "Are you sure you want to exit?" style dialogs, and extendedExecution on Desktop to keep running when minimized. Is there another scenario you're thinking of?

VagueGit commented 4 years ago

@ptorr-msft Currently we have to deal with UWP apps being suspended and request an extendedExecution, but this might be denied. It would be nice not to have to deal with it at all.

If the app could declare on install that it doesn't want Windows to suspend it and give the user the option to accept that, then the issue goes away. We have both UWP and Win32 versions of our business app and our customers are used to leaving the app open all day.

ptorr-msft commented 4 years ago

Thanks for the extra info. I agree it's a useful feature to add (whether it's a manifest opt-in or something else that is easier to manage than "sessions").

In the meantime, as long as your users are on Desktop and not running on battery, the Extended Execution should run forever. If they are running on battery power, there is a setting they can use to still enable the app to run forever (see Run with Extended Execution)

VagueGit commented 4 years ago

Also thinking more of tools vendors as the support of tools vendors is important for the success of WinUI ... could it be made easier for tools vendors to just support WinUI and not split the market between WinUI (Desktop) and WinUI (UWP)? Here again we revisit the Window/Page ... could we just have one or the other with the capabilities of both in WinUI?

Consolidate navigation too as navigation between windows within an app and navigation between pages is different

Same with binding/DataContext

Elmarcotoro commented 4 years ago

I started looking at WinUI and am confused. I have the option to choose a WinUI Desktop project or a WinUI UWP project. In the UWP project I noticed that a MainPage is created. The Desktop project a MainWindow is created.

Why are their pages in the UWP project and Windows in the Desktop project? What fundamentally is the difference?

Why are there these two platforms? I thought the idea was to allow developers to create a single Windows development environment that targets all API's. kind of like a reunion?

Which project platform do we target going forward? There is massive investment when building a LOB app, We want to ensure we have chosen the correct platform before investing in thousands of hours of development.

As @VagueGit says, surely it is easier to offer a single platform so third party tools venders can build tools with confidence and not go in half baked because they are unsure of the traction a platform may have.

Where can one find more information on the differences between WinUI UWP and WinUI Desktop and Pages verses Windows?

ptorr-msft commented 4 years ago

Very good points, and the dichotomy between "Win32" / "UWP" in this area is something we're acutely aware of. The best place to learn / create issues / etc. is on the WinUI repo; I would suggest looking at The WinUI 3 roadmap and commenting there.

ShankarBUS commented 4 years ago

Hey @ptorr-msft, why are named pipes not working incase of a packaged desktop apps?

I couldn't wait till Project Reunion is released just to have single instance apps, so I made my own implementation using Mutex and Named Pipes for a packaged WPF app.

They work perfectly fine when the app is either started as an unpackaged app or deployed from VS. But once the app is published as an MSIX or to Store, this issue happens. The Documentation states that we need to add LOCAL to the pipe name (i.e. like this "\.\pipe\LOCAL\"). But would it work for my case?

I saw a repo which demonstrates a way to communicate between a UWP app and a Console app within the same container? But it is so complex. Are there any other ways to do it?

It would be so great if you could help me with this issue πŸ™

ptorr-msft commented 4 years ago

@mikebattista is that \.\pipe\local requirement for all packaged apps, or only AppContainer apps?

mveril commented 4 years ago

I think command-line activation is not curently good in UWP because the CommandLineActivationOperation expose the command line arguments as string instead of string[] like all the Win32 App models. It can be useful to add a property to expose arguments as string[]in CommandLineActivationOperation object and maybe depreciate the old arguments property or create a helper to do this. It could be great if Win32 conventional command line activation will be merged in UWP CommandLineActivatedEventArgs.

RobMeyer commented 4 years ago

Will there be a functional equivalent for CoreApplication.EnablePrelaunch(Boolean)?

This would fit nicely with the activation and performance (and being a good citizen) parts of this item.

ptorr-msft commented 4 years ago

@RobMeyer just to be clear, are you asking because you want to opt IN to pre-launch (the current default is to not pre-launch)?

RobMeyer commented 4 years ago

@ptorr-msft Yes, that’s right. I’d like to opt-in to prelaunch. We’d also need activation args to differentiate a prelaunch vs regular launch.

DrusTheAxe commented 4 years ago

@RobMeyer you're suggesting string[] CommandLineActivatedEventArgs.Arguments where .Arguments is parsed per CommandLineToArgvW, akin to

string[] Arguments()
{
    argv = CommandLineToArgvW(this.Arguments, &argc)
    args = new string[argc];
    for (int i=0; i<argc; ++i)
        args[i] = new string(argv[i])
    return argv
}

?

RobMeyer commented 4 years ago

@DrusTheAxe I don't think CommandLineActivatedEventArgs is related. I'm referring to the UWP PreLaunch functionality which has two parts.

  1. Opt-in to pre-launch by calling CoreApplication.EnablePrelaunch(true)
  2. Detect and handle prelaunch. There are some app workflows that need to take prelaunch into account. For example, a music player like Spotify might want to auto-play music on launch or a camera app may want to start accessing the camera and microphone data, but this doesn't make sense in the context of prelaunch. UWP apps do this by checking the LaunchActivatedEventArgs.PrelaunchActivated property, typically in Application.OnLaunched.

Edit: 2b. In the case that an app was prelaunch activated, there should also be an additional event to indicate when the app has been non-prelaunched. E.g. when the user has requested that the app open. This is the point at which a music player would want to autoplay or a camera app might want to start accessing the camera nd microphone.

DrusTheAxe commented 4 years ago

@RobMeyer I was thinking about the .Arguments part of your coment. LaunchActivatedEventArgs has a .Arguments property so it should also expose this .ArgV equivalent but ditto any other *ActivatedEventArgs with .Argument[*] properties -- DialReceiverActivatedEventArgs, GameUIProviderEventArgs, etc

You're thinking specifically of Prelaunch of non-Universal apps? e.g. something akin to

boolean IsPrelaunchActivation()
{
    var args = AppInstance.GetActivatedEventArgs()
    return (args.Kind == ActivationKind.Launch) and ((IPrelaunchActivatedEventArgs) args).PrelaunchActivated
}

You don't need different arguments for different prelaunch activations? (Is that even possible?)

ghost commented 3 years ago

currently, all packaged apps be it win32 or UWP suffer from this Packaged Apps Update issue. they just never save the current app data state during package updates and also never restarts itself after an update has been installed. so if an update has been installed all the unsaved data gets lost.πŸ˜•

This is a pain and needs to be fixed ASAP.

I will like Project Reunion consider & provide something like :.

installing package updates (store or I myself locally through App Installer) ➑ check if the app is open ➑ if not open , apply update silently ||| or if open, save all the unsaved current working data/app state ➑ terminate the process & apply package updates ➑ restart the app itself and restore the all the unsaved current working data/app state. everybody is happy. πŸ‘

DrusTheAxe commented 3 years ago

@ecovio1 that's unexpected. Your ask of Project Reunion is unnecessary, as that's how Windows (is supposed to) work. Thank you for raising the issue. @kanismohammed is investigating.

Windows won't service a package while it's in use, i.e. running processes are using it. PackageManager.AddPackageAsync() etc will fail, unless a DeploymentOptions.Force* option is specified. Then running processes are 'stopped', as in, suspend semantics -- tell the process it's being suspended and given the opportunity to save its state, and if the process doesn't stop in a timely manner it's TerminateProcess'd.

Let's continue this discussion on the Packaged Apps Update issue thread as it's more extensively discussed there.

michael-hawker commented 3 years ago

Concerned with the event handler delegates not being strongly typed. As a developer, if I've registered to an event, I expect to just get the latest relevant data I need from the event arguments like other .NET and UX events do (mostly or should). See event design from .NET framework guidelines.

Otherwise, I also can't just proactively discover how to use the API after finding the root type PowerManager. I'm forced to search for up-to-date documentation or a sample to understand how to respond and utilize events effectively vs. just grabbing a property from the EventArgs for straight-forward access, unless I need to correlate multiple values (less common).

It's also handy to know what the sender is of the underlying type (like a PowerManager instance). I may register an event in a different context, and thus may not have access to the original object from the context in which I registered the event (though if PowerManager is a singleton this isn't as much of an issue).

MattBDev commented 3 years ago

I really hope the "good resource citizen" badge or an equivalent is added.

nickrandolph commented 3 years ago

For unpackaged applications it would seem that the intent is for the application (or installer) to be responsible for registering and unregistering. The question then is, what happens if an unpackaged application doesn't unregister - for example, if the user simply deletes the application folder, or moves it to a different location? Is there a mechanism where the cleanup (ie unregistering) can be automated?

riverar commented 3 years ago

I beg the team to please consider my proposal (https://github.com/microsoft/ProjectReunion/issues/126) (and possible future extensions) when creating the design of the manifest for this feature. My proposed changes would immensely benefit from a well-thought out manifest container. Thanks!

JaiganeshKumaran commented 3 years ago

Many single instance desktop apps today just either terminate when a new instance is created or show an message box that an instance is already running. Even more, there's a difference between multiple windows in a single instance versus multiple instances. UWP has the concept of the MainView which is created by the OS however since Win32 desktop apps create their own window, it should be handled in the framework level and not the app model level to switch to the right window when a new instance is created

andreww-msft commented 3 years ago

For unpackaged applications it would seem that the intent is for the application (or installer) to be responsible for registering and unregistering. The question then is, what happens if an unpackaged application doesn't unregister - for example, if the user simply deletes the application folder, or moves it to a different location? Is there a mechanism where the cleanup (ie unregistering) can be automated?

Well, that is after all one of the benefits of MSIX packaging and deployment, and an unpackaged app misses out on those benefits. For the platform to be able to fully track unpackaged app uninstall/move/delete would require significant infrastructure that would probably parallel the MSIX infrastructure.

andreww-msft commented 3 years ago

I beg the team to please consider my proposal (#126) (and possible future extensions) when creating the design of the manifest for this feature. My proposed changes would immensely benefit from a well-thought out manifest container. Thanks!

Yes, thanks Rafael, #126 is under consideration.

andreww-msft commented 3 years ago

Many single instance desktop apps today just either terminate when a new instance is created or show an message box that an instance is already running. Even more, there's a difference between multiple windows in a single instance versus multiple instances. UWP has the concept of the MainView which is created by the OS however since Win32 desktop apps create their own window, it should be handled in the framework level and not the app model level to switch to the right window when a new instance is created

Different apps have different requirements here. We want to be very careful not to force all apps into one path. So instead we provide tools where each app can choose how it wants to behave - and in fact, can make this choice dynamically. This leaves control firmly in the hands of the app itself.

DrusTheAxe commented 3 years ago

@nickrandolph For unpackaged applications it would seem that the intent is for the application (or installer) to be responsible for registering and unregistering

Yes - as they already are. If you're an MSIX package then your "installer" is Windows (and more specifically, the MSIX deployment pipeline in windows). If you're not an MSIX package then you have an install model (run foosetup.exe or foo.msi, unzip foo.zip, even XCOPY has an install model -- copy foo.exe(+friends)). You can use Project Reunion to supplement your app. Like many components and frameworks, Project Reunion has 'install' needs to 'register' appropriately with Windows (and uninstall/deregister on the flip side).

what happens if an unpackaged application doesn't unregister Same thing that happens with any other component/framework that's installed and not uninstalled. Ideally it's inert (just using some disk space) but YMMV, depending on the framework.

for example, if the user simply deletes the application folder If ProjectReunion is installed via MSIX framework packages then its files don't live with the application, they live where the package is managed by Windows, e.g. C:\ProgramFiles\WindowsApps\Microsoft.ProjectReunion.0.5_0.5.0.0_x86__1234567890abc, and since it's managed by Windows it's possible to cleanly remove it (worst case, via powershell -c Get-AppxPackage *reunion*|Remove-AppxPackage).

Of course that assumes the app that installed ProjectReunion is the only one using it. That's unlikely (especially over time). You wouldn't want to remove ProjectReunion if any app on the system needs it.

OTOH if an in-app deployment model is used then any registrations and the app's directory is deleted (or at least Project Reunion's files) then whatever's wired up won't be found if/when Windows tries to access it. Impacts depend on the nature of the registration and can range from nothing (inert, not used) to error dialogs ("I need to run X but can't find it"), broken functionality or other negative user experiences.

or moves it to a different location? Any registrations needing those files would result in the same experience as if you deleted them. Unless you tell Windows "these files? they're over there now" it's the same broken experiences.

Is there a mechanism where the cleanup (ie unregistering) can be automated? Ultimately PackageManager.RemovePackageAsync() is the key to removing an MSIX package. If it can be removed - some can't, for varying reasons. Some packages can't be uninstalled (e.g. Settings) as it would break Windows. Framework packages can't be removed if there's any package dependent on them (again, ripping out FoooFramework.msix would break Bar if BarMain.msix depends on it).

Generally MSIX packages can be uninstalled (if it wouldn't break things). Some people have asked Project Reunion to not be uninstallable, as they view it as critical infrastructure where the cons of being uninstallable (causing problems and support headaches) outweighs the value of being uninstallable. Project Reunion 0.5 is uninstallable (if no one's dependent on it). We are of course interested in developers needs and desires so the feedback is being considered (as is all input).

Good discussion but we're drifting off the App Lifecycle topic. If there's additional questions or issues we should discuss them under new Issues or Discussions more focused on the matter(s).

nickrandolph commented 3 years ago

@DrusTheAxe in the case on in-app deployment, I see the lack of automated cleanup to be a nasty side effect. I get that the whole point of having installers (and ideally MSIX) it to provide for cleanup but if we're providing a mechanism for apps to register (for the in-app deployment scenario), can't we provide a mechanism where cleanup can be done automatically if the app or folder is deleted, or moved. I guess this is something that the community could provide......

DrusTheAxe commented 3 years ago

@nickrandolph can't we provide a mechanism where cleanup can be done automatically if the app or folder is deleted, or moved

Yes, I think we can. In particular I'm thinking of the LifetimeKind + LifetimeArtifact model like in MddTryCreatePackageDependency.

Ideally we'd want LifetimeKind + LifetimeArtifact parameters on the deployment APIs next to ExternalLocation, so you could specify "here's my stuff AND automagically remove me if this thing is gone". Since we're talking ideal we'd want various codepaths to check/handle this as well as a general maintenance task (i.e. garbage collection) to run every so often.

Doing something equivalent in Project Reunion is possible, at least in part. I'll need to think on it some more and talk with a few folks but, yes. This does look very promising. Thanks for the suggestion!

soumyamahunt commented 3 years ago

Some additional things I would like to see in new App Lifecycle management for multi-instance scenario:

  1. Ability to check if an instance is pre-launched, this would come handy when an app is trying to create new instance and instead of creating one they can redirect activation to pre-launched instance for better performance.

  2. Ability to check if there is any instance present in the external display/virtual desktop the activation initiated. One of the pain points in multi-instancing is when user switches to external display/another virtual desktop and launches app/ tries to open file with an app and being dragged to the other virtual desktop where app is already present. This would allow apps to launch a new instance instead of redirecting activation in such scenarios.

mqudsi commented 3 years ago

Question: which WinUI preview release was the to include support for lifecycle management in UWP apps?

Note: a lot of the notes on changes to the lifecycle API are only present in versioned GitHub links to transient versions of MarkDown documents in the repo that are no longer available in HEAD/master. Is there a single "source of truth" document that survives that includes the changes to the APIs?

RobMeyer commented 3 years ago

Is there a single "source of truth" document that survives that includes the changes to the APIs?

I believe that would be docs.microsoft.com. Process lifetime management is a broad set of related apis and has changed/grown over time, so you’ll want to look up a specific api endpoint to see when it was introduced. For example, https://docs.microsoft.com/en-us/uwp/api/windows.applicationmodel.activation.appointmentsprovideraddappointmentactivatedeventargs?view=winrt-20348 was introduced in v1.0, 10.0.10240.0

nlogozzo commented 3 years ago

Is the RequestRestartAsync working? I tried it in my WindowsAppSDK V0.8.1 app and it seems to not be working.

JaiganeshKumaran commented 3 years ago

Is the RequestRestartAsync working? I tried it in my WindowsAppSDK V0.8.1 app and it seems to not be working.

RequestRestartAsync is only for UWP apps. In a desktop app, you can start a new instance of your app and terminate the current one.

mqudsi commented 3 years ago

I have observed GetActivatedEventArgs() returning null in packaged WinMain applications under Project Reunion 0.8.x and Windows App SDK 1.0.0-experimental1.

I have a hunch that this might be because the kind of activation is one of the ~34 other types that @andreww-msft didn't explicitly mention (Launch, File, Protocol, StartupTask, ToastNotification, ShareTarget, CommandLine, Restart). Is there no way for packaged (or unpackaged) WinMain apps to handle being activated in response to such an event, even if it requires manually piecing together an instance of IActivatedEventArgs from various, disjoint sources and then invoking App.OnActivated/App.OnBackgroundActivated/etc yourself?

Samuel12321 commented 3 years ago

Why was this issue closed @aeloros when it hasn't been fully implemented yet.