Service Applications

From RAD Studio
Jump to: navigation, search

Go Up to Creating Applications

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 File > New > Other, 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 File > New > Other, 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. After 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 File > New > Other 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:
     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;
    
    // ---------------------------------------------------------------------------
    #ifndef Unit1H
    #define Unit1H
    // ---------------------------------------------------------------------------
    #include <SysUtils.hpp>
    #include <Classes.hpp>
    #include <SvcMgr.hpp>
    #include <ScktComp.hpp>
    
    // ---------------------------------------------------------------------------
    class TService1 : public TService {
    __published: // IDE-managed Components
    
    	TServerSocket *ServerSocket1;
    
    private: // User declarations
    	TMemoryStream *Stream; // add this line here
    
    public: // User declarations
    
    	__fastcall TService1(TComponent* Owner);
    	PServiceController __fastcall GetServiceController(void);
    	friend void __stdcall ServiceController(unsigned CtrlCode);
    };
    
    // ---------------------------------------------------------------------------
    extern PACKAGE TService1 *Service1;
    // ---------------------------------------------------------------------------
    #endif
    
  4. Select ServerSocket1, the component you added in step 1. In the Object Inspector, double-click the OnClientRead event and add the following event handler:
     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);
    	}
    }
    
  5. 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:
     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;
    	}
    }
    
Note: Service applications are not available for non-Windows applications.

Topics

See Also