3
votes

I'm facing an issue in my .net installer application which will install three windows application together. In these three apps, one is a Windows Service. So, my installer project has three primary output from these three windows apps.

When installed, all these will be installed as expected and the Windows Service will be automatically "STARTED" after the installation.

However, if I uninstall the application (while the windows service is in "RUNNING" mode), the installer will show a "file in use" dialog and will eventually end up with the service not being uninstalled while the other things will be removed. However, if the Windows Service is stopped before uninstall, it will be completed nicely.

I assume that the above problem occurs because the installer app will try to remove the service.exe file (as it is also bundled into the installer).

I tried the below alternates:

  1. I tried to overcome this by adding a custom installer in which I tried to stop the service. But, that also doesn't seem to be working. Reason for that is, the default "uninstall" action will be executed before the "uninstall" custom action. (FAILED)

  2. Set the "Permanent" property of the "Primary output" of the Windows Service application to "true". I was under the assumption that the installer will simply skip the files related to the primary output. But (FAILED)

Anyone faced this kind of an issue ever and please share your thoughts on the same.

How can I stop the service before uninstall so that the un-installation will be completed successfully?

1

1 Answers

0
votes

I had the similar problem with windows services long time ago and was able to solve it by calling WaitForStatus(ServiceControllerStatus) method. The service needs some time to shut down, and you're continuing on before the service has fully stopped. Write the logic for uninstall and whatever you want to do when Shutdown status has stopped.

If you're uninstalling and you want to stop the service before uninstall then you need to override the uninstall custom action, adding your code to stop it, then call base.Uninstall. Keep in mind that a WaitForStatus with a 15 second limit might not be enough time for a service to shut down, depending how responsive it is and what it does in a shutdown. Also make sure you call Dispose() on the ServiceController (or Close as in this example) because if you don't then the internal service handle won't be immediately released, and if it is still in use the service can't be uninstalled.

MSDN link

This is just example of how this could be implemented and logged in EventLogger:

public override void Uninstall(System.Collections.IDictionary savedState)
{
 ServiceController controller = new ServiceController("My Service");
 try
 {
  if (controller.Status == ServiceControllerStatus.Running | controller.Status == ServiceControllerStatus.Paused)
  {
   controller.Stop();
   controller.WaitForStatus(ServiceControllerStatus.Stopped, new TimeSpan(0, 0, 0, 30));
   controller.Close();
  }
 }
 catch (Exception ex)
 {
  string source = "My Service Installer";
  string log = "Application";
  if (!EventLog.SourceExists(source))
  {
   EventLog.CreateEventSource(source, log);
  }
  EventLog eLog = new EventLog();
  eLog.Source = source;
  eLog.WriteEntry(string.Concat(@"The service could not be stopped. Please stop the service manually. Error: ", ex.Message), EventLogEntryType.Error);
 }
 finally
 {
  base.Uninstall(savedState);
 }
}