2012-02-13 7 views
10

He creado algunos servicios en Delphi 7 y no tuve este problema. Ahora que comencé una nueva aplicación de servicio en XE2, no se detendrá correctamente. No sé si es algo que estoy haciendo mal o si podría ser un error en los servicios de XE2.Delphi XE2 El servicio no se detiene correctamente

procedimiento La ejecución se parece a esto:

procedure TMySvc.ServiceExecute(Sender: TService); 
begin 
    try 
    CoInitialize(nil); 
    Startup; 
    try 
     while not Terminated do begin 
     DoSomething; //Problem persists even when nothing's here 
     end; 
    finally 
     Cleanup; 
     CoUninitialize; 
    end; 
    except 
    on e: exception do begin 
     PostLog('EXCEPTION in Execute: '+e.Message); 
    end; 
    end; 
end; 

no tengo una excepción, como se puede ver que registra ninguna excepción. PostLog guarda en un archivo INI, que funciona bien. Ahora uso componentes ADO, así que uso CoInitialize() y CoUninitialize. Se conecta a la base de datos y hace su trabajo correctamente. El problema solo ocurre cuando dejo este servicio. Windows me da el siguiente mensaje:

First stop failure

A continuación, el servicio continúa. Tengo que detenerlo por segunda vez. La segunda vez que se detiene, pero con el siguiente mensaje:

Second stop failure

El archivo de registro indica que el servicio lo hizo con éxito libre (OnDestroy evento se registra) pero nunca se detuvo con éxito (OnStop nunca fue registrada).

En mi código anterior, tengo dos procedimientos Startup y Cleanup. Estos simplemente crear/destruir e inicializar/desinicializar mis cosas necesarias ...

procedure TMySvc.Startup; 
begin 
    FUpdateThread:= TMyUpdateThread.Create; 
    FUpdateThread.OnLog:= LogUpdate; 
    FUpdateThread.Resume; 
end; 

procedure TMySvc.Cleanup; 
begin 
    FUpdateThread.Terminate; 
end; 

Como se puede ver, tengo una ejecución subproceso secundario. De hecho, este servicio tiene numerosos hilos que funcionan así, y el hilo de servicio principal solo está registrando los eventos de cada hilo. Cada hilo tiene diferentes responsabilidades. Los subprocesos informan correctamente y también se cancelan correctamente.

¿Qué podría estar causando esta falla en la detención? Si mi código publicado no expone nada, entonces me pueden enviar más tarde código - sólo hay que 'convertir' a causa de denominación interna, etc.

EDITAR

acabo de comenzar proyecto nuevo servicio

en Delphi XE2, y tienen el mismo problema. Todo esto es mi código de abajo:

unit JDSvc; 

interface 

uses 
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, JDSvcMgr; 

type 
    TJDService = class(TService) 
    procedure ServiceExecute(Sender: TService); 
    private 
    FAfterInstall: TServiceEvent; 
    public 
    function GetServiceController: TServiceController; override; 
    end; 

var 
    JDService: TJDService; 

implementation 

{$R *.DFM} 

procedure ServiceController(CtrlCode: DWord); stdcall; 
begin 
    JDService.Controller(CtrlCode); 
end; 

function TJDService.GetServiceController: TServiceController; 
begin 
    Result := ServiceController; 
end; 

procedure TJDService.ServiceExecute(Sender: TService); 
begin 
    while not Terminated do begin 

    end; 
end; 

end. 
+1

No es probable que sea un error en el código Delphi.¿Puedes reducir esto a una reproducción mínima? –

+0

^^ +1. Parece que su hilo nunca termina, por lo tanto, el tiempo de espera en SCM – whosrdaddy

+1

en mi humilde opinión la rutina TMySvc.Cleanup está destinada a crear problemas. Usted termina FUpdateThread pero no sabe cuándo realmente se termina. Agregue un WaitFor o use un objeto sincronizado para detectar la terminación correctamente. Mire aquí para obtener más información: http://www.eonclash.com/Tutorials/Multithreading/MartinHarvey1.1/Ch5.html – whosrdaddy

Respuesta

6

vistazo al código fuente para el método Execute:

procedure TServiceThread.Execute; 
var 
    msg: TMsg; 
    Started: Boolean; 
begin 
    PeekMessage(msg, 0, WM_USER, WM_USER, PM_NOREMOVE); { Create message queue } 
    try 
    // Allow initialization of the Application object after 
    // StartServiceCtrlDispatcher to prevent conflicts under 
    // Windows 2003 Server when registering a class object with OLE. 
    if Application.DelayInitialize then 
     Application.Initialize; 
    FService.Status := csStartPending; 
    Started := True; 
    if Assigned(FService.OnStart) then FService.OnStart(FService, Started); 
    if not Started then Exit; 
    try 
     FService.Status := csRunning; 
     if Assigned(FService.OnExecute) then 
     FService.OnExecute(FService) 
     else 
     ProcessRequests(True); 
     ProcessRequests(False); 
    except 
     on E: Exception do 
     FService.LogMessage(Format(SServiceFailed,[SExecute, E.Message])); 
    end; 
    except 
    on E: Exception do 
     FService.LogMessage(Format(SServiceFailed,[SStart, E.Message])); 
    end; 
end; 

como se puede ver si no se asigna un método OnExecute, Delphi procesará las solicitudes de SCM (Service Start, Stop, ...) hasta que el servicio se detenga. Cuando hace un bucle en el Servicio. Ejecute debe procesar solicitudes de SCM usted mismo llamando al ProcessRequests(False). Un buen hábito es no utilizar Service.execute e iniciar su workerthread en el evento Service.OnStart y terminarlo/liberarlo en el evento Service.OnStop.

Como se dijo en los comentarios, otro problema radica en la parte FUpdateThread.Terminate. David Heffernan fue directo con el comentario de Free/WaitFor. Asegúrate de finalizar el hilo de forma correcta con los objetos de sincronización.

+2

+1 Recomiendo intercambiar los dos puntos en esta respuesta. El ProcessRequests es la clave y debería estar primero. –

+1

^^ de acuerdo. actualicé mi respuesta. – whosrdaddy

Cuestiones relacionadas