Continue the Wix setup after having a service that

2019-08-31 02:15发布

问题:

We have a setup in which we have a service that we try to install and run.

For some reason, the service cannot start(due to a port already in use). This isn't critical for us and should not stop the setup.

The service is declared like this:

<DirectoryRef Id="BIN">
  <Component Id="MyService" Guid="*" SharedDllRefCount="yes">
    <File Id="MyService.exe" Name="MyService.exe" KeyPath="yes" Vital="no" Compressed="default" DiskId="1" Source="$(var.DirDotfuscated)\MyService.exe" />
    <ServiceControl Id="Install" Name="MyService" Start="install" Stop="install" />
    <ServiceControl Id="Uninstall" Name="MyService" Stop="uninstall" Remove="uninstall" />
    <ServiceInstall Id="NewServiceInstall2" Name="MyService" DisplayName="My Service" Type="ownProcess" Interactive="no" Start="auto" ErrorControl="normal" Description="My service" Vital="no" />
  </Component>
  <Component Id="Xms_HostService_Files" Guid="*" SharedDllRefCount="yes">
    <File Id="MyService.exe.config" Name="MyService.exe.config" Vital="no" Compressed="default" DiskId="1" Source="$(var.DirDotfuscated)\MyService.exe.config" />
    <File Id="MyServiceCommon.dll" Name="MyServiceCommon.dll" Vital="no" Compressed="default" DiskId="1" Source="$(var.DirDotfuscated)\MyServiceCommon.dll" />
    <File KeyPath="yes" Id="MyServiceCore.dll" Name="MyServiceCore.dll" Vital="no" Compressed="default" DiskId="1" Source="$(var.DirDotfuscated)\MyServiceCore.dll" />
  </Component>
</DirectoryRef>

When we execute the setup, we get this error:

And then, we only have the option to Retry(which will also fail) or cancel(that stops the setup).

We tried so many things(only put serviceInstall, not serviceControl, ...) but at some point we always have an error.

How should we manage this?

回答1:

Attempted Answer (without ability to test):

What happens if you set the ServiceControl element's Wait attribute to "no"? I don't have a service exe to test with at the moment, but I believe that could work as you intend it.

Custom actions should generally be avoided for reliability reasons, but on the other hand - if you do need something special - that's what they are there for. Be prepared for most deployment problems to originate from your custom actions though: Why is it a good idea to limit the use of custom actions in my WiX / MSI setups?


Some further advice (which was not asked for :-) ):

  1. You should not install multiple binaries with one component. You should use one file per component for many reasons. Windows Installer best practice specifically dictates to have only one binary per component, but in my opinion you should use one component per file in general to make minor upgrades and patching possible, and self-repair more reliable.
    • To better understand component reference counting: Change my component GUID in wix?
    • By eliminating hard-coded GUIDs you can take advantage of WiX's advanced auto-GUID creation concept. This will change the component GUID if the absolute installation path changes. This is correct behavior for component reference counting. Auto-magic. You either set Guid="*" or just leave out the Guid attribute entirely. A few installation locations need a hard coded GUID - the WiX compiler will warn you and explain why.
  2. If you do change the component structure (to use one file per component) you should change the installation path to "break the link to past sins" with regards to component reference counting. This is a very complex topic to explain, but changing the installation path will sort all problems for you - if you also enable the auto component GUIDs I mentioned in the previous point. Keep the path stable from then on (until you have a major new version).
    • You can do it as simple as adding a sub folder with the the application's major (and minor?) version to the main installation folder hierarchy: "Program Files\MyCompany\MySoftware\5" instead of "Program Files\MyCompany\MySoftware".
    • I would only add the major version to the path and keep the installation path stable throughout your application's lifetime and then increment when you want to break the link to previous installers for a major new software version (for example if you want to install two versions side-by-side - your application must be built to handle this properly, i.e not overwriting shared settings in the registry from both versions etc...).
  3. You might want to consider simplifying your WiX source file by only specifying values for attributes that are non-standard (otherwise rely on defaults). This can substantially simplify your WiX source files. Here is an example: Syntax for guids in WIX?

Just a quick sample inline (same as in link above - check it out), this is all that is required to install a normal file with default attributes / parameters - all other attributes default well - unless you want to override something:

<Component>
  <File Source="..\File.dll" />
</Component>

Some links:

  • Windows Installer Best Practices (full list).
  • Windows Installer Best Practices - Organizing Applications into Components (specifically for component creation).
  • When component reference counting has gone haywire (missing files after upgrades, unexpected removal of shared files on uninstall, etc...): WiX 3.8: Two MSI using the same registry values. How to delete registry values only if both MSI are uninstalled?


回答2:

Drop the ServiceControl element in lieu of a CustomAction element with @DllEntry="WixQuietExec" set, then use a standard means of starting the service like net start foo and ignore the result. See Quiet Execution Custom Action for details.