Service ServiceMain-Funktion

Wenn ein Dienststeuerungsprogramm die Ausführung eines neuen Diensts anfordert, startet der Dienststeuerungs-Manager (SCM) den Dienst und sendet eine Startanforderung an den Steuerelementverteiler. Der Steuerelementverteiler erstellt einen neuen Thread, um die ServiceMain-Funktion für den Dienst auszuführen. Ein Beispiel finden Sie unter Schreiben einer ServiceMain-Funktion.

Die ServiceMain-Funktion sollte die folgenden Aufgaben ausführen:

  1. Initialisieren Sie alle globalen Variablen.

  2. Rufen Sie sofort die Funktion RegisterServiceCtrlHandler auf, um eine Handlerfunktion zum Verarbeiten von Steuerelementanforderungen für den Dienst zu registrieren. Der Rückgabewert von RegisterServiceCtrlHandler ist ein Dienst status Handle, das in Aufrufen verwendet wird, um den SCM über den Dienst status zu benachrichtigen.

  3. Führen Sie die Initialisierung aus. Wenn die Ausführungszeit des Initialisierungscodes sehr kurz sein soll (weniger als eine Sekunde), kann die Initialisierung direkt in ServiceMain durchgeführt werden.

    Wenn die Initialisierungszeit länger als eine Sekunde betragen soll, sollte der Dienst eine der folgenden Initialisierungstechniken verwenden:

    • Rufen Sie die SetServiceStatus-Funktion auf, um SERVICE_RUNNING zu melden, aber keine Steuerelemente zu akzeptieren, bis die Initialisierung abgeschlossen ist. Dazu ruft der Dienst SetServiceStatus auf, wobei dwCurrentState auf SERVICE_RUNNING und dwControlsAccepted in der SERVICE_STATUS-Struktur auf 0 festgelegt ist. Dadurch wird sichergestellt, dass der SCM keine Steuerungsanforderungen an den Dienst sendet, bevor er bereit ist, und gibt dem SCM frei, andere Dienste zu verwalten. Dieser Ansatz zur Initialisierung wird für die Leistung empfohlen, insbesondere für Autostartdienste.

    • Melden Sie SERVICE_START_PENDING, akzeptieren Sie keine Steuerelemente, und geben Sie einen Wartehinweis an. Wenn der Initialisierungscode Ihres Diensts Aufgaben ausführt, die voraussichtlich länger dauern als der anfängliche Wartehinweiswert, muss Ihr Code die SetServiceStatus-Funktion regelmäßig aufrufen (möglicherweise mit einem überarbeiteten Wartehinweis), um anzugeben, dass der Fortschritt erfolgt. Achten Sie darauf, SetServiceStatus nur dann aufzurufen, wenn die Initialisierung voranschreitet. Andernfalls kann der SCM warten, bis Ihr Dienst den SERVICE_RUNNING Zustand erhält, vorausgesetzt, ihr Dienst macht Fortschritte und blockiert den Start anderer Dienste. Rufen Sie SetServiceStatus nicht aus einem separaten Thread auf, es sei denn, Sie sind sicher, dass der Thread, der die Initialisierung ausführt, wirklich Fortschritte macht.

      Ein Dienst, der diesen Ansatz verwendet, kann auch einen Prüfpunktwert angeben und den Wert während einer langwierigen Initialisierung regelmäßig erhöhen. Das Programm, das den Dienst gestartet hat, kann QueryServiceStatus oderQueryServiceStatusEx aufrufen, um den neuesten Prüfpunktwert aus dem SCM abzurufen, und den Wert verwenden, um dem Benutzer den inkrementellen Fortschritt zu melden.

  4. Rufen Sie nach Abschluss der Initialisierung SetServiceStatus auf, um den Dienststatus auf SERVICE_RUNNING festzulegen und die Steuerelemente anzugeben, für die der Dienst bereit ist, zu akzeptieren. Eine Liste der Steuerelemente finden Sie in der SERVICE_STATUS-Struktur .

  5. Führen Sie die Dienstaufgaben aus, oder geben Sie die Steuerung an den Aufrufer zurück, wenn keine ausstehenden Aufgaben vorhanden sind. Jede Änderung des Dienststatus erfordert einen Aufruf von SetServiceStatus, um neue status Informationen zu melden.

  6. Wenn während der Initialisierung oder Ausführung des Diensts ein Fehler auftritt, sollte der Dienst SetServiceStatus aufrufen, um den Dienststatus auf SERVICE_STOP_PENDING festzulegen, wenn die Bereinigung lang ist. Rufen Sie nach Abschluss der Bereinigung SetServiceStatus auf, um den Dienststatus auf SERVICE_STOPPED vom letzten Thread zum Beenden festzulegen. Stellen Sie sicher, dass Sie die Elemente dwServiceSpecificExitCode und dwWin32ExitCode der SERVICE_STATUS-Struktur festlegen, um den Fehler zu identifizieren.

Schreiben einer ServiceMain-Funktion