Service-Anwendungen
Nach oben zu Anwendungen erstellen
Service-Anwendungen nehmen Anforderungen von Client-Anwendungen entgegen, verarbeiten sie und geben Information an die Client-Anwendungen zurück. Normalerweise werden sie im Hintergrund ausgeführt, ohne dass der Benutzer viele Eingaben vorzunehmen braucht. Beispiele für Service-Anwendungen sind Web-, FTP- oder E-Mail-Server.
Um eine Anwendung zu erstellen, die einen Win32-Service implementiert, gehen Sie folgendermaßen vor:
- Wählen Sie Datei > Neu > Weitere und doppelklicken Sie im Dialogfeld Objektgalerie auf den Eintrag Service-Anwendung. Dadurch wird Ihrem Projekt die globale Variable Application hinzugefügt, die den Typ TServiceApplication hat.
- Es erscheint ein Fenster, das einem Service (TService) entspricht. Implementieren Sie den Service, indem Sie im Objektinspektor seine Eigenschaften und Ereignisbehandlungen einrichten.
- Sie fügen Ihrer Service-Anwendung zusätzliche Services hinzu, indem Sie Datei > Neu > Weitere wählen und im Dialogfeld Objektgalerie auf den Eintrag Service doppelklicken. Fügen Sie keine Services zu einer Anwendung hinzu, bei der es sich nicht um eine Service-Anwendung handelt. Während zwar ein TService-Objekt hinzugefügt werden kann, erzeugt die Anwendung nicht die erforderlichen Ereignisse, die veranlassen, dass die entsprechenden Windows-Aufrufe für den Service ausgeführt werden.
- Nachdem Sie die Service-Anwendung erstellt haben, installieren Sie Ihre Services mithilfe des Dienstkontroll-Managers. Andere Anwendungen starten Ihre Services, indem sie Anforderungen an den Dienstkontroll-Manager senden.
Um die Services Ihrer Anwendung zu installieren, führen Sie sie unter Verwendung der Option /INSTALL aus. Die Anwendung installiert ihre Services und beendet sich selbst. Falls die Services erfolgreich installiert werden konnten, erscheint eine Bestätigungsmeldung. Sie unterdrücken diese Meldung, indem Sie die Service-Anwendung unter Verwendung der Option /SILENT ausführen.
Um die Services zu deinstallieren, führen Sie sie mithilfe der Option /UNINSTALL von der Befehlszeile aus. (Um die Bestätigungsmeldung nach der Deinstallation zu unterdrücken, verwenden Sie zusätzlich die Option /SILENT.)
Anmerkung: Dieser Service verfügt über ein TServerSocket, dessen Port auf 80 gesetzt ist. Das ist der Standard-Port für Web-Browser, um Anforderungen an Web-Server zu senden, und für Web-Server, um Antworten an Web-Browser zu senden. Das hier gezeigte Beispiel erzeugt ein Textdokument im Verzeichnis C:\Temp, WebLogxxx.log (wobei xxx die Thread-ID darstellt). Jeder Port sollte von jeweils nur einem Server genutzt werden. Wenn Sie also einen Web-Server haben, sollten Sie sicherstellen, dass er diesen Port nicht abfragt (der Service wird unterbrochen).
Um die Ergebnisse anzuzeigen, gehen Sie wie folgt vor: Öffnen Sie einen Web-Browser auf der lokalen Maschine und geben Sie als Adresse localhost ein. Der Browser wird irgendwann einen Timeout erzeugen, aber die Datei weblogxxx.log befindet sich im Verzeichnis C:\temp.
So erstellen Sie das Beispiel:
- Wählen Sie Datei > Neu > Weitere und im Dialogfeld Objektgalerie den Eintrag Service-Anwendung. Ein Fenster mit dem Namen Service1 wird angezeigt.
- Fügen Sie aus der Kategorie Internet der Tool-Palette eine ServerSocket-Komponente in das Service-Fenster (Service1) ein.
- Anschließend fügen Sie der Klasse TService1 ein private-Datenelement des Typs TMemoryStream hinzu. Der interface-Abschnitt Ihrer Unit sollte jetzt wie folgt aussehen:
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs,
ScktComp;
type
TService1 = class(TService)
ServerSocket1: TServerSocket;
procedure ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
procedure Service1Execute(Sender: TService);
private
{ private-Deklarationen }
Stream: TMemoryStream; // fügen Sie diese Zeile hier ein
public
function GetServiceController: PServiceController; override;
{ public-Deklarationen }
end;
var
Service1: TService1;
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <SysUtils.hpp>
#include <Classes.hpp>
#include <SvcMgr.hpp>
#include <ScktComp.hpp>
//---------------------------------------------------------------------------
class TService1 : public TService
{
__published:
TServerSocket *ServerSocket1;
private:
TMemoryStream *Stream; // fügen Sie diese Zeile hier ein
public:
__fastcall TService1(TComponent* Owner);
PServiceController __fastcall GetServiceController(void);
friend void __stdcall ServiceController(unsigned CtrlCode);
};
//---------------------------------------------------------------------------
extern PACKAGE TService1 *Service1;
//---------------------------------------------------------------------------
#endif
- Wählen Sie jetzt die in Schritt 1 hinzugefügte Komponente ServerSocket1 aus. Im Objektinspektor doppelklicken Sie auf das Ereignis OnClientRead und fügen die folgende Ereignisbehandlungsroutine ein:
procedure TService1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
Buffer: PChar;
begin
Buffer := nil;
while Socket.ReceiveLength > 0 do begin
Buffer := AllocMem(Socket.ReceiveLength);
try
Socket.ReceiveBuf(Buffer^, Socket.ReceiveLength);
Stream.Write(Buffer^, StrLen(Buffer));
finally
FreeMem(Buffer);
end;
Stream.Seek(0, soFromBeginning);
Stream.SaveToFile('c:\Temp\Weblog' + IntToStr(ServiceThread.ThreadID) + '.log');
end;
end;
void __fastcall TService1::ServerSocket1ClientRead(TObject *Sender,
TCustomWinSocket *Socket)
{
char *Buffer = NULL;
int len = Socket->ReceiveLength();
while (len > 0)
{
try
{
Buffer = (char *)malloc(len);
Socket->ReceiveBuf((void *)Buffer, len);
Stream->Write(Buffer, len);
}
__finally
{
free(Buffer);
}
Stream->Seek(0, soFromBeginning);
AnsiString LogFile = "C:\\Temp\\WebLog";
LogFile = LogFile + IntToStr(ServiceThread->ThreadID) + ".log";
Stream->SaveToFile(LogFile);
}
}
- Schließlich wählen Sie Service1 aus, indem Sie in den Client-Bereich des Fensters klicken (aber nicht auf die ServerSocket-Komponente). Doppelklicken Sie im Objektinspektor auf das Ereignis OnExecute und fügen Sie die folgende Ereignisbehandlungsroutine ein:
procedure TService1.Service1Execute(Sender: TService);
begin
Stream := TMemoryStream.Create;
try
ServerSocket1.Port := 80; // WWW-Port
ServerSocket1.Active := True;
while not Terminated do begin
ServiceThread.ProcessRequests(True);
end;
ServerSocket1.Active := False;
finally
Stream.Free;
end;
end;
void __fastcall TService1::Service1Execute(TService *Sender)
{
Stream = new TMemoryStream();
try
{
ServerSocket1->Port = 80; // WWW-Port
ServerSocket1->Active = true;
while (!Terminated)
ServiceThread->ProcessRequests(true);
ServerSocket1->Active = false;
}
__finally
{
delete Stream;
}
}
Anmerkung: Dienst-Anwendungen stehen bei plattformübergreifende Anwendungen nicht zur Verfügung.