31

Currently I have to uninstall the old version of my service before I install the new version. I am pretty sure this has something to do with it not being smart enough to update or remove the old service entries before adding the new ones.

Is there a way to have the installer skip registering the service if it already exists? (I can assume the installation folder and service name do not change between versions.)

Also, is there a way to automatically stop the service when uninstalling?


Edit:

I am using MSI packages and the Visual Studio setup project.

Community
  • 1
  • 1
Jonathan Allen
  • 68,373
  • 70
  • 259
  • 447

6 Answers6

17

I've done this with WiX, which generates .MSI files using the ServiceInstall & SeviceControl commands:

<Component Id='c_WSService' Guid='*'>
    <File Id='f_WSService' Name='WSService.exe' Vital='yes' Source='..\wssvr\release\wsservice.exe' KeyPath="yes" />
    <ServiceInstall Id='WSService.exe' Name='WSService' DisplayName='[product name]' Type='ownProcess'
                    Interactive='no' Start='auto' Vital='yes' ErrorControl='normal'
                    Description='Provides local and remote access to [product name] search facilities.' />
    <ServiceControl Id='WSService.exe' Name='WSService' Start='install' Stop='both' Remove='uninstall' Wait='yes' />
</Component>

This stops the service, installs the new version and re-starts the service.

Ferruccio
  • 98,941
  • 38
  • 226
  • 299
9

I do not use Visual Studio setup projects, so I might be wrong, but it seems it has no support for the ServiceInstall and ServiceControl tables which are standard features of Windows Installer. Those two tables are specially for installing and updating services....

Wix does support it (see this example), Maybe you can create a merge module, and use that in your project.

Otherwise this might help: Installing Services with Visual Studio (Phil Wilson)

wimh
  • 15,072
  • 6
  • 47
  • 98
9

Use sc tool from a command line to stop and start the service:

sc stop {name of your service}
sc start {name of your service}

When the service is stopped, update the corresponding files and then start the service again. You should be able to do that from your installer as well. If you use Wix for your installer, then take a look at ServiceControl element.

David Pokluda
  • 10,693
  • 5
  • 28
  • 26
  • This works fine on Windows XP and later, but sc.exe is not included with Windows 2000; you might need to include your own copy if you plan to support that operating system. – Kevin Kibler Dec 19 '09 at 01:31
2

Can't you just stop the service, and overwrite the service executable, and then restart the service?

jalf
  • 243,077
  • 51
  • 345
  • 550
  • Sure, if I were doing everything by hand. But this needs to be wrapped in a MSI package. – Jonathan Allen Nov 29 '08 at 20:05
  • This is the identical solution offered by David. jalf just didn't spell out the commands to use within the installer. At least that's how I interpreted it. – TTT Feb 15 '13 at 17:09
0

My hacky solution is to modify the ProjectInstaller.vb file so it issues a command to stop and delete the service and then pauses a bit. Probably not as neat from an install perpective as modifying the msi file, but much more readable/logical to whoever inherits my code.

Note that the RunCommandCom bit is blatently cribbed from How to run DOS/CMD/Command Prompt commands from VB.NET?

Using this method combined with code from How to automatically start your service after install? you can have the service install experience you want - A service that installs and starts automatically, and will overwrite a currently running service if there is one.

'This works.  It leaves the MSI in a state that tells you to reboot the PC, but you really don't need to.

Private Sub ProjectInstaller_BeforeInstall(sender As Object, e As System.Configuration.Install.InstallEventArgs) Handles Me.BeforeInstall

    Dim sEchoMessage As String = String.Empty
    sEchoMessage &= " & ECHO ******************       Please be patient      *******************************"
    sEchoMessage &= " & ECHO Pausing to stop and delete the previous version of the following service:"
    sEchoMessage &= " & ECHO " & ServiceInstaller1.ServiceName
    sEchoMessage &= " & ECHO -------------------------------------------------------------------------------"
    sEchoMessage &= " & ECHO After install is complete, you may see a message that says you need to reboot."
    sEchoMessage &= " & ECHO You may IGNORE this message - The service will be installed and running."
    sEchoMessage &= " & ECHO There is NO Reboot required."
    sEchoMessage &= " & ECHO *******************************************************************************"

    RunCommandCom("sc stop " & ServiceInstaller1.ServiceName & " & sc delete " & ServiceInstaller1.ServiceName & sEchoMessage, 15000)

End Sub

Private Sub RunCommandCom(command As String, mSecSleepAfterExecution As Integer)

    Using p As Process = New Process()
        Dim pi As ProcessStartInfo = New ProcessStartInfo()
        pi.Arguments = " /K " + command
        pi.FileName = "cmd.exe"
        p.StartInfo = pi
        p.Start()
        System.Threading.Thread.Sleep(mSecSleepAfterExecution)
        p.CloseMainWindow()
    End Using

End Sub
Community
  • 1
  • 1
edhubbell
  • 2,218
  • 1
  • 16
  • 17
0

You can make separate DLL which service would load and call every time it does its work. Make sure that service unloads DLL after use.

Use should load it into separate Application Domain.

SO http://msdn.microsoft.com/en-us/library/c5b8a8f9.aspx

Din
  • 167
  • 1
  • 6