Unter einem Dienst versteht man ein Programm, das im Hintergrund ohne Interaktion mit dem Benutzer ausgeführt wird, auch wenn kein Benutzer am PC angemeldet ist. Dieser Workshop verrät Ihnen die Grundlagen, um unter WinNT4/2000/XP einen solchen "Dienst" mit VB6 zu erstellen. Allgemeines Um mit VB einen Dienst zu erstellen, wird von Microsoft das Tool ntsvc.ocx benötigt. Leider gestaltet die Suche auf der Microsoft Webpage nach diesem Tool sehr schwierig, weshalb wir Ihnen diese Arbeit abgenommen haben. Über nachfolgenden Link können Sie sich das Tool inkl. VB-Samplecode downloaden. Nach dem Entpacken in einen Ordner Ihrer Wahl kopieren Sie bitte die OCX-Datei (Ordner SRC\Release) in das System32-Verzeichnis und registrieren die ActiveX-Komponente mit "REGSVR32.EXE ntsvc.ocx". Download: Was ist ein Dienst? In diesem Workshop wollen wir nur das Grundgerüst (die Verpackung) für einen Dienst zeigen, Anwendungsmöglichkeiten gibt es viele; z.B. alle 5 Minuten Mails abholen und auf dem Rechner ablegen, auch wenn Sie nicht angemeldet sind oder vieles mehr. Erstellen des Grundgerüstes: Fangen wir einfach mal an und erstellen ein Projekt, dem wir die Komponente ntsvc hinzufügen (Dialog "Projekt - Komponenten"). Wir ziehen die Komponente auf die Form und nennen sie NTService1. Da unser Dienst im Hintergrund laufen soll und keine Form benötigt fügen wir als Erstes folgenden Code hinzu: Option Explicit Private bDoing as Boolean ' Mehr zu dieser Klasse gleich Private cLog as clsLog Private Sub Form_Activate() ' dazu werde ich später etwas sagen On Error Resume Next ' Form nicht anzeigen Me.Hide End Sub Als nächstes ziehen wir ein Timer Control auf die Form und nennen es einfach tmrMain. Unser Timer bekommt noch die Einstellungen "Enabled = False" und "Interval = 60000". (So wichtig ist dieser Dienst nun auch wieder nicht ) Private Sub Form_Load() ' Timer initialisieren tmrMain.Enabled = False tmrMain.Interval = 60000 End Sub Fehlerbehandlung Jetzt müssen wir uns Gedanken über eine Fehlerbehandlung machen. Die beste Lösung ist: Wir machen es mit Klasse . Wir fügen also über Projekt ein neues Klassenmodul hinzu und nennen dieses clsLog. Diese Klasse hat einzig die Aufgabe ein LogFile mitzuführe, so dass man später nachschauen kann, wann was passiert ist. Folgenden Code fügen wir in dieses Klassenmodul ein: Option Explicit ' Dateiname für das LogFile Private m_FileName As String ' Referenz auf das NTService-Control Private m_NTService As Object ' Festlegen des LogFile-Dateinamens Public Property Let sFileName(ByVal sNewFilename As String) On Error Resume Next m_FileName = sNewFilename End Property Public Property Get sFileName() As String sFileName = m_FileName End Property ' Zuweisung des NTService-Controls an die Klasse Public Property Set NTService(oNTService As Object) On Error Resume Next Set m_NTService = oNTService End Property ' Neuen Eintrag in LogFile schreiben Public Sub NewLog(sLogText As String, _ Optional ByVal bWithEventLog As Boolean = True) On Error Resume Next Dim F As Integer F = FreeFile Open m_FileName For Append As #F Print #F, sLogText Close #F If bWithEventLog Then Call m_NTService.LogEvent(svcMessageError, _ svcEventError, sLogText) End If End Sub Warum mit Klasse? -> Weil mir heute einfach so danach ist Wer möchte kann dies auch ohne Klasse machen, es spielt hier keine Rolle, ich finde es einfach praktischer. Schauen wir uns nun mal die Ereignisse der ntsvc.ocx genauer an. Folgende Ereignisse zeigt uns VB, gleich nachdem wir das Control auf die Form gezogen haben, an: Continue Control Pause Start Stop Beispielprojekt Wenn wir nun einen Blick auf das Beispielprojekt werfen, das mit dem Control mitgeliefert wird, finden wir im Form_Load-Teil folgenden Code, den wir in leicht abgeänderter Form in unser Beispielprojekt übernehmen: Private Sub Form_Load() ' Muss in jeder Sub/Function stehen On Error GoTo Err_Load ' Timer initialisieren tmrMain.Interval = 2000 tmrMain.Enabled = False Dim strDisplayName As String Dim bStarted As Boolean ' LogFile-Klasse erstellen Set cLog = New clsLog ' Dateiname für das LogFile festlegen cLog.sFileName = App.Path & "\Log.txt" ' NTService-Objekt zuweisen Set cLog.NTService = NTService1 ' So wird der Dienst unter Dienste bezeichnet strDisplayName = NTService1.DisplayName ' Benutzerinteraktion kann weggelassen werden ' StatusBar.Panels(1).Text = "Loading" If Command = "-install" Then ' Erlauben von Interaktion mit dem Benutzer / ' dem Desktop NTService1.Interactive = True ' Installiert den Dienst If NTService1.Install Then MsgBox strDisplayName & " erfolgreich installiert" Else MsgBox strDisplayName & " konnte nicht " & _ "installiert werden" End If End ElseIf Command = "-uninstall" Then If NTService1.Uninstall Then MsgBox strDisplayName & " erfolgreich deinstalliert" Else MsgBox strDisplayName & " konnte nicht " & _ "deinstalliert werden" End If End ElseIf Command = "-debug" Then NTService1.Debug = True ElseIf Command <> "" Then MsgBox "Invalid command option" End End If ' Erlaubt Pause/Continue. Muss vor StartService ' gesetzt werden NTService1.ControlsAccepted = svcCtrlPauseContinue ' Verbindet diesen Dienst mit dem Windows NT ' Service Controller NTService1.StartService Exit Sub Err_Load: If NTService1.Interactive Then MsgBox "[" & Err.Number & "] " & Err.Description End Else ' eventuelle Fehler ins Eventlog eintragen. cLog.NewLog "[" & Err.Number & "] " & Err.Description End If End Sub Was macht nun diese Funktion? Wird der Dienst vom System beendet kann man dies natürlich ebenfalls mitprotokollieren: Private Sub Form_Unload(Cancel As Integer) ' Service wurde beendet cLog.NewLog "Exit Service" ' Log-Klasse beenden Set cLog = Nothing End Sub Starten, Beenden, Weiterführen, Pause In diesem Ereignis starten wir dann einfach unseren Timer und teilen Windows mit, dass der Dienst erfolgreich gestartet wurde. Das schaut dann in etwa so aus: Private Sub NTService1_Start(Success As Boolean) ' wieder die Fehlerbehandlung On Error GoTo Err_Start ' Starten des Timers, der nun in regelmäßigen ' Abständen eine Aktion auslöst tmrMain.Enabled = True ' Mitteilen, dass alles erfolgreich war. Success = True ' und protokollieren cLog.NewLog "Service started" Exit Sub Err_Start: ' eventuelle Fehler ins Eventlog eintragen. cLog.NewLog "[" & Err.Number & "] " & Err.Description End Sub Jetzt wo der Dienst gestartet werden kann wollen wir doch auch, dass wir ihn wieder beenden können: Private Sub NTService1_Stop() ' Wird ausgelöst, wenn der Stop-Button in der ' Dienstekontrolle angeklickt wird oder Windows ' heruntergefahren wird On Error GoTo Err_Stop ' Timer deaktivieren tmrMain.Enabled = False ' nun warten bis eventuelle tmrEreignisse beendet ' werden hier Do While bDoing ' siehe hierzu das tmrMain Event DoEvents Loop ' und wieder protokollieren cLog.NewLog "Service stopped" ' Alles beenden Unload Me Exit Sub Err_Stop: ' eventuelle Fehler ins Eventlog eintragen. cLog.NewLog "[" & Err.Number & "] " & Err.Description End Sub Nun fehlen noch die Continue- und Pause-Ereignisse: Private Sub NTService1_Continue(Success As Boolean) ' wieder die Fehlerbehandlung On Error GoTo Err_Continue ' Timer wieder aktivieren tmrMain.Enabled = True Success = True ' und wieder protokollieren cLog.NewLog "Service continued" Exit Sub Err_Continue: ' eventuelle Fehler ins Eventlog eintragen. cLog.NewLog "[" & Err.Number & "] " & Err.Description End Sub Private Sub NTService1_Pause(Success As Boolean) ' wieder die Fehlerbehandlung On Error GoTo Err_Pause ' Timer deaktivieren tmrMain.Enabled = False ' siehe hierzu das tmrMain Event Do While bDoing DoEvents Loop Success = True ' und wieder protokollieren cLog.NewLog "Service paused" Exit Sub Err_Pause: ' eventuelle Fehler ins Eventlog eintragen. cLog.NewLog "[" & Err.Number & "] " & Err.Description End Sub Das Timer-Event Die eigentliche Aktion, die der Dienst in bestimmten Zeitabständen verrichten soll, wird über den Timer gesteuert: Private Sub tmrMain_Timer() ' wie immer: Fehlerbehandlung aktivieren On Error GoTo tmrMain_Err ' Wichtig! Diese Variable True setzen, solange ' die Aktion andauert bDoing = True DoEvents ' #### ' Hier die Aktion ausführen bzw. Aktions-Prozedur ' aufrufen ' ' Am besten im LogFile protokollieren cLog.NewLog "Aktion", False ' Aktion beenden... also bDoing = False setzen bDoing = False DoEvents Exit Sub tmrMain_Err: ' eventuelle Fehler ins Eventlog eintragen. cLog.NewLog "[" & Err.Number & "] " & Err.Description ' Nie vergessen, diese Variable auf False zu setzen!! bDoing = False DoEvents End Sub Nun können wir das kleine Beispielprojekt mal starten. Aber staun: Es tut sich nichts - aber auch gar nichts! Korrekt. Wir haben nämlich vergessen, als Startparameter -debug anzugeben. Beenden Sie das laufende Projekt und öffnen Sie die Projekt-Eigenschaftenseite (Menü Projekt - Eigenschaften von...). Klicken Sie auf das Register "Erstellen" und tragen in der Zeile für die Befehlszeilenargumente -debug ein. Anschließend starten Sie das Projekt noch einmal - und diesmal sollte sich auch etwas tun. Zwar nicht sichtbar... aber wenn Sie sich das LogFile mal anschauen, sollten sich dort folgende Einträge befinden: Service started Aktion Aktion AktionAllerdings müssen Sie ein wenig warten, denn den Timer haben wir ja auf 60 Sekunden festgelegt. Zusammenfassung Ein Dienst ist also ein ganz normales Programm, das nicht von einem Benutzer sondern vom Betriebssystem selbst gestartet wird, ohne dass ein Benutzer angemeldet sein muss. Die Aktionen des Benutzers wie Programm starten, stoppen, pausieren und fortführen werden durch neue Ereignisse gesteuert, die das Control netterweise gleich mitliefert. Jeder Fehler MUSS!! abgefangen werden, denn es gibt keinen Benutzer der die MsgBox mit einer etwaigen Fehlermeldung anklicken kann. Anstelle einer MsgBox leiten wir den Fehler an das Eventlog von Windows weiter. Anstelle von Click, DoubleClick, ... Ereignissen (es gibt ja keine wird der Ablauf des Programms nun von Timer-Ereignissen gesteuert. Die Form lassen wir ganz schnell wieder verschwinden, denn die muss nun wirklich nicht angezeigt werden (wer will die denn auch betrachten *g* ). Kommen wir nun zum Timer selbst: Er hat in diesem Programm eine ganz besondere Stelle. Wir müssen drei ganz wichtige Dinge beachten:
Damit dies alles nicht auftritt brauchen wir folgende Hilfskonstruktionen: Zu 1.) Private Sub tmrMain_Timer() ' wie immer: Fehlerbehandlung aktivieren On Error GoTo tmrMain_Err ' Wichtig! Diese Variable True setzen, solange ' die Aktion andauert bDoing = True DoEvents ' #### ' Hier die Aktion ausführen bzw. Aktions-Prozedur ' aufrufen ' ' Am besten im LogFile protokollieren cLog.NewLog "Aktion", False ' Aktion beenden... also bDoing = False setzen bDoing = False DoEvents Exit Sub tmrMain_Err: ' eventuelle Fehler ins Eventlog eintragen. cLog.NewLog "[" & Err.Number & "] " & Err.Description ' Nie vergessen, diese Variable auf False zu setzen!! bDoing = False DoEvents End Sub Zu 2.) Zu 3.) In die eigentliche Ereignisverarbeitung gehört nun auch ein LogFile, damit ein Benutzer die Arbeit des Programms eventuell überprüfen kann. In das EventLog würde ich das nicht hineinschreiben, da sonst dieses Log schnell überfüllt sein könnte und auf Grund des beschränkten Platzes vorhergehende Einträge (auch von anderen Programmen) nicht mehr vorhanden sind. Erläuterung der CommandLine-Parameter Soll der Dienst im System installiert werden, wird die EXE-Datei mit dem Parameter -install aufgerufen. Öffnen Sie anschließend den Dialog Dienste unter Systemsteuerung - Verwaltung, so sollte das kleine Beispielprogramm dort in der Liste eingetragen sein - und zwar unter der Bezeichnung Simple Service. Um den Dienst nun zu starten klicken Sie mit der rechten Maustaste auf den Eintrag und wählen Starten. Sie können auch einstellen, dass dieser Dienst autom. mit jeder Windows-Sitzung gestartet werden soll. Hierzu das Eigenschaften-Fenster öffnen und als Starttyp "automatisch" festlegen. Nachdem der Dienst gestartet wurde können Sie sich ruhig einmal das LogFile anschauen. Hier wird jetzt alles protokolliert, d.h. jeder Start, jede Aktion, jede Pause etc. Testen Sie das ganze ruhig einmal aus, indem Sie den Dienst über die Systemsteuerung manuell "anhalten", ""fortsetzen", "stoppen" oder auch "neu starten". Um den Dienst im System zu deaktivieren, muss die EXE-Datei mit dem Parameter -uninstall aufgerufen werden. Und wenn Sie den Dienst in der VB-IDE testen wollen, einfach mit dem Parameter -debug starten. Wird der Dienst über einen anderen als den drei hier beschriebenen Parametern gestartet, wird eine MsgBox angezeigt und der Dienst sofort wieder beendet. Kommen wir nun zu unserem letztem Punkt: den "Alarmglocken". Es gibt auf dem Markt viele Programme, die einen Server usw. auf Funktion überwachen. Damit dies funktioniert, braucht unser Programm ein Winsock-Control. Ja richtig gelesen, wir brauchen eine Winsock. Das Prinzip dahinter ist einfach. Wir legen ein Winsock auf die Form und sobald der Dienst gestartet wurde machen wir einfach einen Port auf (Listen). Nun kommt das Überwachungsprogramm und verbindet sich mit diesem Port. Wenn wir nun einen Fehler feststellen, anhalten oder beenden, schließen wir die Connection oder beenden das Listen. Das Überwachungsprogramm weiß nun, dass etwas faul ist und kann nach Hilfe "MsgBoxen" (Schönes Wort oder ? Nun ist es aber so, dass das Programm nicht immer mit uns verbunden ist, nein, nur sporadisch verbindet es sich und trennt die Verbindung wieder. Wir müssen also unser Winsock so programmieren, dass es automatisch wieder auf Listen geht. Dies soll hier aber nur ein kleiner Tipp sein. Denn das ist echt ein ganz eigenes Thema an dem ich lange gebastelt habe. Bei Fragen zu diesem Workshop können Sie sich gerne an unser Diskussionsforum im vb@rchiv wenden. Weitere Infos erhalten Sie auch auf der Microsoft Homepage unter: Dieser Workshop wurde bereits 58.537 mal aufgerufen.
Anzeige
Diesen und auch alle anderen Workshops finden Sie auch auf unserer aktuellen vb@rchiv Vol.6 Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv! - nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten - Symbol-Galerie mit mehr als 3.200 Icons im modernen Look Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m. |
sevISDN 1.0 Überwachung aller eingehender Anrufe! Die DLL erkennt alle über die CAPI-Schnittstelle eingehenden Anrufe und teilt Ihnen sogar mit, aus welchem Ortsbereich der Anruf stammt. Weitere Highlights: Online-Rufident, Erkennung der Anrufbehandlung u.v.m. Tipp des Monats Oktober 2024 Heinz Prelle Firewall-Status unter WinXP/Vista prüfen Das Beispiel prüft, ob die Firewall unter Windows XP/Vista eingeschaltet ist oder nicht. Zudem wird eine Abfrage durchgeführt ob es sich bei dem zugrundeliegenden Betriebssystem um Windows XP/Vista handelt oder nicht. TOP! Unser Nr. 1 Neu! sevDataGrid 3.0 Mehrspaltige Listen, mit oder ohne DB-Anbindung. Autom. Sortierung, Editieren von Spalteninhalten oder das interaktive Hinzufügen von Datenzeilen sind ebenso möglich wie das Erstellen eines Web-Reports. |
|||||||||||||
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein. |