I install my C# service (currently on Windows 7 ; I’ve read it exists only since XP and 2003, but it should be all I need to handle) using the ServiceProcessInstaller. My service can run under “Local System” but not “Local Service” nor “Network Service”. Even if my service is basically empty (see code below), I still get
Windows could not start the [service name] service on Local Computer.
Error 5: Access is denied.
Here is my mostly empty service:
EDIT I updated the code to give “Local Service” the necessary access rights.
// Needs System.Configuration.Install.dll and System.ServiceProcess.dll
using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.Reflection;
using System.ServiceProcess;
namespace ServiceTest
{
static class Constants
{
public const string LocalServiceAcctName = @"NT AUTHORITY\LOCAL SERVICE";
public const string ServiceName = "MySvc";
}
class Program
{
/// <summary>
/// Main entry point.
/// </summary>
/// <param name="args">
/// If the 1st argument is "i", it will simply install the service.
/// If it's something else, it will run as a Console application.
/// If it's empty, it will run as a service.
/// </param>
static void Main(string[] args)
{
if (args != null && args.Length != 0 && args[0] == "i")
{
bool result = InstallService(Assembly.GetExecutingAssembly().Location, Constants.ServiceName);
Console.WriteLine(result ? "INSTALLED" : "ERROR INSTALLING");
Console.ReadLine();
}
else
{
var host = new Host();
bool runAsSvc = args == null || args.Length == 0;
host.Launch(runAsSvc);
}
}
static bool InstallService(string exeFullPath, string serviceName)
{
AssemblyInstaller installer = new AssemblyInstaller(exeFullPath, null);
if (ServiceController.GetServices().Any(svcCtlr => svcCtlr.ServiceName == serviceName))
installer.Uninstall(null);
Hashtable dico = new Hashtable();
installer.Install(dico);
installer.Commit(dico);
// Gives "Local Service" the necessary rights on the folder and subfolders and files.
DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(exeFullPath));
DirectorySecurity dirSec = dirInfo.GetAccessControl(AccessControlSections.Access);
FileSystemRights rights = FileSystemRights.Modify;
AccessControlType accessType = AccessControlType.Allow;
dirSec.AddAccessRule(new FileSystemAccessRule(Constants.LocalServiceAcctName, rights, InheritanceFlags.ObjectInherit, PropagationFlags.InheritOnly, accessType));
dirSec.AddAccessRule(new FileSystemAccessRule(Constants.LocalServiceAcctName, rights, InheritanceFlags.ContainerInherit, PropagationFlags.InheritOnly, accessType));
dirSec.AddAccessRule(new FileSystemAccessRule(Constants.LocalServiceAcctName, rights, accessType));
dirInfo.SetAccessControl(dirSec);
return true;
}
}
class Host
{
internal void Launch(bool runAsSvc)
{
if (runAsSvc)
RuntimeService.CreateAndRun(this);
else
{
OnStart();
Console.WriteLine("Component started as a Console app.");
Console.WriteLine("We work a lot...and then we're done.");
OnStop();
Console.WriteLine("Press enter to stop.");
Console.ReadLine();
}
}
internal void OnStart() { Console.WriteLine("We're starting!"); }
internal void OnStop() { Console.WriteLine("We're stopping..."); }
}
class RuntimeService : ServiceBase
{
Host _host;
public RuntimeService(Host host) { _host = host; }
protected override void OnStart(string[] args) { _host.OnStart(); }
protected override void OnStop() { _host.OnStop(); }
internal static void CreateAndRun(Host host) { ServiceBase.Run(new RuntimeService(host)); }
}
/// <summary>
/// Class used to install the service.
/// </summary>
[RunInstaller(true)]
public class RuntimeInstaller : Installer
{
public RuntimeInstaller()
{
var processInstaller = new ServiceProcessInstaller();
processInstaller.Account = ServiceAccount.LocalService; // ServiceAccount.LocalSystem;
var serviceInstaller = new ServiceInstaller();
serviceInstaller.StartType = ServiceStartMode.Automatic;
serviceInstaller.ServiceName = Constants.ServiceName;
Installers.Add(serviceInstaller);
Installers.Add(processInstaller);
}
}
}
Where have you installed the service? The error seems to indicate that the Local Service account does not have access to the service location. So the service manager cannot even load the executable and get it running let alone start the service.
I’ve frequently seen developers do this when developing/debugging a service. They install the service from one of their development folders but set it to run under another account. But by default only the user, the system and the administrators group have access to a user’s folders – so the service fails with an access denied error.