В Delphi вы можете создать автономное приложение Windows VCL Forms. Вы также можете создать служебное приложение Windows.
Можно ли комбинировать два в одном приложении, которое может работать как отдельное приложение, а также может быть установлено как служба Windows?
Совершенно возможно. Трюк состоит в том, чтобы отредактировать .dpr, чтобы создать основную форму, когда вы хотите запускать приложение и форму обслуживания, когда вы хотите работать как услуга. Вот так:
if SvComFindCommand('config') then begin
//When run with the /config switch, display the configuration dialog.
Forms.Application.Initialize;
Forms.Application.CreateForm(TfrmConfig, frmConfig);
Forms.Application.Run;
end
else begin
SvCom_NTService.Application.Initialize;
SvCom_NTService.Application.CreateForm(TscmServiceSvc, scmServiceSvc);
SvCom_NTService.Application.Run;
end;
В приведенном выше коде используется SvCom для запуска службы, но точно такой же эффект может быть достигнут с использованием стандартного TService.
Я написал статью об этом для журнала Delphi много лет назад. Вы можете прочитать его здесь: Много сторон приложения.
Трудно объяснить, но я попробую:)
Я сделал это в своем проекте (Delphi 5):
program TestSvc;
uses SvcMgr,
SvcMain, //the unit for TTestService inherited from TService
...
;
var
IsDesktopMode : Boolean;
function IsServiceRunning : Boolean;
var
Svc: Integer;
SvcMgr: Integer;
ServSt : TServiceStatus;
begin
Result := False;
SvcMgr := OpenSCManager(nil, nil, SC_MANAGER_CONNECT);
if SvcMgr = 0 then Exit;
try
Svc := OpenService(SvcMgr, 'TestService', SERVICE_QUERY_STATUS);
if Svc = 0 then Exit;
try
if not QueryServiceStatus(Svc, ServSt) then Exit;
Result := (ServSt.dwCurrentState = SERVICE_RUNNING) or (ServSt.dwCurrentState = SERVICE_START_PENDING);
finally
CloseServiceHandle(Svc);
end;
finally
CloseServiceHandle(SvcMgr);
end;
end;
begin
if (Win32Platform <> VER_PLATFORM_WIN32_NT) or FindCmdLineSwitch('S', ['-', '/'], True) then
IsDesktopMode := True
else begin
IsDesktopMode := not FindCmdLineSwitch('INSTALL', ['-', '/'], True) and
not FindCmdLineSwitch('UNINSTALL', ['-', '/'], True) and
not IsServiceRunning;
end;
if IsDesktopMode then begin //desktop mode
Forms.Application.Initialize;
Forms.Application.Title := 'App. Title';
ShowTrayIcon(Forms.Application.Icon.Handle, NIM_ADD); // This function for create an icon to tray. You can create a popupmenu for the Icon.
while GetMessage(Msg, 0, 0, 0) do begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
ShowTrayIcon(Forms.Application.Icon.Handle, NIM_DELETE); // for delete the tray Icon
end else begin // Service mode
SvcMgr.Application.Initialize;
SvcMgr.Application.CreateForm(TTestService, TestService);
SvcMgr.Application.Run;
end;
end.
Другой более простой вариант доступен в http://cc.embarcadero.com/item/19703, вам просто нужно включить устройство и изменить свой DPR на что-то вроде:
begin
if CiaStartService('SERVICE NAME') then begin
CiaService.CreateForm(TMain, Main);
CiaService.Run;
Exit;
end;
Application.Initialize;
Application.Title := 'SERVICE NAME';
Application.CreateForm(TMain, Main);
Application.Run;
end.
Пока этот пример довольно устарел, этот метод достаточно прост, что он все еще работает даже с Delphi XE2. При этом ваше приложение будет продолжать работать как несервис, пока не будет использоваться параметр /install (в командной строке с повышенными правами). После этого он будет работать как служба, пока не будет использоваться параметр /uninstall (также в командной строке с повышенными правами).
Существует решение этой проблемы без написания одной строки кода. Это немного зависит от вашего приложения, но в целом это достижимо. Попробуйте следующее: http://iain.cx/src/nssm. Не забудьте запустить все службы, от которых зависит ваше приложение, до того, как вы запустите приложение в качестве службы. Google для получения информации о том, как это сделать.
Это возможно, но в этом случае вы не можете использовать обычные TServiceApplication и TService. Вы должны сами реализовать весь код службы.
Мы столкнулись с проблемой similat и сделали два фреймовых приложения: один для песочного exe и один для сервиса. Теперь мы можем создать одну BPL/DLL, встроенную в оба контейнера.
Если вы хотите потратить немного денег: вы должны посмотреть на SvCOM, я думаю, что у них есть решение проблемы.
{$DEFINE}
которая определяет, работает ли она в автономном режиме или в режиме службы Windows?SvCom_NTService
?