2010-03-05 6 views

Répondre

48

Totalement possible. L'astuce consiste à éditer le fichier .dpr pour créer le formulaire principal lorsque vous souhaitez exécuter en tant qu'application et le formulaire de service lorsque vous souhaitez exécuter en tant que service. Comme ceci:

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; 

Le code ci-dessus utilise SvCom pour exécuter le service, mais exactement le même effet pourrait être obtenu en utilisant la norme TService.

J'ai écrit un article à ce sujet pour The Delphi Magazine il y a plusieurs années. Vous pouvez le lire ici: Many Faces Of An Application.

+0

Est-il possible de créer une compilation globale '{$ DEFINE}' qui identifie si elle s'exécute en mode Standlone ou Windows Service? – dipold

+0

quelle est cette unité 'SvCom_NTService'? –

+0

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

1

Cela est possible mais dans ce cas, vous ne pouvez pas utiliser les applications TServiceApplication et TService normales. Vous devez implémenter vous-même tout le code spécifique au service.

Nous avons eu un problème similaire et fait deux applications de cadre: un pour le sable seul exe et un pour le service. Maintenant, nous pouvons créer un seul BPL/DLL intégré dans les deux conteneurs.

Si vous voulez dépenser de l'argent: vous devriez regarder SvCOM, je pense qu'ils ont une solution au problème.

9

Il sera difficile d'expliquer, mais je vais essayer :)

Je l'ai fait dans mon projet comme ça (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

Il y a une solution à ce problème sans écrire une seule ligne de code. Cela dépend un peu de votre application, mais généralement c'est réalisable. Essayez ceci: http://iain.cx/src/nssm. N'oubliez pas de démarrer tous les services dont dépend votre application AVANT de démarrer votre application en tant que service. Google autour pour savoir comment faire cela.

3

Une autre option presque plus simple est disponible à http://cc.embarcadero.com/item/19703, il vous suffit d'inclure une unité et changer votre DPR à quelque chose comme:

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. 

Bien que cet exemple est maintenant tout à fait date, la technique est assez simple que fonctionne encore, même avec Delphi XE2. Avec cela en place, votre application continuera à fonctionner en tant que non-service jusqu'à ce que vous utilisiez le paramètre "/install" (sur une invite de commande élevée). Après quoi, il fonctionnera comme un service jusqu'à ce que vous utilisiez le paramètre "/uninstall" (également sur une invite de commande élevée).

Questions connexes