Windows Services mit C++

Ein Windows Service läuft im Hintergrund, ohne Oberfläche und damit direkter Interaktion mit dem Benutzer. Ein Service ist etwas anders zu implementieren als ein normales Konsolenprogramm, denn er besteht nicht nur aus einer main() Routine. In der MSDN gibt es ein tolles Beispiel für die Implementierung eines Windows Services.

Der Service Control Manager (SCM) von Windows kontrolliert die Zugriffe auf die Service Datenbank. Bevor der SCM einen Service starten oder konfigurieren kann, muss der Service von einem Programm installiert werden. Ist der Service einmal in der Service Datenbank installiert, kann von einem normalen Konsolenprogramm aus die Startprozedur im SCM ausgelöst werden. Alternativ kann der Service beim Windows Start automatisch mit gestartet werden.

Service Implementierung am Beispiel

Um einen Service zu installieren wird die CreateService Funktion benutzt. Analog dazu wird mit DeleteService der Service wieder deinstalliert.

Damit der SCM mit dem Service Programm interagieren kann, muss dieses zwei Windows API Funktionen bereitstellen:

VOID WINAPI SvcMain( DWORD, LPTSTR * );
VOID WINAPI SvcCtrlHandler( DWORD );

Die SvcMain Funktion ist der Programmeinsprungspunkt (nicht zu verwechseln mit einer normalen main() Funktion) für den Service. Die SvcCtrlHandler Funktion nimmt Kontrollnachrichten des SCM entgegen, wie z.B. das SERVICE_CONTROL_STOP Signal.

Das Service Programm muss in seiner main() Funktion die Verbindung zum SCM herstellen. Dies geschieht über die StartServiceCtrlDispatcher Funktion, in welcher der oder die Hauptserviceroutine(n) hinterlegt werden.

    // Add service routine for the process to this table.
    SERVICE_TABLE_ENTRY DispatchTable[] =
    {
        { SVCNAME, (LPSERVICE_MAIN_FUNCTION) SvcMain },
        { NULL, NULL }
    }; 

    // This call returns when the service has stopped.
    // The process should simply terminate when the call returns.
    StartServiceCtrlDispatcher( DispatchTable );

Damit wird der Hauptthread des Programms zum Dispatcher Thread des Services, welcher erst aus dem StartServiceCtrlDispatcher Aufruf zurückkehrt, wenn der Service beendet wurde.

Die Hauptserviceroutine SvcMain muss zuallererst seinen Handler SvcCtrlHandler registrieren, damit die Kontrollnachrichten vom SCM entgegen genommen werden können.

    gSvcStatusHandle = RegisterServiceCtrlHandler(
        SVCNAME,
        SvcCtrlHandler);

Anschließend kann der eigentliche Service Code initialisiert werden. Hierbei ist zu beachten, dass der Zustand des Service an den SCM mittels SetServiceStatus übermittelt werden muss. Während der Initialisierung ist dieser SERVICE_START_PENDING, anschließend SERVICE_RUNNING.

Bei der Implementierung der SvcCtrlHandler Funktion ist es wichtig zu beachten, dass dort keine langwierigen Operationen ausgeführt werden dürfen. Der Handler wird im Kontext des SCM ausgeführt und nicht im Prozess des Services. Wird dort z.B. das SERVICE_STOP_PENDING Signal empfangen, ist es besser, nur den Status des Services auf SERVICE_STOP_PENDING zu setzen und den Service Prozess über ein Synchronisationsobjekt (z.B. ein Event) zu benachrichtigen. Im Service Prozess kann anschließend der Prozess sauber beendet und der Status auf SERVICE_STOPPED gesetzt werden.

Neuerungen in Windows Vista / Windows 7

Windows Vista bringt einige Verbesserungen im Bezug auf Fehlerbehandlung und Sicherheit. Zum Beispiel laufen Windows Services nun in einem anderen Kontext (session 0) als eingeloggte Benutzer. Mehr Informationen finden sich hier.

Mit Windows 7 bringt uns Microsoft die Möglichkeit, Services nur unter bestimmten Gegebenheiten zu starten. Ein Service kann abhängig von so genannten Service Trigger Events gemacht werden. Damit müssen Services nicht immer laufen, sondern nur wenn sie gebraucht werden. Ein Beispiel hierfür wäre das Anstecken eines USB-Sticks, oder ein beliebig anderer Trigger, der selbst geschrieben werden kann.

Kommentar schreiben

0 Kommentare.

Kommentar schreiben