2009-03-04 14 views
8

Ho un'applicazione di servizio costruita in Delphi che funziona benissimo. Fa esattamente quello che voglio che faccia e tutto è felice. Tutto va bene finché non voglio eseguire due (o più) istanze di quel servizio su una singola macchina. Poiché il nome del servizio è codificato nel programma (tramite la proprietà Name del servizio), posso installare il servizio una sola volta su un dato computer. Se provo a modificare la proprietà Name in fase di esecuzione, il servizio non risponde a meno che la proprietà Name non sia impostata sulla stessa cosa impostata durante la fase di progettazione.È possibile installare più istanze della stessa applicazione di servizio delphi?

Ho fatto una soluzione per questo in cui ho tutto il codice che non interagisce direttamente con il gestore controllo servizi incapsulato in unità separate (s). Poi scrivo un progetto Delphi separato per ogni istanza che voglio del servizio che ha il codice sufficiente per lanciarsi e iniziare a eseguire il codice principale.

Questo metodo è, a mio parere, brutto ed è certamente inefficiente. Funziona bene per due istanze, ma poi abbiamo bisogno di un terzo e un quarto e ...

C'è un modo per modificare il mio codice in modo da avere un solo progetto Delphi che può installare ed eseguire se stesso come più istanze di servizio con qualche semplice input di runtime (es. flag della riga di comando)?

O forse una domanda più ampia: esiste una "via giusta" per raggiungere l'obiettivo?

risposta

13

Non è stato chiarito cosa si è tentato di modificare nella sottoclasse TService.

Hai aggiunto un gestore "BeforeInstall"?

Qualcosa di simile:

procedure TServiceMain.ServiceLoadInfo(Sender : TObject);// new method, not an override 
begin 
    Name := ParamStr(2); 
    DisplayName := ParamStr(3); 
end; 

procedure TServiceMain.ServiceBeforeInstall(Sender: TService); 
begin 
    ServiceLoadInfo(Self); 
end; 
procedure TServiceMain.ServiceCreate(Sender: TObject); 
begin 
    ServiceLoadInfo(Self); 
end; 

Se si esegue questa operazione regolarmente, sottoclasse TService fare thie nel costruttore, invece.

Si dovrebbe fare lo stesso anche in BeforeUninstall - puntare entrambi gli eventi con lo stesso metodo.

C:\>servicename /install MyService "My Service Description" 
+0

Se si esegue questa operazione, il servizio non viene eseguito a meno che ParamStr (2) non sia uguale al valore impostato per Nome in Object Inspector nell'IDE. Se ParamStr (2) è diverso, quando il servizio viene avviato, entra in uno stato di "Avvio" perpetuo e non viene mai eseguito. –

+0

Siamo spiacenti, questa è solo una parte di ciò che è necessario. Hai bisogno dell'evento OnStart per chiamare anche questo. (Lavorando dalla memoria qui!) –

+0

Non riesco a trovare questo metodo ServiceLoadInfo che si sta utilizzando. È un metodo standard, o solo un suggerimento per scrivere un metodo che capisca quale nome viene chiamato in questa istanza? –

3

È possibile creare il proprio servizio con più thread internamente, ognuno dei quali si comporta come se fosse la propria versione/copia del servizio. Lo controlli con l'API di Service Controller, IIRC.

+0

Ho pensato a questo, ma sembrava che fosse fondamentalmente creare codice duplicato. Le caratteristiche dei servizi di Windows hanno già il codice di controllo del thread integrato. Perché non sfruttare questo piuttosto che rotolare il mio? –

+0

No, non è quello che sto dicendo. Windows ha il codice del controller di servizio da utilizzare per avviare/interrompere più thread. Sposta il tuo codice di servizio in un TThread e per ogni istanza del tuo servizio inizia semplicemente un altro thread. Una spiegazione migliore, spero, di ciò che intendevo. –

+0

Mi dispiace, continuo a non pensare di aver capito. Come appare nel pannello di controllo Servizi (una voce/più)? Stai suggerendo di utilizzare l'API di controllo del servizio all'interno del mio codice (ad esempio chiamata ControlService) o semplicemente gestire gli eventi (ad es. ServiceStart, ecc.)? –

2

Ebbene sì, è possibile installare più istanze dello stesso servizio, è sufficiente modificare dinamicamente il nome al momento dell'installazione (non in fase di esecuzione), tuttavia ciò non lo rende desiderabile. (c'è qualche codice di esempio sul progetto Codice http://www.codeproject.com/KB/dotnet/MultipleInstNetWinService.aspx)

Sarei tuttavia incline a ripensare il tuo approccio, i processi di servizio stessi sono in realtà destinati a essere singleton, se hai bisogno di più istanze di un processo in esecuzione, forse il tuo servizio dovrebbe basta controllare e gestire i molteplici processi anziché essere il processo.

+0

Grazie, ma non sono sicuro che questo si applica a Delphi. Questo è quello che ho provato a fare - cambiare il displayName durante l'evento di installazione - ma poi il servizio si è strozzato quando ha provato ad avviarsi sotto il nome "sbagliato". –

+0

Inoltre, si prega di vedere il mio commento alla risposta di Ken ... non sta facendo il tipo di servizio di controller multi-threaded inutilmente rotolare il mio quando Windows potrebbe già fare la parte controller per me? –

+0

Segui il consiglio di Ken. Quello che stai tentando di fare è un esempio di cattiva progettazione. Potresti farlo funzionare? Sicuro. Dovresti? No, non se hai le risorse per farlo correttamente (e questo non è solo un one-off). – Mick

0

Avvolgere tutto il codice in una classe che eredita da TThread.

All'avvio del servizio leggerà un numero da un file di impostazioni o dal registro e creerà molte istanze della classe.

Ogni istanza viene eseguita in modo indipendente.

Per modificare il numero di istanze in esecuzione, è possibile arrestare il servizio, modificare l'impostazione (in un file o registro) e riavviare il servizio.

+0

Con una tale configurazione, diciamo che avvio il servizio con tre thread. Potrei quindi interrompere il thread 2, lasciando in esecuzione i thread 3 e 1 (senza scrivere un mucchio di codice per ricreare in modo efficace il controller del servizio)? –

+0

Con il suggerimento che ho fatto, sì. Il thread principale gestiva le richieste per avviare e interrompere i thread secondari; quei fili del bambino sarebbero quelli che fanno il vero lavoro. Dovresti comunicare con il thread principale del servizio con l'API di controllo servizi. (Come ho detto nel mio commento a voi sotto la mia risposta.) –

0

La risposta accettata sopra è stata terribilmente utile.

codice che ho usato:

procedure TService1.ServiceAfterInstall(Sender: TService); 
begin 
//http://stackoverflow.com/questions/612587/is-it-possible-to-install-multiple-instances-of-the-same-delphi-service-applicati 
//http://www.c-sharpcorner.com/UploadFile/timosten/DynamicServiceInCSharp11262005062503AM/DynamicServiceInCSharp.aspx?ArticleID=4d5020e4-7317-425c-ab29-5bf37a1db421 
//http://support.microsoft.com/kb/137890 
    SaveRegSetting('\SYSTEM\CurrentControlSet\Services\' + Name, 'ImagePath', ParamStr(0) + ' --name=' + Name, HKEY_LOCAL_MACHINE) 
end; 

procedure TService1.ServiceCreate(Sender: TObject); 
begin 
    Name := Trim(FCommandLineOptions.Values['name']); 
    DisplayName := Name; 
end; 

SaveRegSetting è la mia propria procedura e FCommandLineOptions è un oggetto che tokenises i parametri della riga di comando.

Problemi correlati