Как сделать приложение для Windows, чтобы он мог работать как автономная программа?

Я начну с примера: веб-сервер Apache (под Windows) имеет приятную функцию: он может запускаться как автономное приложение (с текущими правами пользователей) и что его можно установить и запустить как окно (как локальная системная учетная запись), используя тот же исполняемый файл.

Чтобы приложение запускалось как отдельное приложение, все, что ему нужно сделать, это в том же порядке, что и статический public Main() в каком-то публичном классе.

Чтобы приложение могло быть установлено и выполняться как служба, оно должно определенным образом выполнять классы ServiceBase и Installer. Но если приложение вроде этого запускается как автономное приложение, оно отображает окно сообщения.

Как можно добиться такого режима работы, подобного Apache? Я считаю, что решение прост, но на самом деле у меня нет идеи, с чего начать.

Для вызова службы используется следующий код. Могут ли они быть изменены, чтобы обеспечить автономное использование?

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);
    }
}

Мой язык выбора - С#.

Изменить: В настоящее время я отформатировал общий код в отдельной сборке (позвольте мне его вызвать Library.dll), и у меня есть два исполняемых файла: Console.exe и Service.exe, которые являются автономными и windows сервисные приложения, соответственно, и оба являются просто средством вызова Library.dll.

Моя цель состоит в том, чтобы объединить эти два исполняемых файла в один, который все равно вызовет библиотеку Library.dll.

Ответы

Ответ 1

После некоторого копания я, наконец, посмотрел метод .NET hood (System.ServiceProcess.ServiceBase.Run), только чтобы обнаружить, что он проверяет Environment.UserInteractive bool, чтобы убедиться, что исполняемый файл НЕ запускается в интерактивном режиме.

Облегченное решение, которое работает для меня:

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();
        // ...
    }
}

Ответ 2

В С# простой способ сделать это - потребовать, чтобы аргумент командной строки запускал его как службу. Если аргумент отсутствует, запустите приложение формы/консоли. Затем просто установите ваш установщик на аргумент в исполняемом пути при установке службы, чтобы он выглядел так:

C:\MyApp\MyApp.exe -service

Он будет выглядеть примерно так:

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());
}

Это просто пример, дающий вам представление, возможно, есть более чистые способы написания этого кода.

Ответ 3

Вы действительно должны полностью исключить всю свою функциональность в библиотеке. Тот факт, что он запускается с помощью службы Windows, не имеет значения. Фактически, если у вас был класс, называемый ServiceFrontEnd, который имел функции Start() и Stop(), приложение Windows Service могло вызвать это, и это могло бы быть приложение командной строки, приложение Windows или что-то еще.

То, что вы описываете здесь, просто требует большей абстракции. Функциональность "службы" не обязательно должна быть тесно связана с тем, как работает служба Windows. надеюсь, что помогает

Ответ 4

В примере на вашем сайте я уверен, что приложение Apache написано на C или С++. Для этого вам понадобится функция ServiceMain. Если вы выполняете его как обычную программу, main вызывается. Если вы укажете на него диспетчер управления службами, вместо этого вызывается ServiceMain.

Что касается С#, я не могу сказать, что знаю об этом. Если бы мне пришлось писать службу в С#, я бы предположил, что я начну здесь - http://msdn.microsoft.com/en-us/library/bb483064.aspx