2010-05-21 35 views

Respuesta

6

Sí, se encuentra: Debugging services: an easy way

Cómo se crea servicios con Delphi? Entonces tal vez también le molesta la forma que consume mucho tiempo de iniciar, reiniciar, matar y adjuntar a la aplicación del proceso de servicio cada vez. Bueno, hay remedio.

No necesita hacer esto. En su lugar, ejecute Delphi como una aplicación de sistema y haga algunas adaptaciones menores al código de servicio .

+0

RunAsSys suena bien. El código de ejemplo en el artículo que enlazó usa definiciones condicionales para seleccionar el "modo". ¿Sabe si RunAsSys permite seleccionar el modo de depuración sin tener que reconstruir la aplicación? Es decir, ¿usar un parámetro de línea de comando para entrar en modo de depuración en lugar de ejecutarlo como un servicio? –

+0

No estoy seguro, pero parece que usted mismo podría agregar esa funcionalidad. – Mick

3

Sí, sí.

En el DPR:

Application.CreateForm(TMyService, MyService); 

_ServiceInDebugMode := SysUtils.FindCmdLineSwitch('DEBUG', True); 
if _ServiceInDebugMode then 
    DebugService(MyService) 
else 
    SvcMgr.Application.Run; 

DebugService es un procedimiento que crea una forma de depuración, un hilo de control de servicio y se inicia todo llamando Forms.Application.Run.

Puede comparar el hilo de control del servicio con el SCM (Service Control Manager) de Windows, el formulario de depuración con una aplicación que se comunica con el SCM (como services.msc) para iniciar y detener servicios. El servicio también debe tener su propio hilo (cadena de servicio) para responder a los códigos de control provenientes de SCM o nuestro hilo de control de servicio y uno o más hilos separados para hacer su trabajo real. Desea hilos separados para el trabajo real (en lugar de codificarlo en los controladores de eventos de su descendiente de TService) para asegurarse de que el hilo en el que se ejecuta el TService siempre responda libremente a los códigos de control del SCM y todavía puede detener y inicie el servicio aun cuando por casualidad a/el hilo de trabajo esté congelado.

Este enfoque también le permite depurar el código de la aplicación de servicio, pero implica una buena cantidad de código y colocar un par de ganchos en las funciones de la API de Windows para que funcionen correctamente. Demasiado para mostrar aquí a corto plazo. Tal vez lo escriba en un artículo algún día.

Mientras tanto, si no desea codificarlo usted solo, tiene dos opciones. Vaya con una biblioteca como SVCOM o la mencionada por Mick que lo haga todo por usted, o cuando esté en modo de depuración omita el código de servicio y "simplemente" comience su servicio como una aplicación de formularios "normal". Tendrá que desentrañar la funcionalidad real de su servicio del código de su descendiente/controladores de eventos, pero eso es algo que recomiendo de todos modos por las razones mencionadas anteriormente.

+0

Tengo la misma aplicación con formularios y servicio. Con formas funciona. Con servicios no funciona. –

+0

@Marjan Venema ¿En que unidad DebugService se encuentra? –

+0

@SpongebobComrade no hay ninguno. Es algo que escribes tú mismo. Lo que debería hacer se menciona en el primer párrafo debajo del código. Verifique las otras respuestas para más información. –

25

Puede utilizar unitDebugService.pas de Colin Wilson's NT Low Level Utilities (página ya no está, available in the wayback machine)

y luego en el DPR:

begin 
    if (paramCount > 0) and (SameText(ParamStr(1), '-DEBUG')) then 
    begin 
    FreeAndNil (Application); 
    Application := TDebugServiceApplication.Create(nil); 
    end; 

    //... the rest of the normal DPR code 
end. 

De esta manera se puede ejecutar desde dentro de Delphi con la depuración (por establecer los parámetros del depurador del proyecto), usar el EXE como un servicio, o ejecutar desde la línea de comandos con el interruptor -DEBUG, y.

13

Use Ejecutar -> Adjuntar para procesar. De esta manera puede depurar un servicio sin realizar ningún cambio en su código.La única parte engañosa tal vez es la depuración del código de inicio del servicio, porque la conexión puede requerir cierto tiempo, y el inicio debe ocurrir en 30 segundos (aunque puede ajustar Windows para permitir un tiempo más prolongado). Puede usar un retraso (sleep ...) para permitir que se adjunte a tiempo, o si solo necesita ver qué sucede, puede usar OutputDebugString() para imprimir en la salida de depuración (use Delphi Event View para verla).

+0

He intentado esto, pero solo aparece la ventana de la CPU con los códigos de ensamblaje. –

+0

'Adjuntar al proceso' funciona bien. Cuando el depurador se conecta por primera vez al proceso de servicio, la ventana de la CPU aparece, pero simplemente puede cerrarla y presionar F9 o el botón Ejecutar para continuar ejecutando el servicio normalmente, y luego puede depurar su código como sea necesario, como cualquier otro proyecto. –

+1

Esto está funcionando bien. Si no desea que aparezca la ventana de la CPU, puede desmarcar la casilla de verificación 'pausa después de adjuntar'. – GolezTrol

5

He intentado esto, pero solo aparece la ventana de la CPU con los códigos de ensamblaje.

Entonces solo deberías resolver este problema.

Básicamente, para depurar un servicio Win2, hay pocas maneras:

  • Uso "asociar al proceso" comando para adjuntar depurador para el servicio ya se está ejecutando. Puede insertar retrasos de inicio para tener tiempo de adjuntar depurador, si necesita adjuntar desde el principio. Sin embargo, también debería modificar el sistema para aumentar el tiempo de espera del servicio.
  • Utilice "Image File Execution Options" registry key para ejecutar forzosamente el depurador de Delphi al arrancar el servicio. Se aplican las mismas consideraciones sobre los tiempos de espera del sistema.
  • Servicio de conversión temporal en la aplicación habitual y ejecutarlo normalmente en el depurador. Puede volver a ejecutar IDE con una cuenta de usuario diferente para obtener más privilegios para el "servicio".

Si por algún motivo solo tiene vista de CPU de su servicio después de iniciar la depuración, esto significa que el depurador de Delphi no puede encontrar la información de depuración para su servicio. Ese es un problema diferente y debería buscar una solución para ello.

lo general, usted tiene que hacer:

  1. Asegúrese de que la carpeta de salida para su aplicación de servicio se establece en carpeta desde la que se cargará por el sistema. Es decir. si su servicio se encuentra en C: \ Windows \ System32 - luego configure la carpeta de salida en C: \ Windows \ System32. No copie el archivo .exe en otro lugar desde su carpeta de salida. Para 64 sistemas puedes probar alias (sysnative/SysWOW64) o nombre real. Creo que es mejor establecer la ruta de salida a la carpeta del proyecto y volver a registrar el servicio que se cargará desde la carpeta del proyecto.
  2. (Opcional) Establezca la ruta de salida para DCU en la misma carpeta que el archivo .exe.
  3. Borre todos sus archivos DCU.
  4. Asegúrese de habilitar las opciones de depuración en la página "Compilador" en las opciones del proyecto.
  5. (Opcional) Además, también puede incluir opciones TD32/RSM/MAP en la página "Enlazador".
  6. Asegúrese de que no hay un experto/extensión IDE, que puede modificar el archivo .exe, la información de depuración o la fecha de modificación del archivo para estos archivos.
  7. Asegúrese de que no haya archivos viejos (DCU/exe) en otras ubicaciones.
  8. Haga una reconstrucción completa (Proyecto/Construir todo).
  9. Ejecute su servicio.
+0

Este método funciona muy bien. – Turrican

13

En realidad es bastante fácil. Simplemente use la directiva de compilador DEBUG estándar para comenzar el servicio como una aplicación de consola en lugar de un servicio.

program MyServiceApp; 

{$ifdef DEBUG} 
    {$APPTYPE CONSOLE} 
{$endif} 

uses 
    System.SysUtils, 

[..]

begin 
    {$ifdef DEBUG} 
    try 
    // In debug mode the server acts as a console application. 
    WriteLn('MyServiceApp DEBUG mode. Press enter to exit.'); 

    // Create the TService descendant manually. 
    ServerContainer1 := TServerContainer.Create(nil); 

    // Simulate service start. 
    ServerContainer1.ServiceStart(ServerContainer1, MyDummyBoolean); 

    // Keep the console box running (ServerContainer1 code runs in the background) 
    ReadLn; 

    // On exit, destroy the service object. 
    FreeAndNil(ServerContainer1); 
    except 
    on E: Exception do 
    begin 
     Writeln(E.ClassName, ': ', E.Message); 
     WriteLn('Press enter to exit.'); 
     ReadLn; 
    end; 
    end; 
    {$else} 
    // Run as a true windows service (release). 
    if not Application.DelayInitialize or Application.Installing then 
    Application.Initialize; 
    Application.CreateForm(TServerContainer, ServerContainer1); 
    Application.Run; 
    {$endif} 
end. 
+0

¡Esto es lejos, un muy buen enfoque! Necesitamos escribir código, en realidad, pero no hay unidades de 3ª parte, funciones o configuraciones de registro de Windows complicadas –

+0

exactamente lo que estaba buscando. gracias. votado. –

Cuestiones relacionadas