Windows Systemdienste programmieren
Willemers Informatik-Ecke
Windows Systemdienste sind im Hintergrund laufende Programme, die den Daemonen unter UNIX vergleichbar sind (vgl. http://de.wikipedia.org/wiki/Windows-Systemdienst).

Die Systemdienste werden über die Systemsteuerung verwaltet:

Start - Einstellungen - Systemsteuerung - Verwaltung - Dienste

Alternativ kann man die Dienste auch über den Task-Manager unter dem Reiter Dienste verwalten.

Ein Systemdienst ist ein auführbares Konsolenprogramm, kann aber auch eine DLL sein, die dann von dem Programm svchost.exe aufgerufen wird. Ein Systemdienst muss die Befehle start, pause, continue und stop verstehen und ausführen können.

Der Dienst wird in der Registry eingetragen.

Abhängigkeit von anderen Diensten. Sie können durch das Programm sc.exe verwaltet werden. Sie können die Abhängigkeiten über Systemsteuerung - Verwaltung - Dienste einsehen.

Starten und Stoppen eines Services per Programm

OpenSCManager

Der Zugriff auf die Services erfolgt über den Service Control Manager. Dieser muss mit der Funktion OpenSCManager geöffnet werden.

Der Rückgabewert dieser Funktion wird als Parameter für CreateService und OpenService benötigt.

SC_HANDLE WINAPI OpenSCManager(
  _In_opt_  LPCTSTR lpMachineName,  // NULL für die lokale Maschine
  _In_opt_  LPCTSTR lpDatabaseName, // NULL setzt SERVICES_ACTIVE_DATABASE
  _In_      DWORD dwDesiredAccess   // SC_MANAGER_ALL_ACCESS gibt alle Rechte
);
Ist etwas schiefgegangen, gibt es NULL zurück. Die Funktion GetLastError() liefert eine Fehlernummer.

Nähere Details: http://msdn.microsoft.com/en-us/library/windows/desktop/ms684323%28v=vs.85%29.aspx

CreateService

Erzeugt ein Service-Objekt, trägt dies in der SCM-Datenbank ein und liefert ein Service-Handle zurück. Benötigt als Parameter die Rückgabe von OpenSCManager
SC_HANDLE WINAPI CreateService(
  _In_       SC_HANDLE hSCManager, // Rückgabe von  OpenSCManager
  _In_       LPCTSTR lpServiceName, // für Zugriffe wie OpenService
  _In_opt_   LPCTSTR lpDisplayName, // für die Anzeige
  _In_       DWORD dwDesiredAccess,
  _In_       DWORD dwServiceType,
  _In_       DWORD dwStartType,
  _In_       DWORD dwErrorControl,
  _In_opt_   LPCTSTR lpBinaryPathName, // Der Pfad zum Service-Programm
  _In_opt_   LPCTSTR lpLoadOrderGroup,
  _Out_opt_  LPDWORD lpdwTagId,
  _In_opt_   LPCTSTR lpDependencies,
  _In_opt_   LPCTSTR lpServiceStartName,
  _In_opt_   LPCTSTR lpPassword
);

Das Programm für den Dienst muss sich auf dem lokalen Computer befinden, also nicht beispielsweise auf einem Netzwerklaufwerk.

Der Dienst bleibt in der Diensttabelle, bis er mit DeleteService wieder entfernt wird.

Nähere Details: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682450%28v=vs.85%29.aspx

ControlService

ControlService sendet einen Control-Code an einen Service, beispielsweise, um ihn zu stoppen.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms682108%28v=vs.85%29.aspx

OpenService

OpenService holt für einen Service-Namen das zugehörige Service-Handle, das beispielsweise von DeleteService benötigt wird. Der übergebene Name entspricht dem Namen des Dienstes, wie er im Task-Manager zu sehen ist.

SC_HANDLE WINAPI OpenService(
  _In_  SC_HANDLE hSCManager, // Rückgabe von OpenSCManager
  _In_  LPCTSTR lpServiceName, // Name des Services
  _In_  DWORD dwDesiredAccess  // beispielsweise SC_MANAGER_ALL_ACCESS für alle Rechte
);

Der Rückgabewert ist das Service-Handle oder NULL, wenn etwas schiefging.

Nähere Details auf der MSDN-Seitehttp://msdn.microsoft.com/en-us/library/windows/desktop/ms684330%28v=vs.85%29.aspx

DeleteService

Mit DeleteService kann der Service aus der Datenbank des Service Control Managers entfernt werden.

DeleteService benötigt als einzigen Parameter das Handle des Service, das durch einen Aufruf von OpenService ermittelt werden kann.

BOOL WINAPI DeleteService(
  _In_  SC_HANDLE hService // Ermittelt durch Aufruf von OpenService
);

Das Löschen eines Dienstes schlägt sich nicht sofort in der Dienstanzeige durch.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms682562%28v=vs.85%29.aspx

CloseServiceHandle

CloseServiceHandle gibt ein Handle an den Service Control Manager zurück. Das kann einmal nach dem Stoppen (ControlService) und Entfernen (DeleteService) eines Services geschehen oder zum Beenden der Zusammenarbeit mit dem Service Control Manager. In allen Fällen führt dieser Aufruf nicht zum Stoppen des Services oder des Managers.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms682028%28v=vs.85%29.aspx

Ein Programm als Service

Die Service-Tabelle besteht aus einem Array von SERVICE_TABLE_ENTRY. In der SERVICE_TABLE_ENTRY wird hinterlegt, welches Programm (lpServiceName) und welche Funktion (lpServiceMain) aufgerufen werden soll.

Die ServiceMain-Funktion hat folgenden Prototyp:

VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )
entspricht also mehr oder weniger einer normalen Main-Funktion.

Der letzte Eintrag des Arrays muss in beiden Feldern NULL enthalten.

Die Funktion StartServiceCtrlDispatcher wird mit der Tabelle als Parameter aufgerufen.

Die Hauptfunktion des Dienstes meldet über die Funktion RegisterServiceCtrlHandler (ServiceName, SvcCtrlHandler) ihre Funktion, die beispielsweise SvcCtrlHandler heißt an. Diese soll die Ereignisse des Dienste-Systems fangen bearbeiten und beantworten.

VOID WINAPI SvcCtrlHandler( DWORD dwCtrl )
{
   switch(dwCtrl) 
   {  
      case SERVICE_CONTROL_STOP: 
         break;
      case SERVICE_CONTROL_PAUSED: 
         break;
      case SERVICE_CONTROL_CONTINUE: 
         break;
      case SERVICE_CONTROL_INTERROGATE: 
         break; 
 
      default: 
         break;
   } 
}
Mit der Funktion SetServiceStatus meldet der Dienst den aktuellen Status an den Dienst-Manager.

Beispiel für ein Service-Programm

Die MSDN von Microsoft stellt ein Programm vor, dass sich selbst als Dienst installiert. Das Programm muss von der lokalen Festplatte aus gestartet werden, richtet sich als Dienst ein und kann dann gestartet und gestoppt werden. Der Dienst bleibt allerdings eingetragen.

http://msdn.microsoft.com/en-us/library/windows/desktop/bb540475%28v=vs.85%29.aspx