views:

21731

answers:

8

I have a standard .NET windows service written in C#.

Can it install itself without using InstallUtil? Should I use the service installer class? How should I use it?

I want to be able to call the following: MyService.exe -install

and it will have the same effect as calling:

InstallUtil MyService.exe

+37  A: 

Yes, that is fully possible (i.e. I do exactly this); you just need to reference the right dll (System.ServiceProcess.dll) and add an installer class...

Here's an example.

Marc Gravell
+1d, see also http://stackoverflow.com/questions/1449994/inno-setup-for-windows-service
Ruben Bartelink
+1  A: 

Here is a class I use when writing services. I usually have an interactive screen that comes up when the service is not called. From there I use the class as needed. It allows for multiple named instances on the same machine -hence the InstanceID field

Sample Call

  IntegratedServiceInstaller Inst = new IntegratedServiceInstaller();
  Inst.Install("MySvc", "My Sample Service", "Service that executes something",
                    _InstanceID,
// System.ServiceProcess.ServiceAccount.LocalService,      // this is more secure, but only available in XP and above and WS-2003 and above
  System.ServiceProcess.ServiceAccount.LocalSystem,       // this is required for WS-2000
  System.ServiceProcess.ServiceStartMode.Automatic);
  if (controller == null)
  {
    controller = new System.ServiceProcess.ServiceController(String.Format("MySvc_{0}", _InstanceID), ".");
                }
                if (controller.Status == System.ServiceProcess.ServiceControllerStatus.Running)
                {
                    Start_Stop.Text = "Stop Service";
                    Start_Stop_Debugging.Enabled = false;
                }
                else
                {
                    Start_Stop.Text = "Start Service";
                    Start_Stop_Debugging.Enabled = true;
                }

The class itself

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Microsoft.Win32;

namespace MySvc
{
    class IntegratedServiceInstaller
    {
     public void Install(String ServiceName, String DisplayName, String Description,
            String InstanceID,
      System.ServiceProcess.ServiceAccount Account, 
      System.ServiceProcess.ServiceStartMode StartMode)
     {
      //http://www.theblacksparrow.com/
      System.ServiceProcess.ServiceProcessInstaller ProcessInstaller = new System.ServiceProcess.ServiceProcessInstaller();
      ProcessInstaller.Account = Account;

      System.ServiceProcess.ServiceInstaller SINST = new System.ServiceProcess.ServiceInstaller();

            System.Configuration.Install.InstallContext Context = new System.Configuration.Install.InstallContext();
      string processPath = Process.GetCurrentProcess().MainModule.FileName;
      if (processPath != null && processPath.Length > 0)
      {
                System.IO.FileInfo fi = new System.IO.FileInfo(processPath);

                String path = String.Format("/assemblypath={0}", fi.FullName);
                String[] cmdline = { path };
                Context = new System.Configuration.Install.InstallContext("", cmdline);
      }

      SINST.Context = Context;
            SINST.DisplayName = String.Format("{0} - {1}", DisplayName, InstanceID);
            SINST.Description = String.Format("{0} - {1}", Description, InstanceID);
      SINST.ServiceName = String.Format("{0}_{1}", ServiceName, InstanceID);
      SINST.StartType = StartMode;
      SINST.Parent = ProcessInstaller;

            // http://bytes.com/forum/thread527221.html
            SINST.ServicesDependedOn = new String[] { "Spooler", "Netlogon", "Netman" };

      System.Collections.Specialized.ListDictionary state = new System.Collections.Specialized.ListDictionary();
      SINST.Install(state);

            // http://www.dotnet247.com/247reference/msgs/43/219565.aspx
            using (RegistryKey oKey = Registry.LocalMachine.OpenSubKey(String.Format(@"SYSTEM\CurrentControlSet\Services\{0}_{1}", ServiceName, InstanceID), true))
            {
                try
                {
                    Object sValue = oKey.GetValue("ImagePath");
                    oKey.SetValue("ImagePath", sValue);
                }
                catch (Exception Ex)
                {
                    System.Windows.Forms.MessageBox.Show(Ex.Message);
                }
            }

     }
     public void Uninstall(String ServiceName, String InstanceID)
     {
      //http://www.theblacksparrow.com/
      System.ServiceProcess.ServiceInstaller SINST = new System.ServiceProcess.ServiceInstaller();

      System.Configuration.Install.InstallContext Context = new System.Configuration.Install.InstallContext("c:\\install.log", null);
      SINST.Context = Context;
            SINST.ServiceName = String.Format("{0}_{1}", ServiceName, InstanceID);
            SINST.Uninstall(null);
     }
    }
}
Brad Bruce
A: 

will u plz tell me wht is InstanceId in the parameter of fun ction

ALso tell me how its related with service property
A: 

Hi! I have a problem with a Setup Project. I install a Windows Service with a VS Setup project. When i'm installing the service the intallation show's me a window asking me for user and password (the same window that InstallUtil shows).

I can install the service but, how can I obtain that values for the installation? The user and password? Because I wanna give to the user privilegies on a folder.

I tried asking for user and password before, and passing username and password values to the ServiceInstaller but I couldn't install the service. I think InstallUtil has a problem with that, that's because I wanna get the username and values from the installUtil Window. Do the installation sets this values in any part of the context?

Ask separate questions in separate posts
JeffreyABecker
+6  A: 

Take a look at the InstallHelper method of the ManagedInstaller class. You can install a service using:

string[] args;
ManagedInstallerClass.InstallHelper(args);

This is exactly what InstallUtil does. The arguments are the same as for InstallUtil.

The benefits of this method are that it involves no messing in the registry, and it uses the same mechanism as InstallUtil.

adrianbanks
+1 for being very simple
romkyns
+1d, see also http://stackoverflow.com/questions/1449994/inno-setup-for-windows-service
Ruben Bartelink
Why do you suggest this when the docs say this is not meant to be called by user code?
Leeks and Leaks
A: 

Bruce,

I appreciate your solution, it offers the best flexibility I found so far for setting up services. However, I have maybe 2 issues:

  1. after calling it for install, it hangs at "registering event source in Application event log" or something like that
  2. after calling it for uninstall, it again hangs after saying "..was successfully removed..." - is this by design? The service is only disabled then, not deleted.

kind regards Florian

flohack
You should post these as comments to the answer you're commenting on, not as separate answers, because the answers get reordered over time.
romkyns
romkyns - he can't, he hasn't enough reputation for that.
mmcteam.com.ua
+3  A: 

You can always fall back to the good old WinAPI calls, although the amount of work involved is non-trivial. There is no requirement that .NET services be installed via a .NET-aware mechanism.

To install:

  • Open the service manager via OpenSCManager.
  • Call CreateService to register the service.
  • Optionally call ChangeServiceConfig2 to set a description.
  • Close the service and service manager handles with CloseServiceHandle.

To uninstall:

  • Open the service manager via OpenSCManager.
  • Open the service using OpenService.
  • Delete the service by calling DeleteService on the handle returned by OpenService.
  • Close the service and service manager handles with CloseServiceHandle.

The main reason I prefer this over using the ServiceInstaller/ServiceProcessInstaller is that you can register the service with your own custom command line arguments. For example, you might register it as "MyApp.exe -service", then if the user runs your app without any arguments you could offer them a UI to install/remove the service.

Running Reflector on ServiceInstaller can fill in the details missing from this brief explanation.

P.S. Clearly this won't have "the same effect as calling: InstallUtil MyService.exe" - in particular, you won't be able to uninstall using InstallUtil. But it seems that perhaps this wasn't an actual stringent requirement for you.

romkyns
A: 

If you don't want or cannot deal with InstalUtil.exe, or sc.exe, or setup projects you can always use installer building services like installer.codeeffects.com

Jane