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 Dienste und NotifyServiceStatusChangeW (https://www.delphipraxis.net/162434-dienste-und-notifyservicestatuschangew.html)

stOrM 23. Aug 2011 03:29

Dienste und NotifyServiceStatusChangeW
 
Moin,
Ich stehe gerade ein wenig auf dem Schlauch und zwar würde ich gerne für ein Projekt mitbekommen ob irgendein Dienst gestartet oder beendet wurde.

Dazu dachte ich mir bieten sich 2 Dinge an:

Polling:
Was ich gerne vermeiden würde weil permanent über die Liste aller Dienste zu wandern und deren Status zu überprüfen, scheint mir nicht wirklich Resourcen schonend.

Callback über:
NotifyServiceStatusChangeW

Letzteres habe ich gerade mal versucht zu übersetzen:

Delphi-Quellcode:
const
  SERVICE_NOTIFY_CREATED = $00000080;
  SERVICE_NOTIFY_CONTINUE_PENDING = $00000010;
  SERVICE_NOTIFY_DELETE_PENDING = $00000200;
  SERVICE_NOTIFY_DELETED = $00000100;
  SERVICE_NOTIFY_PAUSE_PENDING = $00000020;
  SERVICE_NOTIFY_PAUSED = $00000040;
  SERVICE_NOTIFY_RUNNING = $00000008;
  SERVICE_NOTIFY_START_PENDING = $00000002;
  SERVICE_NOTIFY_STOP_PENDING = $00000004;
  SERVICE_NOTIFY_STOPPED = $00000001;
  SERVICE_NOTIFY_STATUS_CHANGE = $00000002;

type
  PFN_SC_NOTIFY_CALLBACK = function(pvParameter: Pointer): DWORD; stdcall;
  TPFN_SC_NOTIFY_CALLBACK = PFN_SC_NOTIFY_CALLBACK;

type
  _SERVICE_STATUS_PROCESS = record
    dwServiceType, dwCurrentState, dwControlsAccepted, dwWin32ExitCode,
      dwServiceSpecificExitCode, dwCheckPoint, dwWaitHint, dwProcessId,
      dwServiceFlags: DWORD;
  end;
  SERVICE_STATUS_PROCESS = _SERVICE_STATUS_PROCESS;
  LPSERVICE_STATUS_PROCESS = ^_SERVICE_STATUS_PROCESS;
  TSERVICE_STATUS_PROCESS = _SERVICE_STATUS_PROCESS;

type
  _SERVICE_NOTIFYW = record
    dwVersion: DWORD;
    pfnNotifyCallback: TPFN_SC_NOTIFY_CALLBACK;
    pContext: PVOID;
    dwNotificationStatus: DWORD;
    ServiceStatus: SERVICE_STATUS_PROCESS;
    dwNotificationTriggered: DWORD;
    pszServiceNames: PChar;
  end;
  SERVICE_NOTIFYW = _SERVICE_NOTIFYW;
  PSERVICE_NOTIFYW = ^_SERVICE_NOTIFYW;
  TSERVICE_NOTIFYW = _SERVICE_NOTIFYW;
Da die GUI einfriert unter verwendung von SleepEx muß ich das ganze wohl in einen sep. Thread auslagern genau hier liegt eines der Probleme vor denen ich gerade stehe.

In der MSDN steht dazu:

Zitat:

The NotifyServiceStatusChange function can be used to receive notifications about service applications. It cannot be used to receive notifications about driver services.

When the service status changes, the system invokes the specified callback function as an asynchronous procedure call (APC) queued to the calling thread. The calling thread must enter an alertable wait (for example, by calling the SleepEx function) to receive notification. For more information, see Asynchronous Procedure Calls.
Gut dachte ich mir versuche ich das ganze mal mit WaitForMultipleObjectsEx.
Der Thread Funktioniert bei mir nun jetzt sagen wir mal teilweise.

Soll heißen, starte ich die Testanwendung, erhalte ich eine Information wenn irgendein Dienst gestartet oder beendet wurde. Soweit ja schon ok, nur das ich die Meldung nur ein einziges mal erhalte.

Bedeutet:
Anwendung startet Thread, Dienst wird gestartet oder beendet, ich bekomme eine Nachricht darüber. Wird jetzt noch ein Dienst gestartet oder beendet erhalte ich keine Nachricht mehr, Callback wird nicht mehr aufgerufen!

Meine Frage dazu wäre, wie muß ich mein WaitForMultipleObjectsEx aufbauen?
Wenn ich das Richtig sehe brauch ich mindestens 2 Events? Ein TerminateEvent (damit der Thread sauber beendet werden kann und nicht irgendwo hängen bleibt?) sowie ein weiteres Event welches sich um den Callback kümmert?

Ich hatte es vorher mal so angefangen:

Delphi-Quellcode:
  scManagerHandle := OpenSCManager(nil, nil, SC_MANAGER_ENUMERATE_SERVICE);

  if srvManager = 0 then
    exit;

  GetMem(fNotifyBuffer, sizeof(PSERVICE_NOTIFYW));
  fNotifyBuffer^.dwVersion := SERVICE_NOTIFY_STATUS_CHANGE;
  fNotifyBuffer^.pfnNotifyCallback := CALLBACK;
  fNotifyBuffer.pContext := Pointer(nil);

  DResult := NotifyServiceStatusChangeW(scManagerHandle,
    SERVICE_NOTIFY_CREATED or SERVICE_NOTIFY_DELETED, fNotifyBuffer);

    while not Terminated do
  begin
    // nur für den thread selber gedacht, wenn ich den Thread von außen einfach beende der aber auf   ein Alert wartet für den callback bleibt er hängen
    case WaitForMultipleObjectsEx(2, @ThreadHandles[0], FALSE, INFINITE, True) of
      WAIT_OBJECT_0 + 0:
        begin
          try
            exit;
          except

          end;

        end;
      WAIT_OBJECT_0 + 1:
        begin
            if DResult = ERROR_SUCCESS then
            begin
              // hier ist das Problem was mach ich hier nochmal ein WaitformultipleObjects einbauen?
              // Wenn ja, muß ich das Event dann im Callback resetten ?
              // Oder SleepEx ?
            end;
         end;
Also die Frage hier ist wie aus dem Kommentar in Wait_Object_0 +1 hervorgeht was mach ich da?
Da es ja funktionierte einmalig (war noch ein WaitforMultipleObjectsEx enthalten) geh ich davon aus das das Problem genau dort zu liegen scheint, heißt der Callback wird ausgeführt, nur ist der Thread danach wohl nicht mehr in Parkposition bzw. der Thread schon nur eben NotifyServiceStatusChangeW nicht mehr ...

Wäre super, wenn da mal jemand Licht in mein Dunkel bringen könnte.

chaosben 23. Aug 2011 08:03

AW: Dienste und NotifyServiceStatusChangeW
 
Zitat:

Zitat von stOrM (Beitrag 1118760)
Soll heißen, starte ich die Testanwendung, erhalte ich eine Information wenn irgendein Dienst gestartet oder beendet wurde. Soweit ja schon ok, nur das ich die Meldung nur ein einziges mal erhalte.

Das muss so sein denn:
Zitat:

Zitat von MSDN
After the callback function is invoked, the caller must call NotifyServiceStatusChange to receive additional notifications.


stOrM 23. Aug 2011 11:17

AW: Dienste und NotifyServiceStatusChangeW
 
Zitat:

Zitat von chaosben (Beitrag 1118793)
Zitat:

Zitat von stOrM (Beitrag 1118760)
Soll heißen, starte ich die Testanwendung, erhalte ich eine Information wenn irgendein Dienst gestartet oder beendet wurde. Soweit ja schon ok, nur das ich die Meldung nur ein einziges mal erhalte.

Das muss so sein denn:
Zitat:

Zitat von MSDN
After the callback function is invoked, the caller must call NotifyServiceStatusChange to receive additional notifications.


Uff glatt überlesen...
Jetzt bin ich aber nicht sicher ob ich das wirklich verstanden habe? Also ruf ich im Callback dann nochmal NotifyServiceStatusChange auf?

Wie setzt ich denn das nun um jetzt steh ich ja nochmehr auf dem Schlauch als vorher :stupid:

chaosben 23. Aug 2011 11:20

AW: Dienste und NotifyServiceStatusChangeW
 
Das solltest du lieber nicht tun denn:
Zitat:

Zitat von MSDN
Note that certain functions in the Windows API, including NotifyServiceStatusChange and other SCM functions, use remote procedure calls (RPC); these functions might perform an alertable wait operation, so they are not safe to call from within the callback function

Die Lösung ist:
Zitat:

Zitat von MSDN
Instead, the callback function should save the notification parameters and perform any additional work outside the callback.


stOrM 23. Aug 2011 11:25

AW: Dienste und NotifyServiceStatusChangeW
 
Zitat:

Zitat von chaosben (Beitrag 1118877)
Das solltest du lieber nicht tun denn:
Zitat:

Zitat von MSDN
Note that certain functions in the Windows API, including NotifyServiceStatusChange and other SCM functions, use remote procedure calls (RPC); these functions might perform an alertable wait operation, so they are not safe to call from within the callback function

Die Lösung ist:
Zitat:

Zitat von MSDN
Instead, the callback function should save the notification parameters and perform any additional work outside the callback.


Ah ja :shock::?:
Glaub ich bin zu Doof dazu, ich krieg das irgendwie nicht gelöst das mir der Callback ein weiteres mal ausgelöst wird. Ich hab schon mittlerweile noch ein Event eingebaut, was ich im Callback zurücksetzen wollte geht irgendwie auch nicht. Gleich nehm ich Variante 1 und machs doch mit polling :mrgreen:

chaosben 23. Aug 2011 14:29

AW: Dienste und NotifyServiceStatusChangeW
 
Ich würde mir das Notify im Callback wegschreiben, von deinem Thread auswerden lassen (eventuell an Hauptthread weiterreichen) und dann deinen Thread das NotifyServiceStatusChange mit dem gleichen Notify-Buffer wieder aufrufen lassen.

Ich hab damit vorhin mal rumgespielt und bin mit einem zusätzlichen Thread klargekommen.

Wenn du noch ein bißchen Zeit hast, kann ich dir vielleicht auch was von meine Code zukommen lassen. Er ist nur im Moment nicht wirklich lesbar. :-D

stOrM 23. Aug 2011 18:51

AW: Dienste und NotifyServiceStatusChangeW
 
Zitat:

Zitat von chaosben (Beitrag 1119003)
Ich würde mir das Notify im Callback wegschreiben, von deinem Thread auswerden lassen (eventuell an Hauptthread weiterreichen) und dann deinen Thread das NotifyServiceStatusChange mit dem gleichen Notify-Buffer wieder aufrufen lassen.

Ich hab damit vorhin mal rumgespielt und bin mit einem zusätzlichen Thread klargekommen.

Wenn du noch ein bißchen Zeit hast, kann ich dir vielleicht auch was von meine Code zukommen lassen. Er ist nur im Moment nicht wirklich lesbar. :-D

ja das wär was feines wenn du das machen würdest ? :bouncing4:

chaosben 23. Aug 2011 19:11

AW: Dienste und NotifyServiceStatusChangeW
 
Ich seh zu, das ich den Code morgen aufräume. Dann sag ich wieder Bescheid.

stOrM 23. Aug 2011 19:15

AW: Dienste und NotifyServiceStatusChangeW
 
Zitat:

Zitat von chaosben (Beitrag 1119096)
Ich seh zu, das ich den Code morgen aufräume. Dann sag ich wieder Bescheid.

Optimal! Schon mal vielen Dank im vorraus!

chaosben 24. Aug 2011 08:58

AW: Dienste und NotifyServiceStatusChangeW
 
So ... hier (http/svn) der aufgeräumte Code.

Theoretisch ist für dich nur die Klasse TServiceStatusChangeThread interessant.
Wenn was nicht klar ist, sags einfach.

stOrM 24. Aug 2011 14:54

AW: Dienste und NotifyServiceStatusChangeW
 
Krass!
Ich muß da erstmal durchsteigen was Du da alles gebaut hast, so kompliziert hatte ichs mir nicht vorgestellt aber sieht gut aus. Ich hab grad mal einen kleinen Test gebaut für deine Kompo. Bei Uninstall bzw. Install wird der ServiceName jeweils 2 malig ausgegeben?

Neee war mein Fehler funktioniert bestens, schade das es sowas nicht für Processe gibt :)

Viele Grüße

chaosben 24. Aug 2011 19:54

AW: Dienste und NotifyServiceStatusChangeW
 
Ist eigentlich auch nicht schwer. Denk dir einfach das ganze GUI-Komponenten-Zeug weg.

Im Moment ist die ganze Sache auch "fehlerhaft" implementiert. Wenn man innerhalb des Notifies zuviel Zeit verbraucht, kann man nachfolgende Events verpassen.
Mal sehen, vielleicht änder ich das noch mal.

stOrM 25. Aug 2011 08:36

AW: Dienste und NotifyServiceStatusChangeW
 
Zitat:

Zitat von chaosben (Beitrag 1119413)
Ist eigentlich auch nicht schwer. Denk dir einfach das ganze GUI-Komponenten-Zeug weg.

Im Moment ist die ganze Sache auch "fehlerhaft" implementiert. Wenn man innerhalb des Notifies zuviel Zeit verbraucht, kann man nachfolgende Events verpassen.
Mal sehen, vielleicht änder ich das noch mal.

Wär nicht schlecht wenn du an dem Teil weiterbastelst? Weil das hast schon super gemacht, was ich bisher darin gesehen hatte. Vielleicht wird ja ne Kompo draus wo man halt auch steuern kann also quasi ne regelrechte Diensteverwaltung?

Viele Grüße
Marc

chaosben 25. Aug 2011 08:44

AW: Dienste und NotifyServiceStatusChangeW
 
Hmmm ... ist n Gedanke ... mal sehen. :)

stOrM 25. Aug 2011 08:49

AW: Dienste und NotifyServiceStatusChangeW
 
Zitat:

Zitat von chaosben (Beitrag 1119475)
Hmmm ... ist n Gedanke ... mal sehen. :)

Dann sag mir bitte vorher bescheid dann weiss ich was ich nicht mehr implmentieren muß in meinem Programm :-D

chaosben 25. Aug 2011 08:52

AW: Dienste und NotifyServiceStatusChangeW
 
Naja .. so schnell wird das nicht. Ab morgen mach ich erst mal Urlaub. :-)

stOrM 25. Aug 2011 08:59

AW: Dienste und NotifyServiceStatusChangeW
 
Zitat:

Zitat von chaosben (Beitrag 1119480)
Naja .. so schnell wird das nicht. Ab morgen mach ich erst mal Urlaub. :-)

Hehe ja gut dann fang ich mal jetzt damit an :mrgreen:
Schönen Urlaub wünsch ich Dir!

chaosben 8. Sep 2011 12:04

AW: Dienste und NotifyServiceStatusChangeW
 
So ... der Urlaub ist vorbei und ich habs hier noch mal "sauber" implementiert.

Um es zu nutzen, leitet man sich eine Klasse von TCustom***Notify ab und tut in der Prozedur
Delphi-Quellcode:
DoNotfication
was man will.
Das neue Konzept ist nicht mehr ganz so klickibunt aber lässt dem Entwickler mehr Freiraum.

Die JWA-Units bezieht man am besten per svn von hier.

Dezipaitor 8. Sep 2011 20:36

AW: Dienste und NotifyServiceStatusChangeW
 
Storm hat die SVN Units aus erster Hand :)

chaosben 9. Sep 2011 05:21

AW: Dienste und NotifyServiceStatusChangeW
 
uups ... da war mein Hinweis ja sehr daneben :-)

stOrM 9. Sep 2011 16:16

AW: Dienste und NotifyServiceStatusChangeW
 
Zitat:

Zitat von chaosben (Beitrag 1122775)
uups ... da war mein Hinweis ja sehr daneben :-)

:mrgreen: Macht doch nichts ich bin eh extrem vergesslich ...
Btw. hab das ganze nun eingebaut klappt wunderbar!


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:46 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