RO as a Windows Service

delphi

(Marcos Cunha Lima) #1

I need to port our RO9 Delphi server to a Windows Service and would like to get some guidance here.

Currently, our project creates all components ( TROIndyHTTPServer, TROBinMessage, etc ) and hooks them up in a class at runtime:

TServerHttp = class
  private
    ...
    FRoServer: TRoIndyHttpServer;
    FRoMessage: TRoBinMessage;

constructor TServerHttp.Create(iniFileName: string);
begin

FRoServer := TRoIndyHttpServer.Create(nil);
FRoMessage := TRoBinMessage.Create(nil);
TROMessageDispatcher(FROServer.Dispatchers.Add).Message := FROMessage;

FRoServerControl := TRoIndyHttpServer.Create(nil);
FRoMessageControl := TRoBinMessage.Create(nil);
TROMessageDispatcher(FROServerControl.Dispatchers.Add).Message := FROMessageControl;

FenvAESEnvelope := TROAESEncryptionEnvelope.Create(nil);
FenvAESEnvelope.EnvelopeMarker := 'AES';

end;

And it works well starting as a normal executable file in Windows.
After doing some research ( didn’t find anything in the documentation but created an example using IDE > Create new project > Other > Windows Service (CodeFirst) ) , I noticed that the only thing different from our project is that it creates all components wrapped in a class inherited by TService (defined in the unit Vcl.SvcMgr), hooks some properties and that’s it. Is that correct?

Should I have to install it using nameexe /install after that? Or should I have to go to any other direction in order to port to Windows Service?


(EvgenyK) #2

Hi,

yes, you can use your TServerHttp class and handle TService1.Service* methods.

yes, you are correct.
note: this operation requires administrative rights


(Marcos Cunha Lima) #3

Hi struggling a little bit (Named Pipes sample works but mine not…) but I am keep trying to search for things that are different between both.
A small question: is there a way in the project file to know if the project is in “install mode” (where I would run TService stuff) or in the executable mode (where I run it as a normal server)?


(EvgenyK) #4

you can check std ParamStr/ParamCount


(Marcos Cunha Lima) #5

OK, I will try it out.
Other thing now.
Is there something that I am missing here regarding units used in uses at project file?
When I comment out (like below) some units in the project file, I can install the exe without problems.

program ServidorNFe;

uses
  SimpleShareMem,
  Vcl.SvcMgr,
  //Forms,
  uROComInit,
  //Windows,

The problem is that I need those units in order to compile/run the EXE as usual (without installing it as a service) because, as an EXE, it has a small form - like the form RO samples. Is there a way to have just one EXE and run it as a service (with clause /install) and as an normal EXE (running without any clauses)?
Moreover, if I just let the units there and try to run it as a service, it won’t install anymore.


(EvgenyK) #6

Try to create your app with Combo Service/Standalone template:

program FileBroadcastServer;

{#ROGEN:FileBroadcastLibrary.rodl} // RemObjects: Careful, do not remove!

uses
  uROComInit,
  uROComboService,
  Forms,
  FileBroadcastServerData in 'FileBroadcastServerData.pas' {FileBroadcastServerDataForm: TDataModule},
  FileBroadcastServerMain in 'FileBroadcastServerMain.pas' {FileBroadcastServerMainForm},
  FileBroadcastLibrary_Intf in 'FileBroadcastLibrary_Intf.pas',
  FileBroadcastLibrary_Invk in 'FileBroadcastLibrary_Invk.pas',
  FileBroadcastService_Impl in 'FileBroadcastService_Impl.pas' {FileBroadcastService: TRORemoteDataModule};

{$R *.res}
{$R RODLFile.res}

begin
  if ROStartService('FileBroadcast', 'FileBroadcast') then begin
    ROService.CreateForm(TFileBroadcastServerDataForm, FileBroadcastServerDataForm);
    ROService.Run;
    Exit;
  end;

  Application.Initialize;
  Application.Title := 'File Broadcast Server';
  Application.CreateForm(TFileBroadcastServerDataForm, FileBroadcastServerDataForm);
  Application.CreateForm(TFileBroadcastServerMainForm, FileBroadcastServerMainForm);
  Application.Run;
end.

(Marcos Cunha Lima) #7

Now it’s initializing OK but I noticed that the combo project doesn’t create an inherited TService dataModule nor it hooks events to start/stop the service. So, my questions:

  1. How this combo service knows how to stop/start the service (using Windows Service Window to stop/start it)?

  2. I didn’t change the TService dataModule implementation yet, just the dproj file to install/uninstall it and run it as a normal Exe. What happens now is that when I execute it as an Exe, it works flawlessly but when I run it as a service and try to run a remote function, it always returns an Exception: Error reading parameter Result: Stream read Error. Do you have any clues of how to solve it?


(Marcos Cunha Lima) #8

I’ve put some logs (as I cannot put breakpoint on the server running as a service) and the log at the first line of the server remote procedure doesn’t get called, eg, the client runs at the line in which it calls the remote server procedure and then it throws an exception when it tries to execute the remote procedure.


(EvgenyK) #9

Hi,

it does it in ROStartService method

can you create a simple testcase, pls?
you can attach it here or drop email to support@


(Marcos Cunha Lima) #10

I did and it worked. So, I will check out the differences from our main project.

Meanwhile, I don’t understand yet how ROStartService knows how to start/stop the service.
What I suppose is that when it receives signal to start (from Windows) it tries to create the datamodule unit which has the server component in it and we need to hook onCreate event to start our server.

If this is correct, I presume that, in order to stop it, it frees the datamodule shutting down the server (as in the sample code it does not have any code to stop server component), is that correct?

So how does it deals with pause/continue signals from Windows?


(EvgenyK) #11

if you pass /standalone parameter, server will be launched as standalone app, otherwise it will be launched as service.
Note: you can’t stop service with cmdline parameters.

yep, when you stop service, it closes app and all resources are freed

TService performs pause/continue as it was implemented in that class.
you can change default behavior and assign these events:

    property OnContinue: TContinueEvent read FOnContinue write SetOnContinue;
    property OnExecute: TServiceEvent read FOnExecute write FOnExecute;

to uROComboService.ROService global variable.


(Marcos Cunha Lima) #12

OK, It’s just to let you know that it is working flawlessly now (it was a problem with our application dependencies).