How to Install a Windows Service Programmatically in C#

Installing Windows Service programmatically

You can install the service by adding this code (in the program file, Program.cs) to install itself when run from the commandline using specified parameters:

/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(string[] args)
{
if (System.Environment.UserInteractive)
{

if (args.Length > 0)
{
switch (args[0])
{
case "-install":
{
ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
break;
}
case "-uninstall":
{
ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
break;
}
}
}
}
else
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MyService() };
ServiceBase.Run(ServicesToRun);
}
}

How to install a windows service programmatically in C#?

Ok, here is what REALLY worked for me, it has been tested on multiple machines with different OS ( Vista, XP, Win2k, Win2003 server )

The code has been taken from here so full credit goes to whoever wrote this piece of code.

Once you add the dll or source file into your project make sure to add the ServiceTools namespace and then you have access to some very handy functionality such as...

//Installs and starts the service
ServiceInstaller.InstallAndStart("MyServiceName", "MyServiceDisplayName", "C:\\PathToServiceFile.exe");

//Removes the service
ServiceInstaller.Uninstall("MyServiceName");

//Checks the status of the service
ServiceInstaller.GetServiceStatus("MyServiceName");

//Starts the service
ServiceInstaller.StartService("MyServiceName");

//Stops the service
ServiceInstaller.StopService("MyServiceName");

//Check if service is installed
ServiceInstaller.ServiceIsInstalled("MyServiceName");

I hope this helps.

Unable to install a Windows Service programmatically


public static class SelfInstaller
{
private static readonly string _exePath = Assembly.GetExecutingAssembly().Location;

public static bool InstallMyService()
{
try
{
ManagedInstallerClass.InstallHelper(new string[] { _exePath });
}
catch
{
return false;
}
return true;
}

public static bool UninstallMyService()
{
try
{
ManagedInstallerClass.InstallHelper(new string[] { "/u", _exePath });
}
catch
{
return false;
}
return true;
}
public static bool IsInstalled(string serviceName)
{
var serviceExists = ServiceController.GetServices().Any(s => s.ServiceName == serviceName);
if (serviceExists == null) return false;
return true;
}
}

Installing a windows service programmatically

It looks like the log source is null; are you sure that ServiceConfiguration.ServiceName is defined and has a value?

Programmatically Install Windows Service On Remote Machine

The C# code to do this is as follows:

using (var scmHandle = NativeMethods.OpenSCManager("MachineName", null, NativeMethods.SCM_ACCESS.SC_MANAGER_CREATE_SERVICE))
{
if (scmHandle.IsInvalid)
{
throw new Win32Exception();
}

using (
var serviceHandle = NativeMethods.CreateService(
scmHandle,
"ServiceName",
"Service Display Name",
NativeMethods.SERVICE_ACCESS.SERVICE_ALL_ACCESS,
NativeMethods.SERVICE_TYPES.SERVICE_WIN32_OWN_PROCESS,
NativeMethods.SERVICE_START_TYPES.SERVICE_AUTO_START,
NativeMethods.SERVICE_ERROR_CONTROL.SERVICE_ERROR_NORMAL,
"Path to your service.exe",
null,
IntPtr.Zero,
null,
null,
null))
{
if (serviceHandle.IsInvalid)
{
throw new Win32Exception();
}

NativeMethods.StartService(serviceHandle, 0, null);
}
}

Safe Handle

When dealing with unmanaged handles, you should use SafeHandles which ensure that resources are freed correctly in C#.

[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
public class ServiceControlHandle : SafeHandleZeroOrMinusOneIsInvalid
{
// Create a SafeHandle, informing the base class
// that this SafeHandle instance "owns" the handle,
// and therefore SafeHandle should call
// our ReleaseHandle method when the SafeHandle
// is no longer in use.
private ServiceControlHandle()
: base(true)
{
}

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
override protected bool ReleaseHandle()
{
// Here, we must obey all rules for constrained execution regions.
return NativeMethods.CloseServiceHandle(this.handle);
// If ReleaseHandle failed, it can be reported via the
// "releaseHandleFailed" managed debugging assistant (MDA). This
// MDA is disabled by default, but can be enabled in a debugger
// or during testing to diagnose handle corruption problems.
// We do not throw an exception because most code could not recover
// from the problem.
}
}

P/Invoke signatures

All of the signatures for the functions you need can be found on http://pinvoke.net, and the entire Service Control API can be found here on MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/ms685942(v=vs.85).aspx

using System;
using System.Runtime.InteropServices;

public static class NativeMethods
{
[DllImport("advapi32.dll")]
public static extern ServiceControlHandle OpenSCManager(string lpMachineName, string lpSCDB, SCM_ACCESS scParameter);

[DllImport("Advapi32.dll")]
public static extern ServiceControlHandle CreateService(
ServiceControlHandle serviceControlManagerHandle,
string lpSvcName,
string lpDisplayName,
SERVICE_ACCESS dwDesiredAccess,
SERVICE_TYPES dwServiceType,
SERVICE_START_TYPES dwStartType,
SERVICE_ERROR_CONTROL dwErrorControl,
string lpPathName,
string lpLoadOrderGroup,
IntPtr lpdwTagId,
string lpDependencies,
string lpServiceStartName,
string lpPassword);

[DllImport("advapi32.dll")]
public static extern bool CloseServiceHandle(IntPtr serviceHandle);

[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ControlService(IntPtr hService, SERVICE_CONTROL dwControl, ref SERVICE_STATUS lpServiceStatus);

[DllImport("advapi32.dll")]
public static extern int StartService(ServiceControlHandle serviceHandle, int dwNumServiceArgs, string lpServiceArgVectors);

[DllImport("advapi32.dll", SetLastError = true)]
public static extern ServiceControlHandle OpenService(ServiceControlHandle serviceControlManagerHandle, string lpSvcName, SERVICE_ACCESS dwDesiredAccess);

[DllImport("advapi32.dll")]
public static extern int DeleteService(ServiceControlHandle serviceHandle);

[DllImport("kernel32.dll")]
public static extern int GetLastError();

[Flags]
public enum ACCESS_MASK : uint
{
DELETE = 0x00010000,

READ_CONTROL = 0x00020000,

WRITE_DAC = 0x00040000,

WRITE_OWNER = 0x00080000,

SYNCHRONIZE = 0x00100000,

STANDARD_RIGHTS_REQUIRED = 0x000F0000,

STANDARD_RIGHTS_READ = 0x00020000,

STANDARD_RIGHTS_WRITE = 0x00020000,

STANDARD_RIGHTS_EXECUTE = 0x00020000,

STANDARD_RIGHTS_ALL = 0x001F0000,

SPECIFIC_RIGHTS_ALL = 0x0000FFFF,

ACCESS_SYSTEM_SECURITY = 0x01000000,

MAXIMUM_ALLOWED = 0x02000000,

GENERIC_READ = 0x80000000,

GENERIC_WRITE = 0x40000000,

GENERIC_EXECUTE = 0x20000000,

GENERIC_ALL = 0x10000000,

DESKTOP_READOBJECTS = 0x00000001,

DESKTOP_CREATEWINDOW = 0x00000002,

DESKTOP_CREATEMENU = 0x00000004,

DESKTOP_HOOKCONTROL = 0x00000008,

DESKTOP_JOURNALRECORD = 0x00000010,

DESKTOP_JOURNALPLAYBACK = 0x00000020,

DESKTOP_ENUMERATE = 0x00000040,

DESKTOP_WRITEOBJECTS = 0x00000080,

DESKTOP_SWITCHDESKTOP = 0x00000100,

WINSTA_ENUMDESKTOPS = 0x00000001,

WINSTA_READATTRIBUTES = 0x00000002,

WINSTA_ACCESSCLIPBOARD = 0x00000004,

WINSTA_CREATEDESKTOP = 0x00000008,

WINSTA_WRITEATTRIBUTES = 0x00000010,

WINSTA_ACCESSGLOBALATOMS = 0x00000020,

WINSTA_EXITWINDOWS = 0x00000040,

WINSTA_ENUMERATE = 0x00000100,

WINSTA_READSCREEN = 0x00000200,

WINSTA_ALL_ACCESS = 0x0000037F
}

[Flags]
public enum SCM_ACCESS : uint
{
/// <summary>
/// Required to connect to the service control manager.
/// </summary>
SC_MANAGER_CONNECT = 0x00001,

/// <summary>
/// Required to call the CreateService function to create a service
/// object and add it to the database.
/// </summary>
SC_MANAGER_CREATE_SERVICE = 0x00002,

/// <summary>
/// Required to call the EnumServicesStatusEx function to list the
/// services that are in the database.
/// </summary>
SC_MANAGER_ENUMERATE_SERVICE = 0x00004,

/// <summary>
/// Required to call the LockServiceDatabase function to acquire a
/// lock on the database.
/// </summary>
SC_MANAGER_LOCK = 0x00008,

/// <summary>
/// Required to call the QueryServiceLockStatus function to retrieve
/// the lock status information for the database.
/// </summary>
SC_MANAGER_QUERY_LOCK_STATUS = 0x00010,

/// <summary>
/// Required to call the NotifyBootConfigStatus function.
/// </summary>
SC_MANAGER_MODIFY_BOOT_CONFIG = 0x00020,

/// <summary>
/// Includes STANDARD_RIGHTS_REQUIRED, in addition to all access
/// rights in this table.
/// </summary>
SC_MANAGER_ALL_ACCESS =
ACCESS_MASK.STANDARD_RIGHTS_REQUIRED | SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_LOCK | SC_MANAGER_QUERY_LOCK_STATUS
| SC_MANAGER_MODIFY_BOOT_CONFIG,

GENERIC_READ = ACCESS_MASK.STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS,

GENERIC_WRITE = ACCESS_MASK.STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG,

GENERIC_EXECUTE = ACCESS_MASK.STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK,

GENERIC_ALL = SC_MANAGER_ALL_ACCESS,
}

[Flags]
public enum SERVICE_CONTROL : uint
{
STOP = 0x00000001,

PAUSE = 0x00000002,

CONTINUE = 0x00000003,

INTERROGATE = 0x00000004,

SHUTDOWN = 0x00000005,

PARAMCHANGE = 0x00000006,

NETBINDADD = 0x00000007,

NETBINDREMOVE = 0x00000008,

NETBINDENABLE = 0x00000009,

NETBINDDISABLE = 0x0000000A,

DEVICEEVENT = 0x0000000B,

HARDWAREPROFILECHANGE = 0x0000000C,

POWEREVENT = 0x0000000D,

SESSIONCHANGE = 0x0000000E
}

[Flags]
public enum SERVICE_ACCESS : uint
{
STANDARD_RIGHTS_REQUIRED = 0xF0000,

SERVICE_QUERY_CONFIG = 0x00001,

SERVICE_CHANGE_CONFIG = 0x00002,

SERVICE_QUERY_STATUS = 0x00004,

SERVICE_ENUMERATE_DEPENDENTS = 0x00008,

SERVICE_START = 0x00010,

SERVICE_STOP = 0x00020,

SERVICE_PAUSE_CONTINUE = 0x00040,

SERVICE_INTERROGATE = 0x00080,

SERVICE_USER_DEFINED_CONTROL = 0x00100,

SERVICE_ALL_ACCESS =
(STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE
| SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL)
}

[Flags]
public enum SERVICE_TYPES : int
{
SERVICE_KERNEL_DRIVER = 0x00000001,

SERVICE_FILE_SYSTEM_DRIVER = 0x00000002,

SERVICE_WIN32_OWN_PROCESS = 0x00000010,

SERVICE_WIN32_SHARE_PROCESS = 0x00000020,

SERVICE_INTERACTIVE_PROCESS = 0x00000100
}

public enum SERVICE_ERROR_CONTROL : int
{
/// <summary>
/// The startup program logs the error in the event log, if possible. If the last-known-good configuration is being started, the startup operation fails. Otherwise, the system is restarted with the last-known good configuration.
/// </summary>
SERVICE_ERROR_CRITICAL = 0x00000003,

/// <summary>
/// The startup program ignores the error and continues the startup operation.
/// </summary>
SERVICE_ERROR_IGNORE = 0x00000000,

/// <summary>
/// The startup program logs the error in the event log but continues the startup operation.
/// </summary>
SERVICE_ERROR_NORMAL = 0x00000001,

/// <summary>
/// The startup program logs the error in the event log. If the last-known-good configuration is being started, the startup operation continues. Otherwise, the system is restarted with the last-known-good configuration.
/// </summary>
SERVICE_ERROR_SEVERE = 0x00000002,
}

public enum SERVICE_START_TYPES : int
{
/// <summary>
/// A service started automatically by the service control manager during system startup. For more information, see Automatically Starting Services.
/// </summary>
SERVICE_AUTO_START = 0x00000002,

/// <summary>
/// A device driver started by the system loader. This value is valid only for driver services.
/// </summary>
SERVICE_BOOT_START = 0x00000000,

/// <summary>
/// A service started by the service control manager when a process calls the StartService function. For more information, see Starting Services on Demand.
/// </summary>
SERVICE_DEMAND_START = 0x00000003,

/// <summary>
/// A service that cannot be started. Attempts to start the service result in the error code ERROR_SERVICE_DISABLED.
/// </summary>
SERVICE_DISABLED = 0x00000004,

/// <summary>
/// A device driver started by the IoInitSystem function. This value is valid only for driver services.
/// </summary>
SERVICE_SYSTEM_START = 0x00000001

}

public enum SERVICE_STATE : uint
{
SERVICE_STOPPED = 0x00000001,

SERVICE_START_PENDING = 0x00000002,

SERVICE_STOP_PENDING = 0x00000003,

SERVICE_RUNNING = 0x00000004,

SERVICE_CONTINUE_PENDING = 0x00000005,

SERVICE_PAUSE_PENDING = 0x00000006,

SERVICE_PAUSED = 0x00000007
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SERVICE_STATUS
{
public static readonly int SizeOf = Marshal.SizeOf(typeof(SERVICE_STATUS));

public SERVICE_TYPES dwServiceType;

public SERVICE_STATE dwCurrentState;

public uint dwControlsAccepted;

public uint dwWin32ExitCode;

public uint dwServiceSpecificExitCode;

public uint dwCheckPoint;

public uint dwWaitHint;
}
}

installing a windows service

You will need have a class that derives from ServiceBase and add code to the OnStart and OnStop methods. Once you get that working you can right click anywhere in designer view and choose "Add Installer" which will add the necessary code to the assembly that allows installutil to register the service.

public class YourService : ServiceBase
{
public static void Main(string[] args)
{
ServiceBase.Run(new ServiceBase[] { new YourService() });
}

protected overrides void OnStart(string[] args)
{
// Add code to start your logic here. Try to return immediately.
}

protected overrides void OnStop()
{
// Add code to stop your logic here.
}
}

It is possible that in the OnStart method you are waiting too long to return. You need to make sure that you are only doing enough work to get the logic of your service started. This means you may have to spin up a new thread or otherwise somehow start your logic asynchronously.



Related Topics



Leave a reply



Submit