Как сделать приложение для 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