开发者

How to make windows service application so it can run as a standalone program as well?

开发者 https://www.devze.com 2023-01-05 02:26 出处:网络
I\'ll start with an example: Apache web server (under Windows) has a nice feature: it can be both run as a standalone application (with current users privileges), and that it can be installed and run

I'll start with an example: Apache web server (under Windows) has a nice feature: it can be both run as a standalone application (with current users privileges), and that it can be installed and run as a windows service directly (as local system account), using same executable.

In order for application to be run as a standalone app, all it needs to do is along the lines of having static public Main() in some public class.

In order for application to be installable and runnable as service, it has to implement ServiceBase and Installer classes in certain way. But, if application like this is run as standalone app, it will show message box.

How can this Apache-like mode of operation be achieved? I believe solution is simple, but I don't really have an idea where to start.

Piece of code that follows is used to invoke service. Can it be modified to allow standalone usage?

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    stat开发者_如何学Pythonic void Main()
    {
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] 
        { 
            new Service() // defined elsewhere as Service : ServiceBase
        };
        ServiceBase.Run(ServicesToRun);
    }
}

My language of choice is C#.

Edit: Currently, I have abstracted common code into separate assembly (let's call it Library.dll), and I have two executables: Console.exe and Service.exe, which are standalone and windows service applications, respectively, and both are just means to invoking Library.dll.

My goal is to merge those two executables into one, that will still call to Library.dll.


In C#, an easy way to do it is to require a command line argument to run it as a service. If the argument isn't there, then run your form/console app. Then just have your installer include the argument in the executable path when installing the service so it looks like so:

C:\MyApp\MyApp.exe -service

It would look something like this:

static void Main(string[] args)
{
    foreach (string arg in args)
    {
        //Run as a service if our argument is there
        if (arg.ToLower() == "-service")
        {
            ServiceBase[] servicesToRun = new ServiceBase[] { new Service1() };
            ServiceBase.Run(servicesToRun);
            return;
        }
    }

    //Run the main form if the argument isn't present, like when a user opens the app from Explorer.
    Application.Run(new Form1());
}

This is just an example to give you an idea, there are probably cleaner ways to write this code.


After some digging, I have finally looked under .NET hood (System.ServiceProcess.ServiceBase.Run method), only to find that it checks Environment.UserInteractive bool to make sure that executable is NOT run interactively.

Oversimplified solution that works for me:

class Program
{
    static void Main(string[] args)
    {
        if (!Environment.UserInteractive)
        {
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[] 
            { 
                // Service.OnStart() creates instance of MainLib() 
                // and then calls its MainLib.Start() method
                new Service()
            };
            ServiceBase.Run(ServicesToRun);
            return;
        }

        // Run in a console window
        MainLib lib = new MainLib();
        lib.Start();
        // ...
    }
}


You should really have all of your functionality abstracted in a library. The fact that it happens to be run from a Windows Service should not matter. In fact, if you had a faced class called ServiceFrontEnd that had a Start() and Stop() - the Windows Service application could call that, and so could a command-line app, a windows app, or whatever.

What you're describing here just needs more abstraction. The functionality of "the service" doesn't need to be tightly-coupled to how a Windows Service happens to operate. hope that helps


In the example you site, I'm pretty confident the Apache app is written in C or C++. For that, you would need a ServiceMain function. If you execute it like a normal program, main gets called. If you point the service control manager at it, ServiceMain gets called instead.

Regarding C#, can't say I know about that. If I had to write a service in c#, I suppose I would start here - http://msdn.microsoft.com/en-us/library/bb483064.aspx

0

精彩评论

暂无评论...
验证码 换一张
取 消