2009-03-04 12 views
8

Tengo una aplicación de servicio integrada en Delphi que funciona muy bien. Hace exactamente lo que yo quiero que haga y todo está feliz. Todo está bien hasta que quiera ejecutar dos (o más) instancias de ese servicio en una sola máquina. Como el nombre del servicio está codificado en el programa (a través de la propiedad Nombre del servicio), solo puedo instalar el servicio una vez en cualquier computadora. Si trato de modificar la propiedad Name en tiempo de ejecución, el servicio no responde a menos que la propiedad Name esté configurada para lo mismo que se configuró durante el tiempo de diseño.¿Es posible instalar varias instancias de la misma aplicación de servicio Delphi?

He hecho una solución para esto donde tengo todo el código que no está interactuando directamente con el administrador de control de servicio encapsulado en unidades separadas. Luego escribo un proyecto Delphi por separado para cada instancia que quiero del servicio que tiene el código suficiente para iniciarse y comenzar a ejecutar el código principal.

Este método es, en mi opinión, feo y sin duda es ineficiente. Funciona bien para dos instancias, pero luego necesitamos un tercero y un cuarto y ...

¿Hay alguna manera de que pueda modificar mi código para que tenga solo un proyecto Delphi que pueda instalarse y ejecutarse como múltiple instancias de servicio con alguna entrada de tiempo de ejecución simple (por ejemplo, indicador de línea de comando)?

O tal vez una pregunta más amplia: ¿Hay una "manera correcta" de lograr el objetivo?

Respuesta

13

No ha aclarado lo que ha intentado cambiar en la subclase TService.

¿Ha agregado un controlador "BeforeInstall"?

Algo así como:

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; 

Si usted hace esto regularmente, subclase TService hacer Thie en el constructor en su lugar.

Debe hacer lo mismo en BeforeUninstall también - apunte ambos eventos con el mismo método.

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

Si hago esto, el servicio no se ejecutará a menos que ParamStr (2) sea igual al valor que se ha establecido para Nombre en el Inspector de objetos en el IDE. Si ParamStr (2) es diferente, cuando se inicia el servicio, entra en un estado perpetuo de "Inicio" y nunca se ejecuta. –

+0

Disculpe, esto es solo una parte de lo que se necesita. Necesita el evento OnStart para llamar esto también. (¡Trabajando desde la memoria aquí!) –

+0

No puedo encontrar este método ServiceLoadInfo que está utilizando. ¿Es ese un método estándar, o simplemente una sugerencia para escribir un método que averigüe a qué nombre se lo está llamando en este caso? –

3

Puede crear su servicio con múltiples subprocesos internos, cada uno actuando como su propia versión/copia del servicio. Usted lo controla con la API del controlador de servicios, IIRC.

+0

Pensé en esto, pero parecía que básicamente creaba código duplicado. Las funciones de servicios de Windows ya tienen incorporado el código de control de subprocesos. ¿Por qué no aprovechar eso en lugar de rodar el mío? –

+0

No, eso no es lo que estoy diciendo. Windows tiene el código de controlador de servicio que puede usar para iniciar/detener varios hilos. Mueva su código de servicio a TThread, y para cada instancia de su servicio simplemente inicie otro hilo. Mejor explicación, espero, de lo que pretendía. –

+0

Lo siento, todavía no creo que lo entiendo. ¿Cómo aparece esto en el panel de control de Servicios (una entrada/múltiple)? ¿Sugiere que utilizo la API de control de servicio en mi código (por ejemplo, llame a ControlService) o simplemente manejo los eventos (por ejemplo, ServiceStart, etc.)? –

2

Bueno, sí, es posible instalar varias instancias del mismo servicio, simplemente necesita modificar dinámicamente el nombre en el momento de la instalación (no en tiempo de ejecución), pero esto no lo hace deseable. (hay algún código de muestra en el proyecto de código http://www.codeproject.com/KB/dotnet/MultipleInstNetWinService.aspx)

Sin embargo, me inclinaría a replantear su enfoque, los procesos de servicio en sí mismos están destinados a ser únicos, si necesita varias instancias de un proceso en ejecución, tal vez su servicio debería simplemente controle y administre los múltiples procesos en lugar de ser el proceso.

+0

Gracias, pero no estoy seguro de que esto se aplique a Delphi. Esto es lo que traté de hacer, cambiar el displayName durante el evento de instalación, pero luego el servicio se bloqueó cuando intentó comenzar con el nombre "incorrecto". –

+0

Además, consulte mi comentario a la respuesta de Ken ... ¿no está haciendo el tipo de servicio de controlador de subprocesos múltiples que hace innecesariamente el mío cuando Windows ya podría hacer la parte del controlador por mí? –

+0

Sigue los consejos de Ken. Lo que estás intentando hacer es un ejemplo de mal diseño. ¿Podrías hacer que funcione? Por supuesto. ¿Deberías? No, no si tienes los recursos para hacerlo correctamente (y esto no es solo una excepción). – Mick

0

Envuelva todo su código en una clase heredada de TThread.

Cuando se inicia su servicio, leerá un número de un archivo de configuración o del registro y creará muchas instancias de su clase.

Cada instancia se ejecuta de forma independiente.

Para cambiar el número de instancias en ejecución, puede cerrar el servicio, editar la configuración (en un archivo o registro) y reiniciar el servicio.

+0

Con tal configuración, digamos que empiezo el servicio con tres hilos. ¿Podría entonces detener el hilo 2, dejando los hilos 3 y 1 en ejecución (sin escribir un montón de código para recrear de manera efectiva el controlador de servicio)? –

+0

Con la sugerencia que hice, sí. Su hilo principal manejaría las solicitudes para iniciar y detener hilos hijo; esos hilos de niños serían los que están haciendo el trabajo real. Se comunicaría con el hilo principal del servicio con la API de control de servicio. (Como mencioné en mi comentario debajo de mi respuesta.) –

0

La respuesta aceptada anteriormente fue tremendamente útil.

Código que utiliza:

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 es mi propio procedimiento y FCommandLineOptions es un objeto que tokenises los parámetros de línea de comandos.

Cuestiones relacionadas