TService und Timer
-
Hallo,
da ich ein Timergesteuertes Kopierprogramm, welches in bestimmten Zeitabständen Dateien von einen Verzeichnis in das andere kopiert, geschrieben habe, wollte ich nun das ganze als Dienst im Hintergrund laufen lassen. Bei der Installation des Dienstes werden jedoch nur folgende Ereignisse ausgelöst ->/*1. OnCreate,
2. BeforeInstall,
3. AfterInstall,
4. Meldung Service installiert,
5. OnDestroy */Das Ereignis OnStart wo man eigentlich den Timer initialisieren sollte bleibt aus,
ebenso das Ereignis OnExecute, wo später dann die Kopierroutine rein sollte...Zuerst dachte ich, wenn schon die 5 Ereignisse so aufgerufen werden, müßte auch OnStart etc. folgen, aus mir unerfindlichen Gründen wird mit OnDestroy der Dienst beendet
Zunächst der Quelltext von WinMain, der von Turbo C++ -> Projektvorlage -> Service-Anwendung generiert wurde.
#include <SysUtils.hpp> #include <SvcMgr.hpp> #pragma hdrstop #define Application Svcmgr::Application USEFORM("Autocopy.cpp", AutoBackup); /* TService: File Type */ //--------------------------------------------------------------------------- WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { try { // Für Windows 2003 Server muss StartServiceCtrlDispatcher // CoRegisterClassObject aufgerufen werden, das von Application->Initialize // indirekt aufgerufen werden kann. TServiceApplication->DelayInitialize ermöglicht, // dass Application->Initialize von TService->Main aufgerufen werden kann // (nachdem StartServiceCtrlDispatcher aufgerufen wurde). // // Eine verzögerte Initialisierung des Application-Objekts könnte sich auf // Ereignisse auswirken, die dann vor der Initialisierung auftreten, wie z.B. // TService->OnCreate. Dies wird nur empfohlen, wenn ServiceApplication // ein Klassenobjekt bei OLE registriert und sollte nur in Verbindung mit // Windows 2003 Server verwendet werden. // // Application->DelayInitialize = true; // if ((!Application->DelayInitialize) || (Application->Installing())) { Application->Initialize(); } Application->CreateForm(__classid(TAutoBackup), &AutoBackup); Application->Run(); } catch (Exception &exception) { Sysutils::ShowException(&exception, System::ExceptAddr()); } catch(...) { try { throw Exception(""); } catch(Exception &exception) { Sysutils::ShowException(&exception, System::ExceptAddr()); } } return 0; }
Hier der Quelltext von der Headerdatei, wo die Prototypen der Ereignisprozeduren sind.
//--------------------------------------------------------------------------- #ifndef AutocopyH #define AutocopyH #define ID_TIMER 1 //--------------------------------------------------------------------------- #include <SysUtils.hpp> #include <Classes.hpp> #include <SvcMgr.hpp> #include <vcl.h> //--------------------------------------------------------------------------- class TAutoBackup : public TService { __published: // Von der IDE verwaltete Komponenten void __fastcall AfterInstall(TService *Sender); void __fastcall AfterUninstall(TService *Sender); void __fastcall BeforeInstall(TService *Sender); void __fastcall BeforeUninstall(TService *Sender); void __fastcall OnContinue(TService *Sender, bool &Continued); void __fastcall OnCreate(TObject *Sender); void __fastcall ServiceDestroy(TObject *Sender); void __fastcall ServiceExecute(TService *Sender); void __fastcall ServicePause(TService *Sender, bool &Paused); void __fastcall ServiceShutdown(TService *Sender); void __fastcall ServiceStart(TService *Sender, bool &Started); void __fastcall ServiceStop(TService *Sender, bool &Stopped); private: // Anwender-Deklarationen public: // Anwender-Deklarationen __fastcall TAutoBackup(TComponent* Owner); TServiceController __fastcall GetServiceController(void); friend void __stdcall ServiceController(unsigned CtrlCode); }; //--------------------------------------------------------------------------- extern PACKAGE TAutoBackup *AutoBackup; //--------------------------------------------------------------------------- #endif
Letztendlich die Quelldatei, wo die Ereignisse behandelt werden
//--------------------------------------------------------------------------- #include "Autocopy.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TAutoBackup *AutoBackup; //--------------------------------------------------------------------------- __fastcall TAutoBackup::TAutoBackup(TComponent* Owner) : TService(Owner) { // MessageBox (NULL, "Caller", "Test", MB_ICONERROR); // Ruft nur OnCreate auf } TServiceController __fastcall TAutoBackup::GetServiceController(void) { return (TServiceController) ServiceController; } void __stdcall ServiceController(unsigned CtrlCode) { AutoBackup->Controller(CtrlCode); } //--------------------------------------------------------------------------- void __fastcall TAutoBackup::AfterInstall(TService *Sender) { MessageBox (NULL, "AfterInstall", "Test", MB_ICONERROR); } //--------------------------------------------------------------------------- void __fastcall TAutoBackup::AfterUninstall(TService *Sender) { MessageBox (NULL, "AfterUninstall", "Test", MB_ICONERROR); } //--------------------------------------------------------------------------- void __fastcall TAutoBackup::BeforeInstall(TService *Sender) { MessageBox (NULL, "BeforeInstall", "Test", MB_ICONERROR); } //--------------------------------------------------------------------------- void __fastcall TAutoBackup::BeforeUninstall(TService *Sender) { MessageBox (NULL, "BeforeUninstall", "Test", MB_ICONERROR); } //--------------------------------------------------------------------------- void __fastcall TAutoBackup::OnContinue(TService *Sender, bool &Continued) { MessageBox (NULL, "OnContinue", "Test", MB_ICONERROR); } //--------------------------------------------------------------------------- void __fastcall TAutoBackup::OnCreate(TObject *Sender) { MSG msg; SetTimer (NULL, ID_TIMER, 20000, NULL); /* while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); if (msg.message==WM_TIMER) { MessageBox (NULL, "OnCreate_Timer", "Test", MB_ICONERROR); // Hier kommt später die Kopiersequenz hin } if (msg.message==WM_DESTROY) { KillTimer (NULL, ID_TIMER); PostQuitMessage (0); } } */ MessageBox (NULL, "OnCreate", "Test", MB_ICONERROR); } //--------------------------------------------------------------------------- void __fastcall TAutoBackup::ServiceDestroy(TObject *Sender) { MessageBox (NULL, "OnDestroy", "Test", MB_ICONERROR); } //--------------------------------------------------------------------------- void __fastcall TAutoBackup::ServiceExecute(TService *Sender) { MessageBox (NULL, "OnExecute", "Test", MB_ICONERROR); } //--------------------------------------------------------------------------- void __fastcall TAutoBackup::ServicePause(TService *Sender, bool &Paused) { MessageBox (NULL, "OnPause", "Test", MB_ICONERROR); } //--------------------------------------------------------------------------- void __fastcall TAutoBackup::ServiceShutdown(TService *Sender) { MessageBox (NULL, "OnShutdown", "Test", MB_ICONERROR); } //--------------------------------------------------------------------------- void __fastcall TAutoBackup::ServiceStart(TService *Sender, bool &Started) { SetTimer (NULL, ID_TIMER, 15000, NULL); MessageBox (NULL, "OnStart", "Test", MB_ICONERROR); } //--------------------------------------------------------------------------- void __fastcall TAutoBackup::ServiceStop(TService *Sender, bool &Stopped) { MessageBox (NULL, "OnStop", "Test", MB_ICONERROR); } //--------------------------------------------------------------------------- /*1. OnCreate, 2. BeforeInstall, 3. AfterInstall, 4. Meldung Service installiert, 5. OnDestroy */
Mit der Schleife in OnCreate hat es eigentlich schon geklappt
while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); if (msg.message==WM_TIMER) { MessageBox (NULL, "OnCreate_Timer", "Test", MB_ICONERROR); // Hier kommt später die Kopiersequenz hin } if (msg.message==WM_DESTROY) { KillTimer (NULL, ID_TIMER); PostQuitMessage (0); } }
jedoch läßt sich der Dienst dann nur über den Taskmanager beenden und erst nach der Auskommentierung der Schleife deinstallieren, da die Schleife in dem Fall eine Endlosschleife ist.
Nun die Frage, wie bekomm ich TService dazu ein OnStart Event auszulösen und OnExecute?
-
Die Ereignisse OnStart und Co. werden beim Starten und anderen Aktionen automatisch ausgeführt. Dienste haben normalerweise kein graphisches Interface deshalb schlagen solche Aktionen wie MessageBox fehl. Genauer gesagt, wird das Fenster im Kontext des Nutzers System "angezeigt" und wartet dort auf eine Eingabe. Diese wird niemals erfolgen, deshalb bleibt der Dienst stehen.
OnExecute ist für deine Anwendung nicht unbedingt optimal. Ich würde in OnStart einen Thread erzeugen und in OnStop den Thread beenden.