Recent

Author Topic: Detecting user logon and logoff in a Windows service (Lazarus daemon)  (Read 10227 times)

PascalDragon

  • Hero Member
  • *****
  • Posts: 5486
  • Compiler Developer
Re: Detecting user logon and logoff in a Windows service (Lazarus daemon)
« Reply #30 on: August 18, 2020, 09:43:27 am »
I tried again after commenting out the specified bit of daemonapp.inc and got the following. I assume the notes and warnings are not critical.

Yes, that should be fine.

There is a lot of conflicting info online about how to rebuild Lazarus but doing it from the Tools menu within the IDE seemed to work.

If one has a working IDE then using the item in the Tools menu is indeed the way to go. Though I've now tested this myself and it might be that you also need to open the LazDaemon package and do an explicit compile there (using the Compile button) and afterwards another build of the IDE.

I got stuck again when going back to this instruction:
Quote
...you need to go to your daemon's definition in the Daemon Mapper and inside winbindings.AcceptedCodes enable wccSessionChange.
I started a new project and selected Service as the project type but, even after manually loading DaemonMapperUnit1 in the Project Inspector, "Find in files" couldn't find any reference to winbindings.AcceptedCodes. Do I need to edit Lazarus' source code again rather than the code it generates for my service?

I did it as follows:
  • start a new service application
  • go to the already opened DaemonMapperUnit1 (you can save it with a different name, of course ;) )
  • press F12 to go to the form/data module designer.
  • open the DaemonDefs collection and add a new item
  • set DaemonClassName to the name of your daemon class in (by default) DaemonUnit1
  • open the WinBindings entry: there should be a AcceptedCodes at the top[/tt]
  • enable wccSessionChange
  • inside your daemon set an event handler for OnControlCodeEvent

TyneBridges

  • Full Member
  • ***
  • Posts: 150
    • Personal blog
Re: Detecting user logon and logoff in a Windows service (Lazarus daemon)
« Reply #31 on: August 18, 2020, 05:03:32 pm »
I did it as follows:
  • start a new service application
  • go to the already opened DaemonMapperUnit1 (you can save it with a different name, of course ;) )
  • press F12 to go to the form/data module designer.
  • open the DaemonDefs collection and add a new item
  • set DaemonClassName to the name of your daemon class in (by default) DaemonUnit1
  • open the WinBindings entry: there should be a AcceptedCodes at the top[/tt]
  • enable wccSessionChange
  • inside your daemon set an event handler for OnControlCodeEvent

Thanks for your help. I was able to follow most of that and have enabled wccSessionChange. Now for the difficult bit - incorporating and adapting your example of DataModuleControlCodeEvent. As my understanding of classes and objects is rudimentary, I need to get my head around the significance of the term "data module" and the naming of the daemon class (is it arbitrary or is it referenced manually elsewhere?).
John H, north east England
Lover of the old Delphi, still inexperienced with FPC/Lazarus and not an instinctive programmer

PascalDragon

  • Hero Member
  • *****
  • Posts: 5486
  • Compiler Developer
Re: Detecting user logon and logoff in a Windows service (Lazarus daemon)
« Reply #32 on: August 19, 2020, 10:29:32 am »
Thanks for your help. I was able to follow most of that and have enabled wccSessionChange. Now for the difficult bit - incorporating and adapting your example of DataModuleControlCodeEvent. As my understanding of classes and objects is rudimentary, I need to get my head around the significance of the term "data module" and the naming of the daemon class (is it arbitrary or is it referenced manually elsewhere?).

This will be a longer explanation, bear with me:

A data module is similar to a visual form with the restriction that only non-visual components can be placed there (e.g. database connections, timers, etc.). Like forms they have a LFM file from which the settings you made in the “form designer” (or in this case “data module designer”) are loaded. This includes settings like the WinBindings.AcceptedCodes or which events are mapped to which methods.

Events are in essence properties that are method variables. Simple example is the predefined TNotifyEvent:

Code: Pascal  [Select][+][-]
  1. TNotifyEvent = procedure(aSender: TObject) of object;

An event is usually declared like this:

Code: Pascal  [Select][+][-]
  1. type
  2.   TSomeClass = class
  3.   private
  4.     fOnWhatever: TNotifyEvent;
  5.   public
  6.     property OnWhatever: TNotifyEvent read fOnWhatever write fOnWhatever;
  7.   end;

By default this are set to Nil, thus code usually checks whether they are set before calling them. If the event is triggered in more places then it's usually done using a helper method:

Code: Pascal  [Select][+][-]
  1. procedure TTestClass.DoWhatever;
  2. begin
  3.   if Assigned(fOnWhatever) then
  4.     fOnWhatever(Self); // Self is usually used as aSender parameter
  5. end;

Now the OnControlCodeEvent event has the type TCustomControlCodeEvEvent which has the following signature:

Code: Pascal  [Select][+][-]
  1. TCustomControlCodeEvEvent = Procedure(Sender : TCustomDaemon; ACode, AEventType : DWord; AEventData : Pointer; Var Handled : Boolean) of object;

The dropdown of a event handler in the object inspector will display all published methods of a class that have a matching signature. Published methods are those that are declared in a published section or that are declared at the top without any visibility specifier (private, public, etc.) if the class has type information enabled (which is the case for everything that derives from TPersistent which is the case for both TForm and TDataModule (and thus TDaemon)).
If you simply double click an event handler in the object inspector the IDE will create a suitable name for the event handler together with the matching signature. Due to the inheritance and some internal magics of the IDE the name in this case will be DataModuleControlCodeEvent (though DaemonControlCodeEvent would be more correct, I'll have to check when I find the time if I can improve this :-X ).
You are free to rename this method, but you'll have to adjust the event in the object inspector as well afterwards (the IDE will warn about dangling reference if you save the unit or data module).
Due to the streaming system with the LFM files the RTL will automatically assign your event handler (in this case DataModuleControlCodeEvent or whatever you'll name it) to the OnControlCodeEvent event as if you had written code like this:

Code: Pascal  [Select][+][-]
  1. constructor TDaemon1.Create(AOwner: TComponent);
  2. begin
  3.   inherited Create(AOwner);
  4.   OnControlCodeEvent := @DataModuleControlCodeEvent;
  5. end;

This is perfectly valid and can be used if forms, etc. are created at runtime.

I hope this helps you further, if not feel free to ask back. :)

TyneBridges

  • Full Member
  • ***
  • Posts: 150
    • Personal blog
Re: Detecting user logon and logoff in a Windows service (Lazarus daemon)
« Reply #33 on: August 19, 2020, 04:19:35 pm »
Thanks for the explanation. I kicked myself for having tried to enter your example code in the wrong unit (the Daemon Mapper). I removed the code from there, put it in DataModuleControlEvent in TDaemon1 where it belonged and changed the DaemonClassName to TDaemon1. The service was then able to compile.

However, I'm now starting to run out of hope. When I attempted to install it, Windows gave me the frustratingly useless error message:

Code: Text  [Select][+][-]
  1. C:\Users\JH\Documents\FPProjects\Booking Service\>bc2 -i
  2. Exception at 000000010003D9FE: EOSError:
  3. System error, (OS Code 123):
  4. The filename, directory name, or volume label syntax is incorrect.
  5.  

As all the debugger will give me is "Execution stopped" and some assembly language (not even an error breakpoint), I think I'm back to square one.

I tried again with a new "bare bones" service with nothing else in it except the example code and a few lines to save output to a text file: again I got the same error on installation. I've attached the test project. (Oddly, this compiled to a much larger executable than my other service giving the same error, although that version contained code to attach to an external database etc.)
« Last Edit: August 19, 2020, 04:50:44 pm by TyneBridges »
John H, north east England
Lover of the old Delphi, still inexperienced with FPC/Lazarus and not an instinctive programmer

PascalDragon

  • Hero Member
  • *****
  • Posts: 5486
  • Compiler Developer
Re: Detecting user logon and logoff in a Windows service (Lazarus daemon)
« Reply #34 on: August 20, 2020, 09:39:00 am »
However, I'm now starting to run out of hope. When I attempted to install it, Windows gave me the frustratingly useless error message:

You also need to set the Name property in your DaemonDef in the mapper (next to WinBindings).

Note to self: Might be a good idea to catch that internally before calling CreateService so that users aren't confused...

TyneBridges

  • Full Member
  • ***
  • Posts: 150
    • Personal blog
Re: Detecting user logon and logoff in a Windows service (Lazarus daemon)
« Reply #35 on: August 21, 2020, 03:36:22 pm »
However, I'm now starting to run out of hope. When I attempted to install it, Windows gave me the frustratingly useless error message:

You also need to set the Name property in your DaemonDef in the mapper (next to WinBindings).

Note to self: Might be a good idea to catch that internally before calling CreateService so that users aren't confused...

Thanks! It's working at last. I'm grateful for your help.

Of course, detecting a logon isn't the whole story of what I need to do in the service, so I'll start a new post for my next query.
John H, north east England
Lover of the old Delphi, still inexperienced with FPC/Lazarus and not an instinctive programmer

PascalDragon

  • Hero Member
  • *****
  • Posts: 5486
  • Compiler Developer
Re: Detecting user logon and logoff in a Windows service (Lazarus daemon)
« Reply #36 on: August 21, 2020, 05:43:32 pm »
Thanks! It's working at last. I'm grateful for your help.

Good to know that you have it working now. :)

 

TinyPortal © 2005-2018