I ran into a problem on an major upgrade. The installer includes a service and on an upgrade I got a popup saying that a reboot is required to finish the setup process.
To prevent this behaviour I actually just need to stop the service before RemoveExistingProducts
(rather InstallValidate
) is executed.
The MajorUpgrade
is placed after InstallInitialize
and the package has InstallPrivileges="elevated"
.
I have two cases:
Case 1: The service is installed by ServiceInstall
via
<Component Id="myservice_Service" Guid="*">
<File Id="myservice.exe" KeyPath="yes" Vital="yes"
Source="SourceDir\bin\myservice.exe"/>
<ServiceInstall Id="myservice_ServiceInstall" Type="ownProcess"
Vital="yes" Name="myservice" DisplayName="myservice Service"
Description="myservice Service" Start="auto" Account=".\LocalSystem"
ErrorControl="ignore" Interactive="no" Arguments="--run"/>
<ServiceControl Id="myservice_ServiceControl" Name="myservice" Wait="yes" Stop="uninstall"/>
</Component>
The ServiceControl
is not stopping the service before InstallValidate
is called. Even when saying Stop="both". So the popup appears. Note that the service is not started by the installer.
Reasonable posts I've found (excerpt):
Case 2: The service is installed by a CustomAction
(there are some reasons why not doing via ServiceInstall
as well).
In this case I have to call an executable to stop the service ("myservice.exe --stop"). For this it's getting tricky, since due to ICE63 it's not allowed to schedule a CustomAction
before RemoveExistingProducts
is called. So, how may I achieve this anyway?
So far I've read posts like:
A bootstrapper exe is no option, since I need to produce an plain MSI.
I've found similar unanswered problem here: Wix Installer Problem: Why does RestartManager mark Service as RMCritical and not RMService
The solution for case 2 is:
<DirectoryRef Id='INSTALLDIR'>
<Component Id='StopService' Guid='{0913D365-8EC0-424A-939E-0F04E99D2ACA}' KeyPath='yes'>
<ServiceControl Id='StopServiceControl' Name='ServiceName' Stop='uninstall' Wait='yes'/>
</Component>
</DirectoryRef>
In that case no FileInUse dialaog will appear.
The sequencing of ServiceControl after InstallValidate is irrelevant. If a file-in-use situation is detected for a service in InstallValidate but the service is in the ServiceControl table to be stopped at uninstall then Windows quite reasonably postpones any files-in-use situation to see what actually happens. If you take it out of ServiceControl you'll lose this potentially useful feature. Note that you can use ServiceControl independently of ServiceInstall - they are not bound together, so you don't necessarily need to run an exe to stop a service if it can play well with ServiceControl.
A common reason for this situation is simply that the service misbehaves. Wait=yes won't wait forever, only 30 seconds according to the documentation. So the service must respond to the control message telling it to stop. Even when the service is "stopped" that doesn't mean the process has gone away, only that it is no longer running as a service. If it takes a while to actually terminate the process then Windows has no alternative but to show files-in-use. These things are tricky to debug because timing issues typically are, but if it were me I'd be scrutinizing the service shutdown code.
Note also that you may need stop=both in an upgrade scenario. If InstallValidate (in your incoming upgrade) doesn't see an install stop in ServiceControl and there are files in use then you'll get that files-in-use issue. InstallValidate doesn't look ahead to see when RemoveExistingProducts might run and then go look in another MSI for a ServiceControl stop there that could prevent files-in-use.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With