Click here to Skip to main content
Click here to Skip to main content

Tagged as

Install Windows Service using Custom Actions

, 4 Aug 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
This article explains how to create a custom action EXE to install a Windows Service using WinNT utilities, instsrv.exe and srvany.exe

Introduction

Windows Services can be installed using the Microsoft Installer (MSI) by adding custom actions. This tutorial gives step-by-step details on how to add custom actions to install user services silently. It then modifies the registry entries for the installed services and user account based on user input.

Windows NT resource kit provides two utilities, srvany.exe and instsrv.exe which can be used to allow any Windows application to run as a Windows Service, as well as install and remove any Windows Service.

Creating Custom Action Exe

Use the following steps to create a custom action executable:

  • Create a project of type Windows Application say ServiceInstaller.
  • Add a component class to it. Derive the class from System.Configuration.Install.Installer which will provide the foundation for custom installation.
  • Set its [RunInstaller] attribute to true.
  • Add references to the project using Solution Explorer and in code.
  • Override the Install, Uninstall, and Rollback methods of the base class.
  • Add a main function.
  • Compile the project.

using System.Text;
using System.Configuration.Install;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using System.ServiceProcess;
using System.Resources;
using System.Threading;
using System.Management;
using System.DirectoryServices;
using System.Collections;
using Microsoft.Win32;
using System.Runtime.InteropServices;
 
namespace ServiceInstaller
{
    [RunInstaller(true)]
    public partial class ServiceInstall : System.Configuration.Install.Installer
    { 
        public override void Install(IDictionary savedState)
        {
            base.Install(savedState);
            //Add custom code here
        }
        
        public override void Uninstall(IDictionary savedState)
        {
            base.Uninstall(savedState);
            //Add custom code here
        }
 
        public override void Rollback(IDictionary savedState)
        {
            base.Rollback(savedState);
            //Add custom code here
        }
 
        public override void Commit(IDictionary savedState)
        {
            base.Commit(savedState);
           //Add custom code here
        }
 
        static void Main()
        {
 
        }
    }
}         

Add Custom Action to an MSI project

Add a Setup and Deployment project named SetupService in the same solution.

  • In the File System Editor, select the application folder. On the Action menu, point to Add, and choose Project Output.
  • In the Add Project Output Group dialog box, select the primary output for the ServiceInstaller project. Click OK to close the dialog box.
  • In the Custom Actions Editor, select the Install node. On the Action menu, choose Add Custom Action. In the Select Item in Project dialog box, double-click the Application Folder to the select the primary output from the ServiceInstaller project. Do the same for the Uninstall and Rollback nodes. This signifies that the Install, Rollback and Uninstall methods of the base class have been overridden with custom actions.
  • In the Properties window, set the RemovePreviousVersion property to true.
  • Build the project and click Install on the Project menu.

InstallService.png

LaunchService Method

This method shows how the service is installed using the Windows NT utilities instsrv.exe and srvany.exe.

private bool LaunchService(string serviceEXE)
{
    bool blnServiceInstalled = true;
 
    //Stop Service if running
    System.ServiceProcess.ServiceController[] services;
    services = System.ServiceProcess.ServiceController.GetServices();
    if (services != null)
    {
        for(int intServiceCount=0; intServiceCount<services.Length;intServiceCount++)
        {
            if(services[intServiceCount].ServiceName == serviceEXE)
            {
                if(services[intServiceCount].Status == ServiceControllerStatus.Running)
                {
                    using(StreamWriter sw = File.CreateText(strPath + batchFileName))
                    {
                        sw.WriteLine("net stop {0}", serviceEXE);
                    }
                    ExecuteBatchFile();
                    File.Delete(strPath + batchFileName);
                }
                break;
            }
        }
    }
 
   //Register as Windows Service using instsrv.exe and srvany.exe
   using (StreamWriter sw = File.CreateText(strPath + batchFileName))
   {
        sw.WriteLine("cd {0}", strPath);
        sw.WriteLine("instsrv " + serviceEXE + " " + strPath + "\\" + "srvany.exe");
        sw.Flush();
        sw.Close();
   }
   ExecuteBatchFile();
   File.Delete(strPath + batchFileName);
 
 
   //Modify Registry entries for service added
   RegistryKey SystemServicesKey =  
       Registry.LocalMachine.OpenSubKey("System\\CurrentControlSet\\Services");
   if (SystemServicesKey != null)
   {
        //Open service key with write access
        RegistryKey userServiceKey = SystemServicesKey.OpenSubKey(serviceEXE, true);
        if (userServiceKey != null)
        {
            userServiceKey.SetValue("Description", "Test Service Application");
            if (userName != "")
            {
                userServiceKey.SetValue("ObjectName", ".\\" + userName);
            }
            else
            {
                userServiceKey.SetValue("ObjectName", ServiceAccount.LocalSystem);
            }
            //Set path where service is copied on the system 
            userServiceKey.SetValue("ImagePath", strPath + "\\" +serviceEXE+serviceExtn);
 
            //Start automatically
            userServiceKey.SetValue("Start", 0x02);
 
            userServiceKey.Close();
            SystemServicesKey.Close();
        }
        else
        {
            SystemServicesKey.Close();
            MessageBox.Show("Windows Service registration failed.Installation aborted!");
            blnServiceInstalled = false;
        }
    }
    return blnServiceInstalled;
}

Key Points

  • The user can enter the logon account under whose security context this service will run. The sample code checks whether the logon account entered by the user is one of the domain users on the system. If an invalid user is entered, then LocalSystem is set as the logon account for this service.
  • Custom actions always run at the end of the default installation.

Conclusion

I hope this code provides an insight into writing custom actions and installing Windows services using Windows NT utilities. This is one possible method for installing services. Since the custom action is compiled into an executable, more customized code can, of course, be added.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

lata07mahi
Software Developer
India India
No Biography provided

Comments and Discussions

 
QuestionHow to set password for the configured Account Pinmembertank_rakesh28-Jul-08 1:50 
AnswerRe: How to set password for the configured Account Pinmemberlata07mahi3-Aug-08 22:49 
QuestionWhy not just use what the .NET framework already provide? Pinmember leppie 15-May-08 2:54 
AnswerRe: Why not just use what the .NET framework already provide? PinmemberMartin Bohring15-May-08 5:55 
And even that is not best practice for deployment installations.
It might be sufficient for dev machines, but for production deployment the standard
MSI service install tables should be used.
 
Of course this is not supported by VS deployment projects.
And that is the reason why people try to invent service installation again and again. Cry | :((
 
A conclusion is the place where you got tired of thinking.

AnswerRe: Why not just use what the .NET framework already provide? PinmvpJohn Simmons / outlaw programmer15-May-08 7:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.1411023.1 | Last Updated 4 Aug 2010
Article Copyright 2008 by lata07mahi
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid