How to create an installer for a .net Windows Service using Visual Studio

215,286

Solution 1

In the service project do the following:

  1. In the solution explorer double click your services .cs file. It should bring up a screen that is all gray and talks about dragging stuff from the toolbox.
  2. Then right click on the gray area and select add installer. This will add an installer project file to your project.
  3. Then you will have 2 components on the design view of the ProjectInstaller.cs (serviceProcessInstaller1 and serviceInstaller1). You should then setup the properties as you need such as service name and user that it should run as.

Now you need to make a setup project. The best thing to do is use the setup wizard.

  1. Right click on your solution and add a new project: Add > New Project > Setup and Deployment Projects > Setup Wizard

    a. This could vary slightly for different versions of Visual Studio. b. Visual Studio 2010 it is located in: Install Templates > Other Project Types > Setup and Deployment > Visual Studio Installer

  2. On the second step select "Create a Setup for a Windows Application."

  3. On the 3rd step, select "Primary output from..."

  4. Click through to Finish.

Next edit your installer to make sure the correct output is included.

  1. Right click on the setup project in your Solution Explorer.
  2. Select View > Custom Actions. (In VS2008 it might be View > Editor > Custom Actions)
  3. Right-click on the Install action in the Custom Actions tree and select 'Add Custom Action...'
  4. In the "Select Item in Project" dialog, select Application Folder and click OK.
  5. Click OK to select "Primary output from..." option. A new node should be created.
  6. Repeat steps 4 - 5 for commit, rollback and uninstall actions.

You can edit the installer output name by right clicking the Installer project in your solution and select Properties. Change the 'Output file name:' to whatever you want. By selecting the installer project as well and looking at the properties windows, you can edit the Product Name, Title, Manufacturer, etc...

Next build your installer and it will produce an MSI and a setup.exe. Choose whichever you want to use to deploy your service.

Solution 2

I follow Kelsey's first set of steps to add the installer classes to my service project, but instead of creating an MSI or setup.exe installer I make the service self installing/uninstalling. Here's a bit of sample code from one of my services you can use as a starting point.

public static int Main(string[] args)
{
    if (System.Environment.UserInteractive)
    {
        // we only care about the first two characters
        string arg = args[0].ToLowerInvariant().Substring(0, 2);

        switch (arg)
        {
            case "/i":  // install
                return InstallService();

            case "/u":  // uninstall
                return UninstallService();

            default:  // unknown option
                Console.WriteLine("Argument not recognized: {0}", args[0]);
                Console.WriteLine(string.Empty);
                DisplayUsage();
                return 1;
        }
    }
    else
    {
        // run as a standard service as we weren't started by a user
        ServiceBase.Run(new CSMessageQueueService());
    }

    return 0;
}

private static int InstallService()
{
    var service = new MyService();

    try
    {
        // perform specific install steps for our queue service.
        service.InstallService();

        // install the service with the Windows Service Control Manager (SCM)
        ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
    }
    catch (Exception ex)
    {
        if (ex.InnerException != null && ex.InnerException.GetType() == typeof(Win32Exception))
        {
            Win32Exception wex = (Win32Exception)ex.InnerException;
            Console.WriteLine("Error(0x{0:X}): Service already installed!", wex.ErrorCode);
            return wex.ErrorCode;
        }
        else
        {
            Console.WriteLine(ex.ToString());
            return -1;
        }
    }

    return 0;
}

private static int UninstallService()
{
    var service = new MyQueueService();

    try
    {
        // perform specific uninstall steps for our queue service
        service.UninstallService();

        // uninstall the service from the Windows Service Control Manager (SCM)
        ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
    }
    catch (Exception ex)
    {
        if (ex.InnerException.GetType() == typeof(Win32Exception))
        {
            Win32Exception wex = (Win32Exception)ex.InnerException;
            Console.WriteLine("Error(0x{0:X}): Service not installed!", wex.ErrorCode);
            return wex.ErrorCode;
        }
        else
        {
            Console.WriteLine(ex.ToString());
            return -1;
        }
    }

    return 0;
}

Solution 3

Nor Kelsey, nor Brendan solutions does not works for me in Visual Studio 2015 Community.

Here is my brief steps how to create service with installer:

  1. Run Visual Studio, Go to File->New->Project
  2. Select .NET Framework 4, in 'Search Installed Templates' type 'Service'
  3. Select 'Windows Service'. Type Name and Location. Press OK.
  4. Double click Service1.cs, right click in designer and select 'Add Installer'
  5. Double click ProjectInstaller.cs. For serviceProcessInstaller1 open Properties tab and change 'Account' property value to 'LocalService'. For serviceInstaller1 change 'ServiceName' and set 'StartType' to 'Automatic'.
  6. Double click serviceInstaller1. Visual Studio creates serviceInstaller1_AfterInstall event. Write code:

    private void serviceInstaller1_AfterInstall(object sender, InstallEventArgs e)
    {
        using (System.ServiceProcess.ServiceController sc = new 
        System.ServiceProcess.ServiceController(serviceInstaller1.ServiceName))
        {
            sc.Start();
        }
    }
    
  7. Build solution. Right click on project and select 'Open Folder in File Explorer'. Go to bin\Debug.

  8. Create install.bat with below script:

    :::::::::::::::::::::::::::::::::::::::::
    :: Automatically check & get admin rights
    :::::::::::::::::::::::::::::::::::::::::
    @echo off
    CLS 
    ECHO.
    ECHO =============================
    ECHO Running Admin shell
    ECHO =============================
    
    :checkPrivileges 
    NET FILE 1>NUL 2>NUL
    if '%errorlevel%' == '0' ( goto gotPrivileges ) else ( goto getPrivileges ) 
    
    :getPrivileges 
    if '%1'=='ELEV' (shift & goto gotPrivileges)  
    ECHO. 
    ECHO **************************************
    ECHO Invoking UAC for Privilege Escalation 
    ECHO **************************************
    
    setlocal DisableDelayedExpansion
    set "batchPath=%~0"
    setlocal EnableDelayedExpansion
    ECHO Set UAC = CreateObject^("Shell.Application"^) > "%temp%\OEgetPrivileges.vbs" 
    ECHO UAC.ShellExecute "!batchPath!", "ELEV", "", "runas", 1 >> "%temp%\OEgetPrivileges.vbs" 
    "%temp%\OEgetPrivileges.vbs" 
    exit /B 
    
    :gotPrivileges 
    ::::::::::::::::::::::::::::
    :START
    ::::::::::::::::::::::::::::
    setlocal & pushd .
    
    cd /d %~dp0
    %windir%\Microsoft.NET\Framework\v4.0.30319\InstallUtil /i "WindowsService1.exe"
    pause
    
  9. Create uninstall.bat file (change in pen-ult line /i to /u)
  10. To install and start service run install.bat, to stop and uninstall run uninstall.bat

Solution 4

For VS2017 you will need to add the "Microsoft Visual Studio 2017 Installer Projects" VS extension. This will give you additional Visual Studio Installer project templates. https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.MicrosoftVisualStudio2017InstallerProjects#overview

To install the windows service you can add a new setup wizard type project and follow the steps from Kelsey's answer https://stackoverflow.com/a/9021107/1040040

Solution 5

InstallUtil classes ( ServiceInstaller ) are considered an anti-pattern by the Windows Installer community. It's a fragile, out of process, reinventing of the wheel that ignores the fact that Windows Installer has built-in support for Services.

Visual Studio deployment projects ( also not highly regarded and deprecated in the next release of Visual Studio ) do not have native support for services. But they can consume merge modules. So I would take a look at this blog article to understand how to create a merge module using Windows Installer XML that can express the service and then consume that merge module in your VDPROJ solution.

Augmenting InstallShield using Windows Installer XML - Windows Services

IsWiX Windows Service Tutorial

IsWiX Windows Service Video

Share:
215,286

Related videos on Youtube

Rohit Sharma
Author by

Rohit Sharma

Always out numbered, but never out matched!

Updated on August 22, 2020

Comments

  • Rohit Sharma
    Rohit Sharma over 3 years

    How do I create an installer for a Windows Service that I have created using Visual Studio?

    • Macindows
      Macindows over 3 years
      @slayernoah the link seems to be broken. Do you have any other references?
  • Rohit Sharma
    Rohit Sharma over 12 years
    @El Ronnoco, I had the answer long before I posted. I wanted to document it here because I am always having to look it up every 6 - 12 months (and it hasn't been that easy to find) so now I have it easily searchable for everyone and I can find it myself quickly :)
  • Kiley Naro
    Kiley Naro over 12 years
    Out of curiosity, what is the benefit to having a self-installing / un-installing service? If the service installs itself, how do you start the service the first so that it can be installed in the first place? If there is a mechanism for starting the service without installing it, why bother installing it at all?
  • Admin
    Admin over 12 years
    The service isn't running when it installs itself. System.Environment.UserInteractive is true when the executable is started from an interactive console by a user. The code then checks the command line to see if it should install or uninstall itself. After the service has installed itself you need to start it via the services control panel or using something like "net start MyService".
  • Rohit Sharma
    Rohit Sharma over 12 years
    @BrendanLeber I don't think you need to do all that. Just select ServiceInstaller1 on the ProjectInstaller.cs design surface in your service project and then look at the properties window. Set the StartType property to Automatic and it will startup as soon as it is installed... I don't think you need all that code or complexity.
  • Admin
    Admin over 12 years
    @Kelsey - this code isn't to start the service. This code is to install the service in the Service control manager. It takes the place of the setup project you added to your solution. Instead of running "setup.exe" to install the service you would run "myservice.exe /i". As you say changing the StartType to Automatic will make it start automatically when Windows starts. However, after installing you still need to start the service via the SCM or "net start".
  • Christopher Painter
    Christopher Painter over 12 years
    So how do you handle rollbacks? How do you let MSI know that the service exists so that it can monitor the health for repair purposes? How did you make your out of process, self registration code more reliable then the code that's been in Windows Installer ServiceInstall standard action for the last 12 years?
  • Christopher Painter
    Christopher Painter over 12 years
    Unfortunatly, it's also the wrong answer. Yes, I know you'll find this in books and MSDN but it's a case where one group in Microsoft didn't talk to another group in Microsoft and came up with a inferior solution to a problem that had already been solved. See blog.iswix.com/2006/07/msi-vs-net.html for more information.
  • Rohit Sharma
    Rohit Sharma over 12 years
    @Christopher Painter I have been using the MS installer since2k5 and it has never had a problem. Whether or not you agree with it and consider it an 'anti-pattern' is not the point of this question, it is how do I do x with y, not how do I do a with b. When I posted the question it was for documentation purposes.
  • Christopher Painter
    Christopher Painter over 12 years
    Then you've been getting lucky for 6 years you just don't know it. You might want to read: robmensching.com/blog/posts/2007/4/19/…
  • Admin
    Admin over 12 years
    @Christopher - I don't. My solution isn't a replacement for a full installer that you would use to distributing software. I am presenting another option that works for some situations, such as mine where I write software that drives embedded PCs in unattended kiosks.
  • Dan Csharpster
    Dan Csharpster almost 10 years
    If you're not using the wizard and want to add it manually, here is a great article on adding the Service Installer, including code for the custom action codeproject.com/Tips/575177/Window-Service-Deployment-using-‌​VS
  • Kiquenet
    Kiquenet almost 10 years
    What's ManagedInstallerClass.InstallHelper? any full source code about it?
  • Francisco Goldenstein
    Francisco Goldenstein over 9 years
    When you install it on a production machine, remember to run it as administrator. I created a BAT file that calls the EXE file with the /i parameter but it didn't work on the production environment, even though I executed the BAT file as an administrator. I had to open a command line prompt as administrator and invoke the EXE file /i explicitly (without using the BAT file). At least that happened to me on a Windows Server 2012.
  • wolfyuk
    wolfyuk almost 9 years
    If you get a Service name contains invalid characters, is empty, or is too long (max length = 80) error when adding the Installer then right click in the grey area again, go to Properties and ensure that the Service Name value is set.
  • Yogurtu
    Yogurtu almost 9 years
    Let me see if I understand this code... Are you telling me that I can install my service if I execute it for the first time (the true part of the if) else runs the service? Does this solution has the same result as "InstallUtil"? If this works i will freaking love it!!!, why are we not upvoting this?
  • Yogurtu
    Yogurtu almost 9 years
    I'm returning here just to give my upvote to this solution, works EXCELENT. Also, I may add, if you put on the manifest the privileges needed to launch and install, you got a perfect self-setup for your service.
  • Tim
    Tim over 8 years
    Thank you for sharing this. I don't understand why you follow Kelsey's first set of steps to add the installer classes to the service project". Why does ProjectInstaller.cs need to be added?
  • Alexey Obukhov
    Alexey Obukhov about 7 years
    In old Visual Studio there was a deployment project, with easy creation installer. Now I have to buy third-party software component?
  • Jonathan
    Jonathan over 6 years
    RE: No Output on Command Line. Using VS 2017 Community my new service project defaulted to Output type: Windows Application and Startup object: (none). I had to change Output type to Console Application and set my startup object e.g. myservice.Program. If there may be ramifications of which I am unaware, please advise.
  • Nils Guillermin
    Nils Guillermin over 6 years
    Does the example code have typos? Why are there three difference services (CSMessageQueueService, MyService, MyQueueService)?
  • Dung
    Dung over 4 years
    Be careful! it is more complicated if you do not use "Setup Wizard". Because .InstallState file is missing for me when I use "Setup" template, switching to "Setup Wizard" template, the .InstallState file will no longer missing. And after finishing "Setup Wizard" I can still customize the project as it was created with "Setup".
  • Jean-Roch B.
    Jean-Roch B. about 4 years
    @NilsGuillermin just remove them, it's optional (MyService & MyQueueService). Replace CSMessageQueueService by your own. Comment the following: //var service = new MyService(); //service.InstallService(); //var service = new MyQueueService(); //service.UninstallService(); //DisplayUsage();
  • Alan B
    Alan B about 4 years
    @AlexeyObukhov You can use Wix for free, that's what VS itself uses, but the problem with Wix is the same as the problem with Git - the near vertical learning curve.
  • Akbar Asghari
    Akbar Asghari over 3 years
    for VS 2019 you must download this marketplace.visualstudio.com/… before
  • Oleg Bondarenko
    Oleg Bondarenko over 2 years
    if you need to add xml documentation to installer : right click to installer project=> add => project output => documentation files