ChatGPT解决这个技术问题 Extra ChatGPT

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

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

@slayernoah the link seems to be broken. Do you have any other references?

C
Community

In the service project do the following:

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. Then right click on the gray area and select add installer. This will add an installer project file to your project. 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.

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 On the second step select "Create a Setup for a Windows Application." On the 3rd step, select "Primary output from..." Click through to Finish.

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

Right click on the setup project in your Solution Explorer. Select View > Custom Actions. (In VS2008 it might be View > Editor > Custom Actions) Right-click on the Install action in the Custom Actions tree and select 'Add Custom Action...' In the "Select Item in Project" dialog, select Application Folder and click OK. Click OK to select "Primary output from..." option. A new node should be created. 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.


@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 :)
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.
@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.
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/…
for VS 2019 you must download this marketplace.visualstudio.com/… before
佚名

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;
}

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?
@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.
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.
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.
Does the example code have typos? Why are there three difference services (CSMessageQueueService, MyService, MyQueueService)?
y
youpilat13

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:

Run Visual Studio, Go to File->New->Project Select .NET Framework 4, in 'Search Installed Templates' type 'Service' Select 'Windows Service'. Type Name and Location. Press OK. Double click Service1.cs, right click in designer and select 'Add Installer' 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'. 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(); } } Build solution. Right click on project and select 'Open Folder in File Explorer'. Go to bin\Debug. 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 Create uninstall.bat file (change in pen-ult line /i to /u) To install and start service run install.bat, to stop and uninstall run uninstall.bat


J
JustSomeDev

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


C
Christopher Painter

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


In old Visual Studio there was a deployment project, with easy creation installer. Now I have to buy third-party software component?
@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.