Service Applications
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:
- 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.
- A Service window appears that corresponds to a service (TService). Implement the service by setting its properties and event handlers in the Object Inspector.
- 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.
- 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:
- Choose File > New > Other and select Service Application from the New Items dialog box. The Service1 window appears.
- From the Internet category of the Tool palette, add a ServerSocket component to the service window (Service1).
- 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
- 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); } }
- 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.