2010-03-05 25 views

Respuesta

48

Totally possible. El truco es editar el .dpr para crear el formulario principal cuando desee ejecutarlo como una aplicación y el formulario de servicio cuando desee ejecutarlo como un servicio. De esta manera:

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; 

El código anterior utiliza SvCom para ejecutar el servicio, pero exactamente el mismo efecto podría lograrse mediante el estándar TService.

Escribí un artículo sobre eso para The Delphi Magazine hace muchos años. Puede leerlo aquí: Many Faces Of An Application.

+0

¿Es posible crear una compilación global '{$ DEFINE}' que identifique si se está ejecutando en el modo de servicio de Windows o standlone? – dipold

+0

¿Qué es esta unidad 'SvCom_NTService'? –

+0

http://www.aldyn-software.com/svcom.html – gabr

1

Es posible, pero en ese caso no puede usar TServiceApplication y TService normales. Debe implementar todo el código específico del servicio usted mismo.

Tuvimos un problema similar e hicimos dos aplicaciones de trama: una para el ejecutor solo de arena y otra para el servicio. Ahora podemos crear un único BPL/DLL que esté integrado en ambos contenedores.

Si quiere gastar algo de dinero: debería mirar SvCOM, creo que tienen una solución al problema.

9

Va a ser difícil de explicar pero voy a intentar :)

lo he hecho en mi proyecto como ese (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. 
2

hay una solución para este problema sin escribir una sola línea de código. Depende un poco de tu aplicación, pero en general es alcanzable. Pruebe esto: http://iain.cx/src/nssm. No olvide iniciar todos los servicios de los que depende su aplicación ANTES de iniciar su aplicación como un servicio. Busque en Google información sobre cómo hacerlo.

3

Otra opción casi más simple está disponible en http://cc.embarcadero.com/item/19703, sólo tiene que incluir una unidad y cambiar su DPR a algo como:

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. 

Aunque este ejemplo está bastante anticuado, la técnica es suficiente que sea sencillo todavía funciona, incluso con Delphi XE2. Con esto en su lugar, su aplicación continuará operando como no-servicio hasta que use el parámetro "/install" (en un símbolo del sistema elevado). Después de lo cual funcionará como un servicio hasta que utilice el parámetro "/uninstall" (también en un símbolo del sistema elevado).

Cuestiones relacionadas