Forum > Windows
Getting started with a service (LazDaemon)
TyneBridges:
I've created a number of working programs with Borland Delphi 1, 2 and 5 (and still use Delphi at work) so am familiar with most of the basic conventions. However, I'm mystified when it comes to service apps. I've had a stab at a service that should simply write numbers to a text file using an fptimer, but I'm frustrated to find that I can't test it.
From http://wiki.freepascal.org/Daemons_and_Services:
When the daemon is started the command line parameters are parsed. The following are predefined:
-i --install: register the daemon. This has no effect under unix.
-u --uninstall: unregister the daemon. This has no effect under unix.
-r --run: start the daemon. Windows does this normally itself.
This implies that all I need to do after compiling my program is to type <programname> -i - in my case, bdaemon - i. I compiled it successfully, opened the folder and could see bdaemon.exe there. I right-clicked Windows Command Processor on my menu and selected "Run as administrator" and typed bdaemon -i. No error: good.
I realise that this won't start the service, and that I need to do this manually, or by restarting Windows. However, when I go into Computer | Manage | Services and Applications | Services, surely I should then see bdaemon (or Bdaemon) in the alphabetical list? It's not there and I have no idea why. Down at the first hurdle...
I can't find an example of how to use Lazdaemon with a step-by-step description of the requirements for Windows services. The Wiki is "bare bones" to say the least, and lumps Windows together with Unix. I'm completely unable to translate the following into what I need to do in my code.
TDaemonMapper
This component handles the service registration. Each instance needs one entry in the property DaemonDefs.
My project does contain the following standard code, added automatically by Lazarus:
--- Code: ---type
TDaemonMapper1 = class(TDaemonMapper)
private
{ private declarations }
public
{ public declarations }
end;
var
DaemonMapper1: TDaemonMapper1;
implementation
procedure RegisterMapper;
begin
RegisterDaemonMapper(TDaemonMapper1)
end;
{$R *.lfm}
initialization
RegisterMapper;
end.
--- End code ---
I'm fairly sure I've missed a property but have no idea what to add, or where. I would be grateful if anyone is able to tell me what I've done wrong, or point me to an example of how to use LazDaemon with Windows.
BigChimp:
FYI, for easier reading, use the # button in the editor bar to mark your code. This allows copy/pasting as well as formatting.
Have no experience with writing services with fpc, sorry, so no advice there.
TyneBridges:
Thanks for the hint, BigChimp. I found the following article which looked useful
http://www.turbog.com/wp-content/uploads/2012/04/daemons.pdf
...unfortunately this concentrates on FreePascal alone rather than Lazarus. Most of the code for the visual version is missing and I can't fill in the gaps. I've discovered DaemonMapper1 in the Lazarus default application via the Object Inspector. I changed DaemonDefs from 0 items to 1 item and allowed Lazarus to fill in the default name DaemonMapper1 (I haven't changed any of the other component or object default names). This does compile and now, when I issue the command bdaemon -i the result is
--- Code: ---exception at 0040FCFF:
Unknown daemon class name: .
--- End code ---
Hopefully someone has an example somewhere with Lazarus code, or can give me some hints on what I've missed. Translating the description of the mapper in the article above into Pascal code in the right places is beyond my knowledge. Any help would be gratefully received.
TyneBridges:
Following the create example for FP in the article, I've tried adding the following in mapunit and still get the error "Unknown daemon class name: ." when I try to install. For some reason, my daemon class name is not being picked up (incidentally, I tried D.DaemonClassName both with and without the initial T, recompiling after each edit).
--- Code: ---procedure TDaemonMapper1.DaemonMapper1Create(Sender: TObject);
Var D: TDaemonDef;
begin
D:= DaemonDefs.Add as TDaemonDef;
D.DisplayName:= 'Booking Service';
D.Name:= 'BookingService';
D.DaemonClassName:= 'TDaemonMapper1';
D.WinBindings.ServiceType:= stWin32;
end;
--- End code ---
The article began this bit of code with "inherited Create(AOwner)". I tried inserting this but modifying it to inherited Create(Sender); Of course, that doesn't compile as Sender is the wrong object type.
TyneBridges:
I've now removed the code above and, by clicking into things I didn't even realise had click options, have managed to edit the properties for TDaemonMapper1 in the Object Inspector. I have 1 item in DaemonDefs called DaemonMapper1. Clicking on the line "1 item" gives me Editing DaemonMapper1.DaemonDefs[0] - evidently a zero-based array. In the Properties list I've added the same properties as in my code quoted, leaving UserName blank, which the help file says will run the service under the System account - as I want.
I've recompiled the service but now, typing bdaemon -i at the Windows command prompt from the folder with the .exe file in it gives me
--- Code: ---exception at 0040FCFF:
Unknown daemon class name: TDaemonMapper1.
--- End code ---
Evidently something is still missing, but what?
Navigation
[0] Message Index
[#] Next page