108

I have a .Net Windows service. I want to create an installer to install that windows service.

Basically, it has to do the following:

  1. Pack installutil.exe (Is it required?)
  2. Run installutil.exe MyService.exe
  3. Start MyService

Also, I want to provide an uninstaller which runs the following command:

installutil.exe /u MyService.exe

How to do these using Inno Setup?

Vikrant
  • 4,920
  • 17
  • 48
  • 72
softwarematter
  • 28,015
  • 64
  • 169
  • 263
  • I think you need to use the [Run] section. See [here](http://www.vincenzo.net/isxkb/index.php?title=Inno_Setup_Help_-_'Run'_and_'UninstallRun'_sections) – Preet Sangha Sep 20 '09 at 01:16

5 Answers5

243

You don't need installutil.exe and probably you don't even have rights to redistribute it.

Here is the way I'm doing it in my application:

using System;
using System.Collections.Generic;
using System.Configuration.Install; 
using System.IO;
using System.Linq;
using System.Reflection; 
using System.ServiceProcess;
using System.Text;

static void Main(string[] args)
{
    if (System.Environment.UserInteractive)
    {
        string parameter = string.Concat(args);
        switch (parameter)
        {
            case "--install":
                ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
                break;
            case "--uninstall":
                ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
                break;
        }
    }
    else
    {
        ServiceBase.Run(new WindowsService());
    }
}

Basically you can have your service to install/uninstall on its own by using ManagedInstallerClass as shown in my example.

Then it's just matter of adding into your InnoSetup script something like this:

[Run]
Filename: "{app}\MYSERVICE.EXE"; Parameters: "--install"

[UninstallRun]
Filename: "{app}\MYSERVICE.EXE"; Parameters: "--uninstall"
George Stocker
  • 57,289
  • 29
  • 176
  • 237
lubos hasko
  • 24,752
  • 10
  • 56
  • 61
  • Thanks a lot! That worked like magic. One more clarification. How to run a command like net start WinServ in the Inno Script? – softwarematter Sep 20 '09 at 02:13
  • 3
    you can try `Filename: "net.exe"; Parameters: "start WinServ"`. if it doesn't work, you could just add one more switch --start to your c# application and start windows service directly from the program by using ServiceController class (http://msdn.microsoft.com/en-us/library/system.serviceprocess.servicecontroller.aspx). – lubos hasko Sep 20 '09 at 02:52
  • 2
    +1 Nice. See also http://stackoverflow.com/questions/255056/install-a-net-windows-service-without-installutil-exe – Ruben Bartelink Jan 29 '10 at 09:24
  • 7
    For the C# neophyte (like me), you either need to add a `using System.Reflection;` or change `Assembly` to `System.Reflection.Assembly` in the code above. – rlandster Oct 09 '11 at 19:16
  • 1
    InstallUtil is a part of dot net framework, you don't need "rights" to redistribute it, it's present on your target system already (assuming you can run your app in the first place of course) – Andrew Savinykh May 23 '14 at 06:22
  • 10
    From the documentation about the InstallHelper method in 4.5 - "This API supports the .NET Framework infrastructure and is not intended to be used directly from your code." Discovered after receiving System.InvalidOperationException. – Bratch Jun 09 '14 at 17:01
  • 1
    ...and don't forget to run it as administrator. For that, you can use the option `PrivilegesRequired=admin` in the `[Setup]` header of your `.iss` file. – Daniel Bonetti Aug 15 '16 at 17:48
  • 1
    There's another reason to use this approach instead of InstallUtil: If the service is a 64bit only executable (and not AnyCPU-capable, i.e. because of unmanaged dependencies), InstallUtil will throw with a BadImageFormatException, apparently because it tries to load the service exe into a 32 bit process. If the service exe self-installs itself using this approach, it is entirely 64 bit. – PMF Jul 08 '19 at 10:50
  • 1
    If you don't want to use reflection to find your own executable, you can use `Path.GetFullPath(Environment.GetCommandLineArgs()[0])` – AyrA Jul 23 '21 at 13:27
8

Here's how i did it:

Exec(ExpandConstant('{dotnet40}\InstallUtil.exe'), ServiceLocation, '', SW_HIDE, ewWaitUntilTerminated, ResultCode);

Apparently, Inno setup has the following constants for referencing the .NET folder on your system:

  • {dotnet11}
  • {dotnet20}
  • {dotnet2032}
  • {dotnet2064}
  • {dotnet40}
  • {dotnet4032}
  • {dotnet4064}

More information available here.

brz
  • 1,846
  • 21
  • 21
7

You can use

Exec(
    ExpandConstant('{sys}\sc.exe'),
    ExpandConstant('create "MyService" binPath= {app}\MyService.exe start= auto DisplayName= "My Service" obj= LocalSystem'), 
    '', 
    SW_HIDE, 
    ewWaitUntilTerminated, 
    ResultCode
    )

to create a service. See "sc.exe" on how to start, stop, check service status, delete service, etc.

Steven
  • 681
  • 10
  • 6
2

If you want to avoid reboots when the user upgrades then you need to stop the service before copying the exe and start again after.

There are some script functions to do this at Service - Functions to Start, Stop, Install, Remove a Service

aledpardo
  • 761
  • 9
  • 19
Tony Edgecombe
  • 3,860
  • 3
  • 28
  • 34
  • In your linked article prototypes of the used functions are not precisely translated and their usage is also not correct (there is e.g. no waiting for the service to start, stop etc.). – TLama Dec 11 '14 at 05:27
0

have a look at topshelf http://topshelf-project.com/

  • it lets you develop your service as a console application

  • adds a start/stop service as an API to your service...

  • ... that you can call from InnoSetup

    [Run] Filename: "{app}\myservice.exe"; Parameters: "stop" ; Flags : waituntilterminated Filename: "{app}\myservice.exe"; Parameters: "uninstall" ; Flags : waituntilterminated Filename: "{app}\myservice.exe"; Parameters: "install -description ""myservice""" ; Flags : waituntilterminated

f.capet
  • 39
  • 2