winget-cli icon indicating copy to clipboard operation
winget-cli copied to clipboard

Support installers that close the install process and launch a new process for install

Open Eschryn opened this issue 5 years ago • 1 comments

Brief description of your issue

winget finishes installation before installation finished.

Steps to reproduce

winget install Postman.Postman -e or winget install Insomnia.Insomnia -e

Expected behavior

Installs the Package and done.

Actual behavior

"Installs" the Package, but doesnt wait for the Installer to finish and then can't remove the installer and thus halts execution of scripts and itself

Environment

[winget --info]
Windows Package Manager v0.1.41221 Preview
Windows: Windows.Desktop v10.0.18363.535
Package: Microsoft.DesktopAppInstaller v1.0.41331.0

Eschryn avatar Jun 12 '20 12:06 Eschryn

The current behavior in the install flow is that we launch another process to execute the "installer". In this case, and in general with Squirrel installers, they launch another process and close the one we started.

Unfortunately, this will required some substantial effort to engineer another mechanism to watch all of the processes launched or build a retry mechanism to attempt to delete the installer.

This also introduces new challenges for packages like Visual Studio Code which launches the program after installation. In cases like that, we would hang on installation waiting for the user to close Visual Studio Code.

This may also require changes to the manifests so we can identify packages with these kinds of installers to adjust behavior and or inform users about the expected user experience.

denelon avatar Apr 20 '21 22:04 denelon

Interesting, does this also explain why winget doesn't wait in this case? https://github.com/microsoft/winget-pkgs/issues/77958#issuecomment-1884121499

If tracking all the child processes that were launched by winget is too hard, how about just looking for changes to the registered installers? I.E. looking for changes within HKEY_CLASSES_ROOT\Installer\Products and HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall (and similar for current user installs)? Maybe by adding a property to the pkgs config that specifies which subkey it creates. Then we could also add tracking of the registered metadata and throw an warning/error when the registered metadata differs from the one in the package (I.E. the one we expected).

agowa avatar Jan 10 '24 12:01 agowa

Also on another note, shouldn't setting DEBUG_PROCESS on the installer process while launching it grant us the ability to get the entire child process tree? I just checked it's documentation and it at least is documented exactly this way. We'd get the events of all the children and grandchildren. It doesn't mention anything about it breaking once one of the processes in the chain exits.

Listening to CREATE_PROCESS_DEBUG_EVENT and EXIT_PROCESS_DEBUG_EVENT would allow us to track the entire sub-process tree. Only limitation would be if one of the sub-processes tries to do something similar, but that could be improved upon later by potentially hooking the API for it (which is probably less error prone than hooking the process creating API?). Also these events would contain handlers to the processes that we could use later for more introspection and tracking.

This won't give us 100%, but it's probably as good as it gets without adding a kernel filter and without sacrificing GUI access.

If we'd lets say compromise on the GUI access, which at least in my eyes would be acceptable as at least for me the goal of winget is silent installs anyway, we could also just create a new session and start the process in it. That way anything that runs in the session we created would be something that was started by our installer. Basically we'd just have to query the list of all running processes and filter it by our session id. (I don't know if we could also easily create a new Desktop aka. WinSta, I think applications like KeePass currently use it to provide some form of a secure desktop to enter the password, but I didn't check how easy that would be) Namely that would involve a smart combination of CreateWindowStation, SetProcessWindowStation, CreateDesktop, (if we want to show the GUI, even though I think we should make winget work without GUI, also SwitchDesktop).

(Because it may be a bit unclear, the part about creating a new winsta or desktop is mainly just because it becomes part of the access token and thereby inherited to all child processes. And that basically can be used as a form of identifier to track all the processes we want)

Edit: Realistically we probably could even use an environment variable to track all child and grandchild processes, as almost no process breaks inheritance of environment variables anyway...

Technically in the future that would also allow us to start using the JournalRecordProc and JournalPlaybackProc hooks, but these were deprecated recently I think (can we get them un-deprecated again? Or is there a good alternative that we could use?) to add GUI automation capabilities into the winget installer to even allow installing the "GUI only, sorry no silent install available"-kind of applications to be packaged and installed automatically via winget.

agowa avatar Jan 10 '24 14:01 agowa