Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Dienst "wird beendet" (https://www.delphipraxis.net/137822-dienst-wird-beendet.html)

FriFra 29. Jul 2009 01:07


Dienst "wird beendet"
 
Ich habe einen eigentlich recht simplen Dienst, welcher beim start über shellexecute ein anderes Programm aufruft. Wenn dieses andere Programm beendet wird, piped dieses eine Message zum Service, welcher sich daraufhin beenden soll. dazu verwende ich einen Timer, welcher eine Variable überwacht, die duch die Message verändert wird:
Delphi-Quellcode:
procedure TEasyServer.Timer1Timer(Sender: TObject);
begin
  if uPipesService.bShutDown then
  begin
    Timer1.Enabled := False;
    FServer.ShutDownServer; //TPipeServer
    FServer.Free;
    EasyServer.DoStop;

  end;
end;
Die Message kommt offensichtlich an, denn der Status des Service wechselt zu "wird beendet"... aber er beendet sich nicht. Es gibt nirgends irgendwelche Schleifen oder ähnliches... ich hab keine Erklärung, warum der Prozess weiter läuft.

Apollonius 29. Jul 2009 15:53

Re: Dienst "wird beendet"
 
Behandelst du das Ereignis OnStop?

FriFra 29. Jul 2009 20:42

Re: Dienst "wird beendet"
 
Ja, da pipe ich noch eine message zu einem anderen Programm (das sich übrigens daraufhin korrekt beendet) und dann sollte eigentlich schluß sein... ist es aber nicht
Delphi-Quellcode:
procedure TEasyServer.ServiceStop(Sender: TService; var Stopped: Boolean);
var
  PipeClient: TPipeClient;
begin
  PipeClient := TPipeClient.Create('', 'easyServerPipe');
  PipeClient.SendString('quit');
  PipeClient.Free;
  Stopped := True;
end;
Wenn ich den dienst über den Dienste-Manager beende piped er die genannten Messages auch an die anderen Programme, aber da wird er dann auch beendet. ich habe langsam den Verdacht das DoStop nicht die richtige Methode ist... Ich würde den dienst auch knallhart abschießen, wenn es denn eine Terminate methode gäbe...

FriFra 30. Jul 2009 21:55

Re: Dienst "wird beendet"
 
:roll: hat keiner eine Idee?

quendolineDD 30. Jul 2009 23:42

Re: Dienst "wird beendet"
 
Es gab doch noch OnShutdown welches beim Beenden aufgerufen wurde. Habe länger nichts mehr mit Services zu tun gehabt und könnte mich dann auch erinnern. Aber ich habe damals an zwei Stellen meine Funktion zum beenden aller Threads (war ein Multithread-Service) aufgerufen.

FriFra 31. Jul 2009 09:38

Re: Dienst "wird beendet"
 
Wenn sich der Service selbst beenden soll, wird bei mir OnShutdown NICHT aufgerufen... ich hab das gerad mal mit Messageboxen geprüft... wenn ich den Dienst über den Dienste-Manager beende, durchläuft der OnStop und Onshutdown und wird sauber beendet.

Es gibt definitiv keine nicht geschlossenen Objekte mehr, die das verursachen können... Ich steh auf dem Schlauch :gruebel:

P.S.: Ich habe auch keine echten Threads, sondern nur eigenständige Anwendungen, welche über Pipes mit dem Server (Consolen-Anwendung) reden, der wiederrum dem Dienst (dient nur als Starter) über Pipes mitteilt, wenn er beendet wird.

FriFra 31. Jul 2009 21:35

Re: Dienst "wird beendet"
 
Ich habs jetzt aufgegeben den Dienst dazu bewegen zu wollen, sich selber zu beenden... Jetzt sennde ich eben keine Message mehr, die den Dienst dazu bringt sich zu beenden, sondern rufe einfach folgenden Code auf:
Delphi-Quellcode:
            ShellExecute(0, 'open', 'net', 'stop EasyServer', '', 0);
Damit ist das Problem gelöst.

skateracer 12. Mär 2010 11:43

Re: Dienst "wird beendet"
 
Bei mir funktioniert nur diese Schreibweise:

ShellExecute(0, 'open', 'cmd', PCHAR('/k' + 'net stop "David Grabbing Server"'), '', 0);

Luckie 12. Mär 2010 11:48

Re: Dienst "wird beendet"
 
Das setzt aber voraus, dass das vom Service gestartete Programm als Administrator läuft.

Dezipaitor 12. Mär 2010 12:33

Re: Dienst "wird beendet"
 
Es gibt einige Probleme mit den Shellfunktionen, wenn man sie aus einem Dienst startet.

Man kann einen Dienst ganz einfach beenden, indem man die Executemethode verlässt.
In den JWSCL Beispielen gibt es einige Dienste, die Pipes verwenden (ja sogar mehrere) und auf deren Ende warten und trotzdem die Dienstmanagernachrichten beantworten. (z.B. unvollendete Projekt: XPElevation -> MainUnit.pas)

Delphi-Quellcode:
   try //except
      try
        fThreadsStoppedEvent  := CreateEvent(nil, true, false, nil);
        fServiceStopEvent  := CreateEvent(nil, true, false, nil);
        Sleep(1000);


        ZeroMemory(@OvLapped, sizeof(OvLapped));
        OvLapped.hEvent := CreateEvent(nil, false, false, nil);
...

          try
            Pipe := CreateServicePipe(Log);
            repeat
              ConnectNamedPipe(Pipe, @OvLapped);

              repeat
                if Assigned(ServiceThread) then
                  ServiceThread.ProcessRequests(False);


                if (TJwWindowsVersion.IsWindowsXP(true) or
                    TJwWindowsVersion.IsWindows2003(true)) and
                      (GetSystemMetrics(SM_SHUTTINGDOWN) <> 0) then
                    Stopped := true;

                SetLastError(0);
                WaitResult := JwMsgWaitForMultipleObjects([fServiceStopEvent, OvLapped.hEvent], false, INFINITE, QS_ALLINPUT);

                case WaitResult of
                  WAIT_OBJECT_0 + 1 : ResetEvent(OvLapped.hEvent);
                  WAIT_OBJECT_0 + 2 : PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE); //tag message as read
                else
                  OutputDebugString(PChar(IntToStr(GetLastError)));
                end;

              until WaitResult <> WAIT_OBJECT_0 + 2; //
             
              if WaitResult = WAIT_OBJECT_0 +1 then //OvLapped.hEvent
              begin
                ...
                {We use this pipe only a very short time so it is very unlikely
                that several clients are going to connect at the same time.
                }
                PipeName := THandleRequestThread.CreatePipeName(UniquePipeID);
               
                ReadFile(Pipe, @ProtocolVersion, sizeof(ProtocolVersion) ,nil, @OvLapped2);

                if JwWaitForMultipleObjects([fServiceStopEvent, OvLapped2.hEvent], false,
                      {$IFNDEF DEBUG}1000{$ELSE}INFINITE{$ENDIF}) = WAIT_OBJECT_0 +1 then
                begin
... //Pipeclient und extra Thread übergeben.
                end;
...
...
              Sleep(5000);
              DisconnectNamedPipe(Pipe);

            until Stopped;

          finally
//signal server shutdown
            Stopped := true;

            {Wait for all threads to be stopped or timeout
             Set by a method that is called by threads which are finished.
             It decreases a value down to 0 and then fires the event.
            }
            WaitForSingleObject(ThreadsStopEvent, 30 * 1000);
         
            fPasswords.Free;
          end;
Und manuelles Stopereignis:
Delphi-Quellcode:
procedure TXPService.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  SetEvent(fServiceStopEvent);
end;

FriFra 12. Mär 2010 12:41

Re: Dienst "wird beendet"
 
Zitat:

Zitat von Luckie
Das setzt aber voraus, dass das vom Service gestartete Programm als Administrator läuft.

Da der Dienst auf dem Systemkonto läuft, läuft das von ihm gestartete Programm auch auf dem Systemkonto... da reicht die Berechtigung aus ;)

sirius 4. Mai 2010 11:50

Re: Dienst "wird beendet"
 
Ich will hier kurz noch anfügen, da ich das Problem auch grad hatte. Folgendes funktioniert zumindest:
Delphi-Quellcode:
//beide Zeilen nacheinander ausführen

PostThreadMessage(ServiceThread.ThreadID,CM_SERVICE_CONTROL_CODE, SERVICE_CONTROL_STOP,0); //hier könnte ein einfaches DoStop evtl. auch reichen
PostThreadMessage(ServiceThread.ThreadID,WM_Quit,0,0); //der ServiceThread verstrickt sich in einer Routine und bricht trotz Terminate nicht ab, wenn kein WM_Quit kommt.

himitsu 4. Mai 2010 12:10

Re: Dienst "wird beendet"
 
Zitat:

Zitat von sirius
Folgendes funktioniert zumindest:

Dieses wird von der externen Anwendung an den Service gesendet?

Wenn ja, dann sollte die Anwendung auch mindestens als Administrator gestartet sein,
denn seit Vista kann eine Anwendung Messages nur noch an Anwendngen mit maximal den selben rechten verschicken.

Also eine "User"-Anwendung kann z.B. keine Message an eine Anwendung mit "Admin"-Rechten verschicken.

sirius 4. Mai 2010 12:13

Re: Dienst "wird beendet"
 
Zitat:

Zitat von himitsu
Zitat:

Zitat von sirius
Folgendes funktioniert zumindest:

Dieses wird von der externen Anwendung an den Service gesendet?

Nö, hier gehts doch um den Service selber. Das kommt von innen.

himitsu 4. Mai 2010 12:21

Re: Dienst "wird beendet"
 
Na dann isses was Anderes.
Konnte jetzt nicht direkt erkennen wer nun Dieses oder Beitrag #7 und #8 nun sendet.
(hätte ja auch die gestartete Anwendung sein können :stupid: )


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:38 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz