From 58e895cff6e9674afe5d34afb65f7fc1ac3ded08 Mon Sep 17 00:00:00 2001 From: Mattias Gustavsson Date: Thu, 19 Nov 2020 08:16:06 +0100 Subject: [PATCH] SDA-2651 Using EndSession message to terminate SDA on uninstall --- installer/win/WixSharpInstaller/Symphony.cs | 85 +++++++++------------ src/app/window-handler.ts | 13 ++++ 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/installer/win/WixSharpInstaller/Symphony.cs b/installer/win/WixSharpInstaller/Symphony.cs index 17168953..d776a2b2 100644 --- a/installer/win/WixSharpInstaller/Symphony.cs +++ b/installer/win/WixSharpInstaller/Symphony.cs @@ -117,8 +117,14 @@ class Script new LaunchCondition("VersionNT>=600 AND WindowsBuild>=6001", "OS not supported"), // Add registry entry used by protocol handler to launch symphony when opening symphony:// URIs - new RegValue(WixSharp.RegistryHive.ClassesRoot, productName + @"\shell\open\command", "", "\"[INSTALLDIR]Symphony.exe\" \"%1\"") - ); + new RegValue(WixSharp.RegistryHive.ClassesRoot, productName + @"\shell\open\command", "", "\"[INSTALLDIR]Symphony.exe\" \"%1\""), + + // When installing or uninstalling, we want Symphony to be closed down, but the standard way of sending a WM_CLOSE message + // will not work for us, as we have a "minimize on close" option, which stops the app from terminating on WM_CLOSE. So we + // instruct the installer to not send a Close message, but instead send the EndSession message, and we have a custom event + // handler in the SDA code which listens for this message, and ensures app termination when it is received. + new CloseApplication("Symphony.exe", false) { EndSessionMessage = true } + ); // The build script which calls the wix# builder, will be run from a command environment which has %SYMVER% set. // So we just extract that version string, create a Version object from it, and pass it to out project definition. @@ -234,62 +240,43 @@ class Script Compiler.BuildMsi(project); } - static void KillSymphonyProcesses() - { - System.Diagnostics.Process.GetProcessesByName("Symphony").ForEach(p => { - if( System.IO.Path.GetFileName(p.MainModule.FileName) =="Symphony.exe") - { - if( !p.HasExited ) - { - p.Kill(); - p.WaitForExit(); - } - } - }); - } static void project_Load(SetupEventArgs e) { try { - // "ALLUSERS" will be set to "2" if installing through UI, so the "MSIINSTALLPERUSER" property can be used so the user can choose install scope - if (e.Session["ALLUSERS"] != "2" ) + if (e.IsInstalling || e.IsUpgrading) { - // If "ALLUSERS" is "1" or "", this is a quiet command line installation, and we need to set the right paths here, since the UI haven't - if (e.Session["ALLUSERS"] == "") + // "ALLUSERS" will be set to "2" if installing through UI, so the "MSIINSTALLPERUSER" property can be used so the user can choose install scope + if (e.Session["ALLUSERS"] != "2" ) { - // Install for current user - e.Session["INSTALLDIR"] = System.Environment.ExpandEnvironmentVariables(@"%LOCALAPPDATA%\Programs\Symphony\" + e.ProductName); - } - else - { - // Install for all users - e.Session["INSTALLDIR"] = e.Session["PROGRAMSFOLDER"] + @"\Symphony\" + e.ProductName; - } - } - - // Try to close all running symphony instances before installing - KillSymphonyProcesses(); - - // When force terminating Symphony, sometimes this is detected as the renderer process crashing. - // As this message would confuse users, we wait a short time and then kill all Symphony instances - // again, which would ensure that the dialog about renderer crash will not be shown. - - KillSymphonyProcesses(); // Try again immediately, for fast systems which shows dialog quickly - System.Threading.Thread.Sleep(500); - KillSymphonyProcesses(); // Try yet again after half a second for slow systems which takes time to show dialog - - // Try to close all running symphony instances again - System.Diagnostics.Process.GetProcessesByName("Symphony").ForEach(p => { - if( System.IO.Path.GetFileName(p.MainModule.FileName) =="Symphony.exe") - { - if( !p.HasExited ) + // If "ALLUSERS" is "1" or "", this is a quiet command line installation, and we need to set the right paths here, since the UI haven't + if (e.Session["ALLUSERS"] == "") { - p.Kill(); - p.WaitForExit(); + // Install for current user + e.Session["INSTALLDIR"] = System.Environment.ExpandEnvironmentVariables(@"%LOCALAPPDATA%\Programs\Symphony\" + e.ProductName); + } + else + { + // Install for all users + e.Session["INSTALLDIR"] = e.Session["PROGRAMSFOLDER"] + @"\Symphony\" + e.ProductName; } - } - }); + } + + // Try to close all running symphony instances before installing. Since we have started using the EndSession message to tell the app to exit, + // we don't really need to force terminate anymore. But the older versions of SDA does not listen for the EndSession event, so we still need + // this code to ensure older versions gets shut down properly. + System.Diagnostics.Process.GetProcessesByName("Symphony").ForEach(p => { + if( System.IO.Path.GetFileName(p.MainModule.FileName) =="Symphony.exe") + { + if( !p.HasExited ) + { + p.Kill(); + p.WaitForExit(); + } + } + }); + } } catch (System.ComponentModel.Win32Exception ex) { diff --git a/src/app/window-handler.ts b/src/app/window-handler.ts index 6b9723cc..06e430d8 100644 --- a/src/app/window-handler.ts +++ b/src/app/window-handler.ts @@ -534,6 +534,19 @@ export class WindowHandler { }, ); + // When uninstalling Symphony, the installer needs to tell the app to close down + // The dedault way of doing this, is to send the 'close' event to the app, but + // since we intercept and ignore the 'close' event if the user have turned on the + // option "minimize on close", we use an alternative way of signalling that the + // application should terminate. The installer sends the 'session-end' message + // instead of the 'close' message, and when we receive it, we quit the app. + this.mainWindow.on('session-end', () => { + logger.info( + `window-handler: session-end received`, + ); + app.quit(); + }); + // Handle main window close this.mainWindow.on('close', (event) => { if (!this.mainWindow || !windowExists(this.mainWindow)) {