代码之家  ›  专栏  ›  技术社区  ›  mr.b Scott Lystig Fritchie

如何使Windows服务应用程序也可以作为独立程序运行?

  •  15
  • mr.b Scott Lystig Fritchie  · 技术社区  · 14 年前

    我将从一个例子开始:ApacheWeb服务器(在Windows下)有一个很好的特性:它既可以作为独立应用程序运行(具有当前用户权限),也可以使用相同的可执行文件直接作为Windows服务安装和运行(作为本地系统帐户)。

    为了让应用程序作为独立的应用程序运行,它所需要做的就是在某些公共类中使用静态public main()。

    为了使应用程序能够作为服务安装和运行,它必须以某种方式实现ServiceBase和Installer类。但是,如果像这样的应用程序作为独立应用程序运行,它将显示消息框。

    如何实现这种类似Apache的操作模式?I believe solution is simple, but I don't really have an idea where to start.

    下面的代码用于调用服务。Can it be modified to allow standalone usage?

    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main()
        {
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[] 
            { 
                new Service() // defined elsewhere as Service : ServiceBase
            };
            ServiceBase.Run(ServicesToRun);
        }
    }
    

    My language of choice is C#.

    编辑: 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.

    我的目标是将这两个可执行文件合并为一个,这将仍然调用Labal.dLL。

    4 回复  |  直到 11 年前
        1
  •  10
  •   Joe Doyle    14 年前

    在C中,一种简单的方法是需要一个命令行参数来将其作为服务运行。如果参数不存在,则运行表单/控制台应用程序。然后让安装程序在安装服务时将参数包含在可执行路径中,这样看起来就像:

    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.

        2
  •  8
  •   mr.b Scott Lystig Fritchie    14 年前

    在进行了一些挖掘之后,我终于找到了.NET Hood(System.ServiceProcess.ServiceBase.Run方法)下的内容,结果发现它检查了 Environment.UserInteractive bool to make sure that executable is NOT run interactively.

    为我工作的过于简单的解决方案:

    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();
            // ...
        }
    }
    
        3
  •  3
  •   Robert Seder    14 年前

    您应该将所有功能都抽象到一个库中。它恰好是从Windows服务运行的这一事实应该无关紧要。事实上,如果您有一个名为servicefrontend的面类,它有start()和stop(),那么Windows服务应用程序可以调用它,命令行应用程序、Windows应用程序或其他应用程序也可以调用它。

    你在这里描述的只是需要更多的抽象。“服务”的功能不需要与Windows服务的运行方式紧密耦合。希望有所帮助

        4
  •  0
  •   Ed.    14 年前

    在您的站点示例中,我非常确信Apache应用程序是用C或C++编写的。为此,你需要一个军人的职能。如果您像普通程序一样执行它,那么会调用main。如果您将服务控制管理器指向它,则会调用ServiceMain。

    关于C,我不能说我知道。如果我必须用C语言编写服务,我想我应该从这里开始- http://msdn.microsoft.com/en-us/library/bb483064.aspx