Detecting user logon and logoff in a Windows service (Lazarus daemon) lazarus / 34-Windows ---------------------------------------------------------------------- TyneBridges · 2020-07-22 14:07 I have a Windows service created in Lazarus that can access a remote MySQL database and read and update records there. The service was not all my own work but was put together years ago with the help of forum members. I'm now looking for a way to detect user logon and logoff by handling SERVICE_CONTROL_SESSIONCHANGE. One piece of advice on line says that this isn't difficult in a service, but only gives code snippets in C++, of which I have very little understanding.  I've found a thread here from 6 years ago which makes it look as if this is difficult and refers to directly hooking into FPC source code. Obviously FPC will have changed a lot since then and I wonder if there's now a simpler way to do this...? I'd be grateful for any hints or code snippets (with advice as to where they should go in the service). ---------------------------------------------------------------------- balazsszekely · 2020-07-22 14:20 Maybe this thread can help: https://forum.lazarus.freepascal.org/index.php/topic,24826.0.html ---------------------------------------------------------------------- TyneBridges · 2020-07-22 14:26 Quote from: GetMem on July 22, 2020, 04:20:00 pmMaybe this thread can help: https://forum.lazarus.freepascal.org/index.php/topic,24826.0.html Thanks. That's the thread I was referring to. Does what was said in 2014 still apply? ---------------------------------------------------------------------- ASBzone · 2020-07-22 17:01 Quote from: TyneBridges on July 22, 2020, 04:26:46 pmQuote from: GetMem on July 22, 2020, 04:20:00 pmMaybe this thread can help: https://forum.lazarus.freepascal.org/index.php/topic,24826.0.html Thanks. That's the thread I was referring to. Does what was said in 2014 still apply? Are you trying to capture or track when the service is logged on or off?  Or when specific users logon or logoff of Windows in general? ---------------------------------------------------------------------- TyneBridges · 2020-07-22 18:41 Quote from: ASBzone on July 22, 2020, 07:01:38 pmQuote from: TyneBridges on July 22, 2020, 04:26:46 pmQuote from: GetMem on July 22, 2020, 04:20:00 pmMaybe this thread can help: https://forum.lazarus.freepascal.org/index.php/topic,24826.0.html Thanks. That's the thread I was referring to. Does what was said in 2014 still apply? Are you trying to capture or track when the service is logged on or off?  Or when specific users logon or logoff of Windows in general? It's user logons and logoffs I'm interested in, because the service will be set to automatic, so it starts at bootup and only closes at system shutdown. I think, if I can detect when the logon happens, getting the user name should be straightforward with a call to the Windows API. ---------------------------------------------------------------------- TyneBridges · 2020-07-30 13:27 Has anyone any hints on how to do this, and where in my existing service the code should go? What I want to do is record each user session in my database (already created and linked), so I need to detect each user logon and logoff - session end or system shutdown. It seems as if this would be a frequent requirement in a Windows service and I'm disappointed that it's not easier or better- documented. Thanks. ---------------------------------------------------------------------- fred · 2020-07-30 14:02 I don't know much of it but in a windows network there is a policy for running a task at logon/logoff. You can also start a scheduled task on user logon and system  events. ---------------------------------------------------------------------- PascalDragon · 2020-07-30 14:14 I have not tested it, but in essence you need to add a class that inherits from TDaemonController where you override the virtual Controller method (this method will be called like the LPHANDLER_FUNCTION_EX). Then you need to descend from TDaemonApplication and override CreateDaemonController where you return your TDaemonController descendant. Finally set AppClass to your TDaemonApplication descendant first thing in your main project before any call to Application. The daemon framework should now use your classes and you can happily intercept the SERVICE_CONTROL_SESSIONCHANGE message. Again: I have not tested this, but from what I can see it should work. ---------------------------------------------------------------------- TyneBridges · 2020-07-30 21:52 Quote from: PascalDragon on July 30, 2020, 04:14:50 pmI have not tested it, but in essence you need to add a class that inherits from TDaemonController where you override the virtual Controller method (this method will be called like the LPHANDLER_FUNCTION_EX). Then you need to descend from TDaemonApplication and override CreateDaemonController where you return your TDaemonController descendant. Finally set AppClass to your TDaemonApplication descendant first thing in your main project before any call to Application. The daemon framework should now use your classes and you can happily intercept the SERVICE_CONTROL_SESSIONCHANGE message. Again: I have not tested this, but from what I can see it should work. Thanks for the hints - will give it a try. ---------------------------------------------------------------------- TyneBridges · 2020-08-07 09:25 On further examination I find I can't fill all the required detail: in brief, I just don't understand enough about services and objects to do it. As this task must be a frequent requirement in services, I'm surprised that it's so difficult. (The main code in the linked thread is in daemonapp.pp and it contains no mention of SERVICE_CONTROL_SESSIONCHANGE). I know it's a long shot but would appreciate any further details from someone who has successfully done this in FreePascal or Delphi. ---------------------------------------------------------------------- PascalDragon · 2020-08-08 11:23 I've now tried this myself. While my solution was correct per se, it wasn't enough. Thus I have now implemented this in FPC 3.3.1, to make it easier to utilize this. You can either use FPC trunk or you can backport the changes (see at the bottom). Now if you create a new Daemon application (I assume you use the Lazarus package for that) you need to go to your daemon's definition in the Daemon Mapper and inside WinBindings.AcceptedCodes enable wccSessionChange. In your daemon you then add an event handler for the new OnControlCodeEvent (not OnControlCode!). The parameters of this event handler will be like those for LPHANDLER_FUNCTION_EX (minus the lpContext parameter). For example (the constants used here are in JwaWinSvc and JwaWinUser): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TDaemon1.DataModuleControlCodeEvent(Sender: TCustomDaemon; ACode,  AEventType: DWord; AEventData: Pointer; var Handled: Boolean);var  evtype, sessionid: String;begin  if ACode = SERVICE_CONTROL_SESSIONCHANGE then begin    case aEventType of      WTS_CONSOLE_CONNECT:        evtype := 'Console Connect';      WTS_CONSOLE_DISCONNECT:        evtype := 'Console Disconnect';      WTS_REMOTE_CONNECT:        evtype := 'Remote Connect';      WTS_REMOTE_DISCONNECT:        evtype := 'Remote Disconnect';      WTS_SESSION_LOGON:        evtype := 'Session Logon';      WTS_SESSION_LOGOFF:        evtype := 'Session Logoff';      WTS_SESSION_LOCK:        evtype := 'Session Lock';      WTS_SESSION_UNLOCK:        evtype := 'Session Unlock';      WTS_SESSION_REMOTE_CONTROL:        evtype := 'Session Remote Control';      otherwise        evtype := Format('Unknown event type %d', [aEventType]);    end;     if Assigned(aEventData) then      sessionid := Format('%d', [PWTSSESSION_NOTIFICATION(aEventData)^.dwSessionId])    else      sessionid := 'none';     Logger.Info('Session Change of type ''%s'' with session %s', [evtype, sessionid]);  end;end; What you do with the received session ID is up to you... If you want to backport the changes to FPC 3.2.0: You need the changes of revisions 46326 and 46327. Apply these to your 3.2.0 sources (those that are provided by Lazarus for example). You then need to do a slight adjustment in packages/fcl- extra/src/win/daemonapp.inc: in TDaemonController.ReportStatus.GetAcceptedCodes you need to disable the handling of wccTimeChange, wccTriggerEvent and wccUserModeReboot (this way you don't need to add revision 46325 as well which might lead to the need to compile more than necessary). Once you've done the changes you go to the packages/fcl-extra/src directory and execute the following: Code: [Select]fpc -FUpath\to\units -Fiwin daemonapp.pp The path\to\units is the path where the compiler FPC 3.2.0 units are located in case of Lazarus that should be fpc\3.2.0\units\x86_64-win64\fcl-extra (or i386-win32 if you use the 32-bit variant). ---------------------------------------------------------------------- TyneBridges · 2020-08-09 14:21 Quote from: PascalDragon on August 08, 2020, 01:23:25 pmI've now tried this myself. While my solution was correct per se, it wasn't enough. Thus I have now implemented this in FPC 3.3.1, to make it easier to utilize this. You can either use FPC trunk or you can backport the changes (see at the bottom). ... That's great, thanks! This looks like just what I need. I'm currently using Lazarus 2.0.8 with FPC 3.0.4, so I will upgrade and try it out. I'm really grateful for your help. John ---------------------------------------------------------------------- TyneBridges · 2020-08-10 14:28 PascalDragon wrote: QuoteIf you want to backport the changes to FPC 3.2.0: You need the changes of revisions 46326 and 46327. Apply these to your 3.2.0 sources (those that are provided by Lazarus for example). As these are both modifications of the same files, have you any tips or pointers for how to get just the updated bits of each .pp and .inc file? Using 3.3.1 looked simpler but I couldn't work out how to get and install it. I'm also confused about the nature of the revisions - if the two sets are needed, that suggests the changes are not cumulative: can I assume the later version always takes priority? Thanks. ---------------------------------------------------------------------- ASBzone · 2020-08-10 19:33 Quote from: TyneBridges on August 10, 2020, 04:28:01 pmI'm also confused about the nature of the revisions - if the two sets are needed, that suggests the changes are not cumulative: can I assume the later version always takes priority? Version 3.3.1 is "trunk" or "development".   It is where all the new features go to percolate and blossom (to mix metaphors terribly). Version 3.2.0 is current "stable" version.    So if you want to be otherwise on the stable release version, but have the advantage of this specific change, you'll have to pull it from the development version and back port it to stable version. At some point when we get to FPC 3.4 (or even 4.0), it is hoped that all these new features will prove stable enough to end up in the new stable edition at that time (in the future) ---------------------------------------------------------------------- PascalDragon · 2020-08-11 08:09 Quote from: TyneBridges on August 10, 2020, 04:28:01 pmPascalDragon wrote: QuoteIf you want to backport the changes to FPC 3.2.0: You need the changes of revisions 46326 and 46327. Apply these to your 3.2.0 sources (those that are provided by Lazarus for example). As these are both modifications of the same files, have you any tips or pointers for how to get just the updated bits of each .pp and .inc file? Using 3.3.1 looked simpler but I couldn't work out how to get and install it. I'm also confused about the nature of the revisions - if the two sets are needed, that suggests the changes are not cumulative: can I assume the later version always takes priority? Changes build upon each other. In this specific case they're independent, but in general apply them from oldest to newest. I have attached the patches that correspond to the revisions. To apply them you go to fpc\3.2.0\source inside your Lazarus directory (in a command line or PowerShell terminal). Maybe do a backup of the packages\fcl-extra\src directory to be safe. Then you execute the following commands (the patch utility is shipped together with the FPC distribution that Lazarus provides, if you don't have fpc\3.2.0\bin\x86_64-win64 (or i386-win32 for 32-bit) in your PATH then you need to use the full path to that): Code: [Select]patch -Np 1 -i path\to\fcl-extra-46326.patch patch -Np 1 -i path\to\fcl-extra-46327.patch The output should look like this: Code: [Select]PS D:\lazarus\2.0.10\fpc\3.2.0\source> patch -Np 1 -i X:\fcl-extra-46326.patch patching file `packages/fcl-extra/src/daemonapp.pp' patching file `packages/fcl-extra/src/win/daemonapp.inc' PS D:\lazarus\2.0.10\fpc\3.2.0\source> patch -Np 1 -i X:\fcl- extra-46327.patch patching file `packages/fcl-extra/src/daemonapp.pp' patching file `packages/fcl-extra/src/unix/daemonapp.inc' patching file `packages/fcl-extra/src/win/daemonapp.inc' After that you go to the packages\fcl-extra directory and execute the following command (the same remark regarding PATH as for patch applies for fpc): Code: [Select]fpc -FU..\..\..\units\x86_64-win64\fcl-extra -Fiwin daemonapp.pp (Note: if you use a 32-bit Lazarus then you need to use i386-win32 instead of x86_64-win64) After that you rebuild Lazarus and everything should be set. Edit: forgot to attach the patches... ---------------------------------------------------------------------- TyneBridges · 2020-08-11 08:56 Thanks for your clarifications. I realised that 3.3.1 was a development version but got lost in the detail of how to install it, and wasn't aware of the patch utility. I will follow the instructions later today. ---------------------------------------------------------------------- TyneBridges · 2020-08-12 15:43 Sorry, another problem - the PATCH utility isn't on my PC: please see the attached image. It isn't on my other PC with 3.0.0 either. I have a utility called "Search Everything" and it didn't find it anywhere on either PC. Can you tell me how/where to get it? ---------------------------------------------------------------------- ASBzone · 2020-08-12 18:06 My installation of Lazarus/FPC is installed to:  C:\Programs\Lazarus.Fixes And I have this (attached): Do you get anything that turns up if you run the following at a command prompt? Code: [Select]DIR C:\Lazarus\patch.exe /s /a ---------------------------------------------------------------------- TyneBridges · 2020-08-12 18:16 Quote from: ASBzone on August 12, 2020, 08:06:30 pmMy installation of Lazarus/FPC is installed to:  C:\Programs\Lazarus.Fixes And I have this (attached): Do you get anything that turns up if you run the following at a command prompt? Code: [Select]DIR C:\Lazarus\patch.exe /s /a Thanks, but no, I don't. I can see the command looks in the Lazarus folder and its subfolders but, for me, it spends a few seconds searching and then returns "File not found". ---------------------------------------------------------------------- PascalDragon · 2020-08-12 19:35 Quote from: TyneBridges on August 12, 2020, 05:43:46 pmSorry, another problem - the PATCH utility isn't on my PC: please see the attached image. It isn't on my other PC with 3.0.0 either. I have a utility called "Search Everything" and it didn't find it anywhere on either PC. Can you tell me how/where to get it? Strange... maybe it's part of the i386-win32 addon? Cause I have that installed as well... Anyway, you should be able to get it from here as well. Alternatively you could add the changes manually... ---------------------------------------------------------------------- ASBzone · 2020-08-12 20:12 Quote from: PascalDragon on August 12, 2020, 09:35:18 pmStrange... maybe it's part of the i386-win32 addon? Strange... maybe it's part of the i386-win32 addon? Cause I have that installed as well... That's a good point.  I also have the add-on for deploying 32-bit Windows code. ---------------------------------------------------------------------- TyneBridges · 2020-08-14 13:06 I'm either really unlucky with this project or just plain stupid. I've now got the patch executable but can't get it to work. Can anybody see what I'm doing wrong here? As far as I can tell, the system is telling me that a file doesn't exist which obviously does. Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i c:\lazarus\ fpc\3.2.0\source>c:\lazarus\fpc\3.2.0\bin\x86_64-win64\patch -Np 1 -i c:\lazpatches\fcl- extra-43626.patchc:\lazarus\fpc\3.2.0\bin\x86_64-win64\patch: **** Can't open patch file c:\lazpatches\fcl-extra-43626.patch : No such file or directory c:\lazarus\fpc\3.2.0\source>dir C:\lazpatches Volume in drive C is OS Volume Serial Number is AC27-A577  Directory of C:\lazpatches 12/08/2020  16:30              .12/08/2020  16:30            ..12/08/2020  16:24             4,257 fcl- extra-46326.patch12/08/2020  16:24             5,574 fcl- extra-46327.patch12/08/2020  16:30              src_backup             2 File(s)          9,831 bytes               3 Dir(s)  713,456,386,048 bytes free Does it matter if I rename the patch files to something brief and simple like 1.patch and 2.patch, or is there an internal check that would prevent this working? ---------------------------------------------------------------------- AlexTP · 2020-08-14 13:11 I don't use "patch" app, I always run "svn patch ". And with RELATIVE filename. ---------------------------------------------------------------------- TyneBridges · 2020-08-14 13:15 Quote from: Alextp on August 14, 2020, 03:11:33 pmI don't use "patch" app, I always run "svn patch ". And with RELATIVE filename. Thanks. I created copies of the patch files called 1.patch and 2.patch and the utility was able to find them, so that seems to have worked. I guess I'm seeing an undocumented bug in Windows long file names because I also had a "file not found" with Windows' fc the other day, even after double-checking the name. ---------------------------------------------------------------------- TyneBridges · 2020-08-14 14:19 I've applied the two patches I followed the first part of your instruction and the patches seemed to apply successfully. However, things went wrong again at this stage: Quote from: PascalDragon on August 11, 2020, 10:09:03 am QuoteAfter that you go to the packages\fcl-extra directory and execute the following command (the same remark regarding PATH as for patch applies for fpc): Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i fpc -FU..\..\..\units\x86_64-win64\fcl-extra -Fiwin daemonapp.pp (Note: if you use a 32-bit Lazarus then you need to use i386-win32 instead of x86_64-win64) After that you rebuild Lazarus and everything should be set. I tried the FPC command both without and then with the full path before daemonapp.pp. Both times it failed with an error: Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i c:\lazarus\fpc\3.2.0\source\packages\fcl- extra>c:\lazarus\fpc\3.2.0\bin\x86_64-win64\fpc -FU C:\lazarus\fpc\3.2.0\units\x86_64-win64\fcl-extra -Fiwin c:\lazarus\fpc\3.2.0\source\packages\fcl- extra\src\daemonapp.ppWarning: Only one source file supported, changing source file to compile from "C:\lazarus\fpc\3.2.0\units\x86_64-win64\fcl-extra" into "c:\lazarus\fpc\3.2.0\source\packages\fcl-extra\src\daemonapp.pp"Free Pascal Compiler version 3.2.0 [2020/07/07] for x86_64Copyright (c) 1993-2020 by Florian Klaempfl and othersTarget OS: Win64 for x64Compiling c:\lazarus\fpc\3.2.0\source\packages\fcl- extra\src\daemonapp.ppdaemonapp.pp(461,2) Fatal: Cannot open include file "daemonapp.inc"Fatal: Compilation abortedError: c:\lazarus\fpc\3.2.0\bin\x86_64-win64\ppcx64.exe returned an error exitcode The command line was invoked with "Run as Administrator". I guess the problem is being unable to find daemonapp.inc, but I don't know how to fix that. (I have C:\lazarus\fpc\3.2.0\bin\x86_64-win64 in my Windows path.) ---------------------------------------------------------------------- PascalDragon · 2020-08-14 14:51 Ah, sorry, small mixup there. You should go to packages\fcl-extra\src (a subdirectory of where you are). And don't add a space between -FU and the directory. The full command line should now be this: Code: [Select]c:\lazarus\fpc\3.2.0\source\packages\fcl- extra\src>c:\lazarus\fpc\3.2.0\bin\x86_64-win64\fpc -FUC:\lazarus\fpc\3.2.0\units\x86_64-win64\fcl-extra -Fiwin daemonapp.pp ---------------------------------------------------------------------- TyneBridges · 2020-08-15 14:34 Thanks but it still won't work for me, I'm afraid. Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i C:\lazarus\fpc\3.2.0\source\packages\fcl- extra\src>c:\lazarus\fpc\3.2.0\bin\x86_64-win64\fpc -FUC:\lazarus\fpc\3.2.0\units\x86_64-win64\fcl-extra -Fiwin daemonapp.ppFree Pascal Compiler version 3.2.0 [2020/07/07] for x86_64Copyright (c) 1993-2020 by Florian Klaempfl and othersTarget OS: Win64 for x64Compiling daemonapp.ppdaemonapp.inc(34,10) Warning: Function result does not seem to be setdaemonapp.inc(40,80) Warning: Converting pointers to signed integers may result in wrong comparison results and range errors, use an unsigned type instead.daemonapp.inc(249,31) Warning: Local variable "IDTag" does not seem to be initializeddaemonapp.inc(526,13) Warning: Symbol "Resume" is deprecateddaemonapp.inc(547,29) Warning: Symbol "Resume" is deprecateddaemonapp.inc(597,27) Error: Identifier not found "SERVICE_ACCEPT_USERMODEREBOOT"daemonapp.pp(1350,12) Warning: Symbol "Suspend" is deprecateddaemonapp.pp(1520) Fatal: There were 1 errors compiling module, stoppingFatal: Compilation abortedError: c:\lazarus\fpc\3.2.0\bin\x86_64-win64\ppcx64.exe returned an error exitcode  Does the "Identifier not found" error mean the patches weren't applied correctly? I didn't see any errors when I applied them. ---------------------------------------------------------------------- PascalDragon · 2020-08-16 11:59 Did you do this part I had written to you in my original post about my changes? QuoteYou then need to do a slight adjustment in packages/fcl- extra/src/win/daemonapp.inc: in TDaemonController.ReportStatus.GetAcceptedCodes you need to disable the handling of wccTimeChange, wccTriggerEvent and wccUserModeReboot (this way you don't need to add revision 46325 as well which might lead to the need to compile more than necessary). ---------------------------------------------------------------------- TyneBridges · 2020-08-16 14:55 Quote from: PascalDragon on August 16, 2020, 01:59:37 pmDid you do this part I had written to you in my original post about my changes? QuoteYou then need to do a slight adjustment in packages/fcl- extra/src/win/daemonapp.inc: in TDaemonController.ReportStatus.GetAcceptedCodes you need to disable the handling of wccTimeChange, wccTriggerEvent and wccUserModeReboot (this way you don't need to add revision 46325 as well which might lead to the need to compile more than necessary). Oops! Sorry, I didn't - just realised I've missed that step. I'll do the missing step and then try again. Thanks. ---------------------------------------------------------------------- TyneBridges · 2020-08-17 13:36 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. 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. Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i c:\lazarus\fpc\3.2.0\bin\x86_64-win64\fpc -FUC:\lazarus\fpc\3.2.0\units\x86_64-win64\fcl-extra -Fiwin daemonapp.pp C:\lazarus\fpc\3.2.0\source\packages\fcl- extra\src>c:\lazarus\fpc\3.2.0\bin\x86_64-win64\fpc -FUC:\lazarus\fpc\3.2.0\units\x86_64-win64\fcl-extra -Fiwin daemonapp.ppFree Pascal Compiler version 3.2.0 [2020/07/07] for x86_64Copyright (c) 1993-2020 by Florian Klaempfl and othersTarget OS: Win64 for x64Compiling daemonapp.ppdaemonapp.inc(34,10) Warning: Function result does not seem to be setdaemonapp.inc(40,80) Warning: Converting pointers to signed integers may result in wrong comparison results and range errors, use an unsigned type instead.daemonapp.inc(249,31) Warning: Local variable "IDTag" does not seem to be initializeddaemonapp.inc(526,13) Warning: Symbol "Resume" is deprecateddaemonapp.inc(547,29) Warning: Symbol "Resume" is deprecateddaemonapp.inc(556,28) Warning: Function result does not seem to be setdaemonapp.pp(845,3) Note: Local variable "C" not useddaemonapp.pp(946,3) Note: Local variable "D" is assigned but never useddaemonapp.pp(1062,3) Note: Local variable "ControlCodes" not useddaemonapp.pp(1296,3) Note: Local variable "CC" is assigned but never useddaemonapp.pp(1297,3) Note: Local variable "S" is assigned but never useddaemonapp.pp(1350,12) Warning: Symbol "Suspend" is deprecateddaemonapp.pp(249,5) Note: Private field "TDaemonDef.FServiceName" is never useddaemonapp.pp(362,5) Note: Private field "TCustomDaemonApplication.FControllerCount" is never useddaemonapp.pp(466,3) Note: Local variable "DesignMapper" not usedWriting Resource String Table file: daemonapp.rsj2198 lines compiled, 0.3 sec7 warning(s) issued8 note(s) issued 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? Thanks for your help. ---------------------------------------------------------------------- PascalDragon · 2020-08-18 07:43 Quote from: TyneBridges on August 17, 2020, 03:36:17 pmI 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. Quote from: TyneBridges on August 17, 2020, 03:36:17 pmThere 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. Quote from: TyneBridges on August 17, 2020, 03:36:17 pmI 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 applicationgo 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 itemset DaemonClassName to the name of your daemon class in (by default) DaemonUnit1open the WinBindings entry: there should be a AcceptedCodes at the top[/tt]enable wccSessionChangeinside your daemon set an event handler for OnControlCodeEvent ---------------------------------------------------------------------- TyneBridges · 2020-08-18 15:03 Quote from: PascalDragon on August 18, 2020, 09:43:27 amI did it as follows: start a new service applicationgo 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 itemset DaemonClassName to the name of your daemon class in (by default) DaemonUnit1open the WinBindings entry: there should be a AcceptedCodes at the top[/tt]enable wccSessionChangeinside 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?). ---------------------------------------------------------------------- PascalDragon · 2020-08-19 08:29 Quote from: TyneBridges on August 18, 2020, 05:03:32 pmThanks 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TNotifyEvent = procedure(aSender: TObject) of object; An event is usually declared like this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  TSomeClass = class  private    fOnWhatever: TNotifyEvent;  public    property OnWhatever: TNotifyEvent read fOnWhatever write fOnWhatever;  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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TTestClass.DoWhatever;begin  if Assigned(fOnWhatever) then    fOnWhatever(Self); // Self is usually used as aSender parameterend; Now the OnControlCodeEvent event has the type TCustomControlCodeEvEvent which has the following signature: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i 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 ). 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i constructor TDaemon1.Create(AOwner: TComponent);begin  inherited Create(AOwner);  OnControlCodeEvent := @DataModuleControlCodeEvent;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 · 2020-08-19 14:19 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i C:\Users\JH\Documents\FPProjects\Booking Service\>bc2 -iException at 000000010003D9FE: EOSError:System error, (OS Code 123):The filename, directory name, or volume label syntax is incorrect.  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.) ---------------------------------------------------------------------- PascalDragon · 2020-08-20 07:39 Quote from: TyneBridges on August 19, 2020, 04:19:35 pmHowever, 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 · 2020-08-21 13:36 Quote from: PascalDragon on August 20, 2020, 09:39:00 amQuote from: TyneBridges on August 19, 2020, 04:19:35 pmHowever, 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. ---------------------------------------------------------------------- PascalDragon · 2020-08-21 15:43 Quote from: TyneBridges on August 21, 2020, 03:36:22 pmThanks! It's working at last. I'm grateful for your help. Good to know that you have it working now.