Unfortunately we broke some component rules in our msi setup made with Windows Installer for XML. From one specific point in time our windows service executable needs another file to work properly, but this setup is shared between different versions of our application. So we got an issue.
Service executable (snippet. ServiceInstall part removed)
<Component Id="WindowsServiceId" Guid="GUID_A">
<File Id ="file_ServiceEXE" Checksum="yes" Source="$(var.pathToServiceRelease)WindowsService.exe" KeyPath="yes" />
</Component>
This above is our application version 2.0 with service 1.0.
In application version 2.1 we added another file to our setup, the version of all files are increased to 1.1:
<Component Id="AdditionalServiceFile" Guid="GUID_B" >
<File Id="additionalFile_dll" Source="$(var.pathToServiceRelease)ServiceManager.dll" KeyPath="yes" Checksum="yes"/>
</Component>
So imagine we have both application setups 2.0 and 2.1 installed, so the version of the service executable is 1.1, as of the ServiceManager.dll When we deinstall application setup 2.1, it will remove the ServiceManager.dll since no other installation needs it, but leaves the executable in version 2.1 – so the service can’t be startet, since the dll is missing. Unfortunately, this scenario has been already released.
Our first approach to solve this issue was to install the ServiceManager.dll permanent, not a good approach, but works for most cases. But when we install the ServiceManager.dll Permanent=true, we are going into this:
- Install application 2.0, exe is installed in version 1.0
- Install application 2.1, exe and dll are installed in version 1.1
- Deinstall application 2.0, exe and dll are still installed in version 1.1
- Deinstall application 2.1, exe is beeing removed, the dll remains.
- Reinstall apllication 2.0: exe is installed in version 1.0, dll is still installed in version 1.1 -> the service is broken.
So we tried this:
<Component Id="WindowsServiceId" Guid="GUID_A">
<RemoveFile Id=“myId“ Name=“ServiceManager.dll“/>
<File Id ="file_ServiceEXE" Checksum="yes" Source="$(var.pathToServiceRelease)WindowsService.exe" KeyPath="yes" />
<File Id="additionalFile_dll" Source="$(var.pathToServiceRelease)ServiceManager.dll" Checksum="yes"/>
</Component>
We simply added the ServiceManager file to he same component as the service executable, so both are always doing the same and are treated equally. Any prior left behinds are removed within the component. We would create an application 2.2 with the same service files like in application version 2.1, but just with changed installation like described above. We know that our application version 2.1 will always have that issue, but we would recommend our customers to delete this and never use it again. And we would address our main issue:
- Install application 2.0, exe is installed in version 1.0
- Install application 2.2, exe and dll are installed in version 1.1
- Deinstall application 2.0, exe and dll are still installed in version 1.1
- Deinstall application 2.2, exe is beeing removed, the dll is beeing removed.
- Reinstall apllication 2.0: exe is installed in version 1.0, dll is installed in version 1.0 -> should work fine, also in future releases with aplication 2.x and service version 1.y
Before the user can install application version 2.2, they must deinstall application version 2.1. Is this a valid approach? Or do we have to create an new component and a new window service?