Windows Service in einer C++-Klasse
-
Hi,
ich möchte mir ein Programm schreiben, welches als graphische Oberfläche zum Starten und Stoppen von Services genutzt wird. Dieses Programm soll allerdings nicht als SCM-Ersatz dienen und alle eingetragenen Services bearbeiten, sondern ich möchte eine Programm welches drei verschiedene von mir geschriebene Services starten und stoppen kann. Außerdem soll es möglich sein gewisse Einstellungen zu bearbeiten, auf die diese Services zugreifen.
Das ist soweit ja alles erst einmal kein Problem: Ich habe mir ein Benutzeroberfläche geschrieben, welche die einzelnen EXE-Dateien der Services mit gewissen Parametern aufruft. Mein Ziel ist es allerdings die Services und die Benutzeroberfläche in ein Programm zu bekommen. So daß, die Services zwar von der Benutzeroberfläche gestartet werden, aber trotzdem weiterlaufen, auch wenn die Benutzeroberfläche beendet wurde.
Das habe ich jetzt Klassen für jeden Service angelegt. Die WINAPI-Funktionen "ServiceMain" und "ServiceCtrlHandler" sind als static deklariert. Allerdings will der Code trotzdem nicht so ganz wie ich will. Hat jemand von euch eine Idee???
Header-Datei:#ifndef _SERVICE_H_ #define _SERVICE_H_ #include "windows.h" #include "Winsvc.h" class Service { public: Service(); ~Service(); bool StartService(); bool StopService(); void SetLogFile(char* LogFile); private: static void WINAPI _ServiceMain(DWORD argc, LPTSTR* argv); static void WINAPI _ServiceCtrlHandler(DWORD Opcode); SERVICE_STATUS _ServiceStatus; SERVICE_STATUS_HANDLE _ServiceStatusHandle; char* _LogFile; char* _ServiceName; bool _Stop; }; #endifUnd die CPP-Datei:
#include "Service.h" Service* __Service; Service::Service() { __Service = this; _Stop = false; _ServiceName = new char[sizeof("MyService")]; strcpy(_ServiceName, "MyService"); _LogFile = (char*)NULL; } Service::~Service() { if (_LogFile != (char*)NULL) delete _LogFile; } bool Service::Start() { SERVICE_TABLE_ENTRY TableEntry[] = {{_ServiceName, _ServiceMain},{NULL,NULL}}; StartServiceCtrlDispatcher(TableEntry); return true; } bool Service::Stop() { //noch nicht implementiert return true; } void Service::SetLogFile(char* LogFile) { if (_LogFile != (char*)NULL) delete _LogFile; _LogFile = new char[sizeof(LogFile)]; strcpy(_LogFile, LogFile); } void WINAPI Service::_ServiceMain(DWORD argc, LPTSTR* argv) { __Service->_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; __Service->_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; __Service->_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP; __Service->_ServiceStatus.dwWin32ExitCode = NO_ERROR; __Service->_ServiceStatus.dwServiceSpecificExitCode = 0; __Service->_ServiceStatus.dwCheckPoint = 0; __Service->_ServiceStatus.dwWaitHint = 3000; if ((__Service->_ServiceStatusHandle = RegisterServiceCtrlHandler(__Service->_ServiceName, _ServiceCtrlHandler)) == (SERVICE_STATUS_HANDLE)0) { __Service->_ServiceStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(__Service->_ServiceStatusHandle, &__Service->_ServiceStatus); return; } __Service->_ServiceStatus.dwCurrentState = SERVICE_RUNNING; __Service->_ServiceStatus.dwCheckPoint = 1; SetServiceStatus(__Service->_ServiceStatusHandle, &__Service->_ServiceStatus); while (!__Service->_Stop) { Sleep(1000); //nur zum Test folgende Zeile: PlaySound("Error.wav", NULL, SND_ASYNC | SND_FILENAME); } } void WINAPI Service::_ServiceCtrlHandler(DWORD Opcode) { switch (Opcode) { case SERVICE_CONTROL_PAUSE: __Service->_ServiceStatus.dwCurrentState = SERVICE_PAUSED; SetServiceStatus(__Service->_ServiceStatusHandle, &__Service->_ServiceStatus); break; case SERVICE_CONTROL_CONTINUE: __Service->_ServiceStatus.dwCurrentState = SERVICE_RUNNING; SetServiceStatus(__Service->_ServiceStatusHandle, &__Service->_ServiceStatus); break; case SERVICE_CONTROL_STOP: __Service->_ServiceStatus.dwWin32ExitCode = 0; __Service->_ServiceStatus.dwCurrentState = SERVICE_STOPPED; __Service->_ServiceStatus.dwCheckPoint = 0; __Service->_ServiceStatus.dwWaitHint = 0; SetServiceStatus(__Service->_ServiceStatusHandle, &__Service->_ServiceStatus); __Service->_Stop = true; break; case SERVICE_CONTROL_INTERROGATE: break; }; }Wegen des Zeigers "__Service". Dazu gibt es ja einen Eintrag im WINAPI-Faq, wie man Callback-Funktionen in einer Klasse realisiert. In meinem Beispiel, soll es jeden Service ja nur einmal geben. Deshalb dachte ich, daß die Idee mit dem Zeiger auf this vielleicht in meinem Fall ganz günstig ist.
Beim Neustart der Benutzeroberfläche soll dann natürlich auch bekannt sein, daß der Service bereits läuft. Wie ich das mache weiß ich noch nicht. Habe ich aber auch noch nicht nachgeschaut. Da kümmere ich mich drum, wenn ich weiß, wie ich den Service zum laufen bekomme.Danke schon mal.
-
Läuft den der Service an sich, wenn du ihn über den Dienste-Manager startest?
Vielleicht hilft dir das hier: http://www.gamedev.net/reference/articles/article1899.asp