Wix installer to replace INSTSRV and SRVANY for user defined service installation

Here’s the real scoop: A service is a service is a service. That’s my motto. What I mean by that is I don’t care if you are using a C++ EXE, a VB exe, a C# EXE, some thunking host EXE such as SrvAny.exe… they all implement the same API’s to interact with the service control manager.

So SrvAny is going to get invoked by the SCM and get a start command. At that point it’s going to read the registry values and know how to run your other EXE or script. When SrvAny gets Stop call it’s going to terminate your process and report stopped to the SCM.

So that’s how a service runs. Let’s talk about how to install it. There are a great many ways you could programmatically create the service (SC, InstSrv.exe, Installer Class Custom Actions and so on) but from an MSI perspective none of them are ever needed. The Windows Installer has the ServiceInstall and ServiceControl tables along with standard actions to handle starting, stopping, creating and removing Windows Services. Occassionally, such as the case with SrvAny.exe, you get some installer requirements that can’t be expressed using those tables and in that case you use the Registry table. For SrvAny.exe that’s the requirement to create a Parameters key with registry data that teaches SrvAny.exe what to actually call when it starts.

Here’s a sample in WiX for using SrvAny.exe to run a NodeJs script as a service:

<Component Id="c1" Guid="redacted">
  <File Id="f1" Source="$(var.SourceDir)\srvany.exe" KeyPath="yes" />
  <ServiceInstall Id="si1" DisplayName="MyService" Description="MyService" Name="MyService" Start="auto" Type="ownProcess" Vital="no" ErrorControl="normal" Account="NT AUTHORITY\NetworkService"  />
  <ServiceControl Id="sc1" Name="MyService" Remove="both" Stop="both" Start="install" Wait="yes" />
  <RegistryValue Id="reg1" Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\MyService\Parameters" Name="Application" Type="string" Value="node &quot;[#f2]&quot;" Action="write" />
</Component>
<Component Id="c2" Guid="redacted" KeyPath="yes">
  <File Id="f2" Source="$(var.SourceDir)\server.js" />
</Component>

Leave a Comment