Newsgroup: it.comp.lang.delphi
Titolo: scrivere una semplice "Service Application"

ciao a tutti
sto cercando di scrivere una service application che ogni 2 secondi faccia qualcosa (copia dei files), senza nessuna form grafica, ma non ci riesco proprio.
Sotto scrivo il programma che ho fatto e la unit (sono proprio due righe ma non le so evidentemete fare bene....)
registro il servizio cosě "uno.exe /INSTALL", lo lancio, lui NON ENTRA MAI NELLA EXECUTE!!!, quindi non fa niente, e non riesco neanche a stopparlo piů....
AIUTO!!!!
COSA STO SBAGLIANDO?!?!?!?!
program uno;
uses SvcMgr, main in 'main.pas' {UnoSvc: TService};
{$R *.RES}
begin
  Application.Initialize;
  Application.CreateForm(TUnoSvc, UnoSvc);
  Application.Run;
end.
unit main;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs, ExtCtrls;
type
  TUnoSvc = class(TService)
    procedure ServiceExecute(Sender: TService);
  private
    { Private declarations }
  public
    function GetServiceController: TServiceController; override;
    { Public declarations }
  end;
var
  UnoSvc: TUnoSvc;
implementation
{$R *.DFM}
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  UnoSvc.Controller(CtrlCode);
end;
function TUnoSvc.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;
procedure TUnoSvc.ServiceExecute(Sender: TService);
begin
..
end;
end.
-- 
Questo articolo e` stato inviato dal sito web 
http://www.nonsolonews.it

ci ho sbattuto la testa pure io, devi fare un ciclo che continui a lavorare 
altrimenti il servizio si chiude subito
Simo 


Le ho provate tutte fino ad arrivare a questo stupidissimo OnExecute:
procedure TUnoSvc.ServiceExecute(Sender: TService);
begin
  while not Terminated do
    MessageBox(0, 'testo', 'titolo', MB_OK);
end;
In pratica faccio solo questo!!!
ma sembra che non ci entri mai, cosa devo cambiare?
Sto diventando matto...


Sotto scrivo il programma che ho fatto e la unit (sono proprio due righe ma non le so evidentemete fare bene....)
Immagino che nella Execute() tu non abbia impostato il ciclo che tiene
attivo il servizio. Non essendoci il ciclo di fetch/dispatch dei
messaggi di una normale applicazione Windows, è necessario che il
servizio venga tenuto in vita in qualche modo.

end;
A parte che questo codice è terribilmente indecente, non puoi usare
API per la grafica, se stai scrivendo un servizio.

Andrea,
capisco che non sia il massimo come codice ma, rispetto alla creazione della "Service Application" ho solo messo in piu la MessageBox per vedere se ci entravo (mi sembrava chiaro)
il problema è che nella Execute NON CI ENTRA MAI!!!! MAI!!!! MAIIII!!!!!!! NEANCHE LA PRIMA VOLTA!!!!!
ora:
me la dai una mano e mi dici dove sta l'inghippo o facciamo i puristi sulla MessageBox?????
Andrea Laforgia ha scritto:

-- 


 API per la grafica, se stai scrivendo un servizio.
Se non erro dovrebbe essere possibile utilizzarle se al servizio e'
permesso di interagire con il desktop.
-- 
Vuoi distribuire il tuo sito web su CD/DVD?
Prova 
http://www.dwebpro.com/
Vuoi diventare un esperto analista PHP/MySQL?
Vieni a fare uno stage con noi: 
http://www.creativepark.it/stage/

me la dai una mano e mi dici dove sta l'inghippo o facciamo i puristi sulla MessageBox?????
Già fatto.

permesso di interagire con il desktop.
Gli "interactive services" possono avere una GUI, ma in generale non è
una buona idea scrivere un servizio interattivo.

 una buona idea scrivere un servizio interattivo.
Concordo.
-- 
Vuoi distribuire il tuo sito web su CD/DVD?
Prova 
http://www.dwebpro.com/
Vuoi diventare un esperto analista Delphi?



Ciao, 
sinceramente non ho mai usato l'evento OnExecute perchč l'ho sempre
ritenuto poco pratico, viceversa ho sempre usato gli eventi OnStart e OnStop.
Il ciclo lo faccio fare ad un TTimer. Il codice lo riporto sotto.
Comunque ho provato a far eseguire il codice anche sotto OnExecute, con un
ciclo infinito (While not Terminated..) come te e funziona, ma quando
provo a chiudere il servizio devo attendere parecchio prima che si chiuda
e solitamente ottengo un messaggio di errore in quanto il control manager
ha raggiunto il massimo limite temporale per lo stop del programma. Credo
che sia una cosa normale visto che il programma stesso č in loop infinito
e quindi non da spazio alla gestione dei messaggi.
Usando gli eventi OnStart e OnStop, coniugati con il TTimer il servizio,
mentre non esegue il codice dell'evento OnTimer che il tempo di processare
gli eventi che gli arrivano dal Control manager.
Comunque ti riporto il mio codice, generato da D2006 (non so cosa utilizzi
tu...)
Ciao.
======================================================
program ServizioProva;
uses
  SvcMgr,
  PrincipaleF in 'PrincipaleF.pas' {ServizioDiProva: TService};
{$R *.RES}
begin
  // Windows 2003 Server requires StartServiceCtrlDispatcher to be
  // called before CoRegisterClassObject, which can be called indirectly
  // by Application.Initialize. TServiceApplication.DelayInitialize allows
  // Application.Initialize to be called from TService.Main (after
  // StartServiceCtrlDispatcher has been called).
  //
  // Delayed initialization of the Application object may affect
  // events which then occur prior to initialization, such as
  // TService.OnCreate. It is only recommended if the ServiceApplication
  // registers a class object with OLE and is intended for use with
  // Windows 2003 Server.
  //
  // Application.DelayInitialize := True;
  //
  if not Application.DelayInitialize or Application.Installing then
    Application.Initialize;
  Application.CreateForm(TServizioDiProva, ServizioDiProva);
  Application.Run;
end.
--------------------------------------------------------------
unit PrincipaleF;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr,
Dialogs, IniFiles,
  ExtCtrls;
type
  TServizioDiProva = class(TService)
    Temporizzatore: TTimer;
    procedure ServiceStart(Sender: TService; var Started: Boolean);
    procedure ServiceStop(Sender: TService; var Stopped: Boolean);
    procedure TemporizzatoreTimer(Sender: TObject);
  private
    { Private declarations }
  public
    function GetServiceController: TServiceController; override;
    { Public declarations }
  end;
var
  ServizioDiProva: TServizioDiProva;
implementation
{$R *.DFM}
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  ServizioDiProva.Controller(CtrlCode);
end;
function TServizioDiProva.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;
procedure TServizioDiProva.ServiceStart(Sender: TService; var Started:
Boolean);
begin
        Temporizzatore.Enabled := True;
        Started := True;
end;
procedure TServizioDiProva.ServiceStop(Sender: TService; var Stopped:
Boolean);
begin
        Temporizzatore.Enabled := False;
        Stopped := True;
end;
procedure TServizioDiProva.TemporizzatoreTimer(Sender: TObject);
var
        Impostazioni : TIniFile;
begin
        Impostazioni := TIniFile.Create('C:\TEST.INI');
        Impostazioni.WriteString('CICLO', DateTimeToStr(Now), 'Ok');
        Impostazioni.Free;
end;
end.
Cristiano
--- posted by geoForum on 
http://www.delphiedintorni.it

ritenuto poco pratico, viceversa ho sempre usato gli eventi OnStart e OnStop.
E' sbagliato. Bisogna usare OnExecute() perché è il metodo invocato
dal service thread.

 COSA STO SBAGLIANDO?!?!?!?!
finche l'execute sara' vuoto il servizio OVVIAMENTE, come ben spiegato
nella guida, in qlc tonnellata di vecchi post sia di quetso ng che di
molti altri, non fara un "pene"....
A

 Sto diventando matto...
"la fase + difficile è quella iniziale: si chiama PREPARAZIONE."
A.

 me la dai una mano e mi dici dove sta l'inghippo o facciamo i puristi sulla MessageBox?????
A domande cinofalliche come questa non vale la pena rispondere.
A


Ciao Andrea, 
non credo sia sbagliato, è uno dei due metodi per fare un servizio:
1. usando l'OnExecute 
2. usando gli eventi OnStart, OnStop.
A me piace più il secondo anche perchè durante l'inizializzazione (e
quindi prima di restituire il controllo al service manager) se ci sono
errori posso settare started a False, così vedo che il servizio non è
partito e vado a controllare perchè (log su file ini, registro, mail, ecc.).
Ciao.


2. usando gli eventi OnStart, OnStop.
Niente affatto. Il metodo corretto è quello di usare l'OnExecute
oppure implementare un tuo thread.


Va bene, prendo nota per i prossimi servizi e pubblico, per aiutare il
nostro amico in difficoltà anche un esempio di codice funzionante con
l'evento OnExecute, sperando di essergli di aiuto.
Ciao.
program ServizioProva;

{$R *.RES}

unit PrincipaleF;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr,
Dialogs, IniFiles,
  ExtCtrls;
type
  TServizioDiProva = class(TService)
    Temporizzatore: TTimer;
    procedure TemporizzatoreTimer(Sender: TObject);
    procedure ServiceExecute(Sender: TService);
  private
    { Private declarations }
  public
    function GetServiceController: TServiceController; override;
    { Public declarations }
  end;
var
  ServizioDiProva: TServizioDiProva;
implementation
{$R *.DFM}
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  ServizioDiProva.Controller(CtrlCode);
end;
function TServizioDiProva.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;
procedure TServizioDiProva.ServiceExecute(Sender: TService);
begin
        Temporizzatore.Enabled := True;
        While not Terminated do
        begin
                ServiceThread.ProcessRequests(True);
        end;
        Temporizzatore.Enabled := False;
end;
procedure TServizioDiProva.TemporizzatoreTimer(Sender: TObject);
var
        Impostazioni : TIniFile;
begin
        Impostazioni := TIniFile.Create('C:\TEST.INI');
        Impostazioni.WriteString('CICLO', DateTimeToStr(Now), 'Ok');
        Impostazioni.Free;
end;
end.
Cristiano


> nostro amico in difficoltà anche un esempio di codice funzionante con
una precisazione...il "tuo" amico non è in
"difficolta"...semplicemente non ha studiato.
A.