Search code examples
c#windows-services

Start Windows Service in C#


I want to start a windows service that was just installed.

ServiceBase[] ServicesToRun;
if (bool.Parse(System.Configuration.ConfigurationManager.AppSettings["RunService"]))
{
    ServicesToRun = new ServiceBase[] { new IvrService() };
    ServiceBase.Run(ServicesToRun);
}

The IvrService code is:

partial class IvrService : ServiceBase
{
    public IvrService()
    {
        InitializeComponent();

        Process myProcess;
        myProcess = System.Diagnostics.Process.GetCurrentProcess();

        string pathname = Path.GetDirectoryName(myProcess.MainModule.FileName);

        //eventLog1.WriteEntry(pathname);

        Directory.SetCurrentDirectory(pathname);

    }

    protected override void OnStart(string[] args)
    {
        string sProcessName = Process.GetCurrentProcess().ProcessName;

        if (Environment.UserInteractive)
        {
            if (sProcessName.ToLower() != "services.exe")
            {
                // In an interactive session.
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new IvrInteractive());
                IvrApplication.Start(); // the key function of the service, start it here
                return;
            }
        }
    }

I am not sure how to start the service. Using ServiceController.Start()? But I already have ServiceBase.Run(ServicesToRun); Is it for starting a service?

Code hint is definitely appreciated.


Solution

  • To answer the question about starting a service from code, you would want something like this (which would be equivalent to running net start myservice from the command line):

    ServiceController sc = new ServiceController();
    sc.ServiceName = "myservice";
    
    if (sc.Status == ServiceControllerStatus.Running || 
        sc.Status == ServiceControllerStatus.StartPending)
    {
        Console.WriteLine("Service is already running");
    }
    else
    {
        try
        {
            Console.Write("Start pending... ");
            sc.Start();
            sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 10));
    
            if (sc.Status == ServiceControllerStatus.Running)
            {
                Console.WriteLine("Service started successfully.");
            }
            else
            {
                Console.WriteLine("Service not started.");
                Console.WriteLine("  Current State: {0}", sc.Status.ToString("f"));
            }
        }
        catch (InvalidOperationException)
        {
            Console.WriteLine("Could not start the service.");
        }
    }
    

    This will start the service, but keep in mind that it will be a different process than the one that is executing the above code.


    Now to answer the question about debugging a service.

    • One option is to attach after the service has been started.
    • The other is to make your service executable be able to run the main code, not as a service but as a normal executable (typically setup via a command line parameter). Then you can F5 into it from your IDE.


    EDIT: Adding sample flow of events (based on questions from some of the comments)

    1. OS is asked to start a service. This can be done from the control panel, the command line, APIs (such as the code above), or automatically by the OS (depending on the service's startup settings).
    2. The operating system then creates a new process.
    3. The process then registers the service callbacks (for example ServiceBase.Run in C# or StartServiceCtrlDispatcher in native code). And then starts running its code (which will call your ServiceBase.OnStart() method).
    4. The OS can then request that a service be paused, stopped, etc. At which point it will send a control event to the already running process (from step 2). Which will result in a call to your ServiceBase.OnStop() method.


    EDIT: Allowing a service to run as a normal executable or as a command line app: One approach is to configure your app as a console application, then run different code based on a command line switch:

    static void Main(string[] args)
    {
        if (args.Length == 0)
        {
            // we are running as a service
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[] { new MyService() };
            ServiceBase.Run(ServicesToRun);
        }
        else if (args[0].Equals("/debug", StringComparison.OrdinalIgnoreCase))
        {
            // run the code inline without it being a service
            MyService debug = new MyService();
            // use the debug object here
        }