RAD Studio |  |

Service Applications
See Also
Collapse All

Service applications take requests from client applications, process those requests, and return information to the client applications. They typically run in the background, without much user input. A Web, FTP, or e-mail server is an example of a service application.

To create an application that implements a Win32 service:

1. Choose FileNewOther, and double-click Service Application in the New Items dialog box. This adds a global variable named Application to your project, which is of type TServiceApplication.
2. A Service window appears that corresponds to a service (TService). Implement the service by setting its properties and event handlers in the Object Inspector.
3. You can add additional services to your service application by choosing FileNewOther, and double-click Service in the New Items dialog box. Do not add services to an application that is not a service application. While a TService object can be added, the application will not generate the requisite events or make the appropriate Windows calls on behalf of the service.
4. Once your service application is built, you can install its services with the Service Control Manager (SCM). Other applications can then launch your services by sending requests to the SCM.

To install your application's services, run it using the /INSTALL option. The application installs its services and exits, giving a confirmation message if the services are successfully installed. You can suppress the confirmation message by running the service application using the /SILENT option.

To uninstall the services, run it from the command line using the /UNINSTALL option. (You can also use the /SILENT option to suppress the confirmation message when uninstalling).

Note: This service has a TServerSocket whose port is set to 80. This is the default port for Web browsers to make requests to Web servers and for Web servers to make responses to Web browsers. This particular example produces a text document in the C:\Temp directory called WebLogxxx.log (where xxx is the ThreadID). There should be only one server listening on any given port, so if you have a Web server, you should make sure that it is not listening (the service is stopped).
To see the results: open up a Web browser on the local machine and for the address, type 'localhost' (with no quotes). The browser will time out eventually, but you should now have a file called Weblogxxx.log in the C:\Temp directory.
To create the example:

1. Choose FileNewOther and select Service Application from the New Items dialog box. The Service1 window appears.
2. From the Internet category of the Tool palette, add a ServerSocket component to the service window (Service1).
3. Add a private data member of type TMemoryStream to the TService1 class. The interface section of your unit should now look like this:

Copy Code

    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 declarations }
        Stream: TMemoryStream; // Add this line here
      public
        function GetServiceController: PServiceController; override;
        { Public declarations }
      end;
    var
      Service1: TService1;

Copy Code

    //---------------------------------------------------------------------------
    #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; // add this line here
    public:
    __fastcall TService1(TComponent* Owner);
    PServiceController __fastcall GetServiceController(void);
    friend void __stdcall ServiceController(unsigned CtrlCode);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TService1 *Service1;
    //---------------------------------------------------------------------------
    #endif

1. Select ServerSocket1, the component you added in step 1. In the Object Inspector, double-click the OnClientRead event and add the following event handler:

Copy Code

    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;

Copy Code

    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);
    }
    }

1. Finally, select Service1 by clicking in the window's client area (but not on the ServiceSocket). In the Object Inspector, double click the OnExecute event and add the following event handler:

Copy Code

    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;

Copy Code

    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;
    }
    }

When writing your service application, you should be aware of:

- Service threads
- Service name properties
- Debugging service applications

Note: Service applications are not available for cross-platform applications.
See Also

TServiceApplication

TService

Copyright(C) 2009 Embarcadero Technologies, Inc. All Rights Reserved.
What do you think about this topic? Send feedback!