[Lazarus] Where to define conditionals for FPC
Marc Weustink
marc at dommelstein.nl
Sat May 16 17:59:05 CEST 2020
On 15-5-2020 23:54, Bo Berglund via lazarus wrote:
> On Fri, 15 May 2020 21:26:43 +0200, Marc Weustink via lazarus
> <lazarus at lists.lazarus-ide.org> wrote:
>
>>
>>
>> On May 14, 2020 10:21:22 AM GMT+02:00, Bo Berglund via lazarus <lazarus at lists.lazarus-ide.org> wrote:
>>> On Tue, 12 May 2020 13:49:08 +0200, Marc Weustink via lazarus
>>> <lazarus at lists.lazarus-ide.org> wrote:
>>>
>>> While going through your post I got into this section:
>>>
>>>>> 3) Compiling same code with Delphi and FPC?
>>>>> Do you convert your projects (manually) to make it possible to use
>>>>> both Delphi and Lazarus as the IDE for further work on the same
>>>>> sources?
>>>>> If so do you have any hints as to what to look out for?
>>>>
>>>> Yes, it is a manual conversion. But in our case not that hard. Most of
>>>
>>>> the converted projects are windows (network) services.
>>>> The difference between a delphi service and a fpc daemon is covered in
>>> a
>>>> BaseServer class / unit. So for services derived from it there is no
>>>> different code.
>>>
>>> Since I am dealing with a Windows Service too I wonder how you do it
>>> to get a daemon application in Lazarus?
>>>
>>> I have installed the package lazdaemon 0.9.9 on advice elsewhere.
>>> It is said to be implementing services, but I don't know if it is
>>> involved in the Delphi conversion...
>>>
>> I'll see if I can extract some example snippet. I cannot remember that I used a package.
>>
>> I didn't use the form based service
>
> Well this application also does not use any forms, but inherently the
> TService application creates a data module, which supplies some of the
> form functionality, I guess.
>
> I tried in Lazarus by creating a new daemon application and look what
> it brings into the project...
>
> But I did not figure out how it works by looking at the code framework
> so I guess I have to read up a lot about the way daemons work in
> FPC...
> In any case there is a sort of form here as well, looks a lot like a
> data module.
Never used that. I've attached and stripped down and anonymized version
of our base server definition. At places where you should place your own
code or where it is trivial, I wrote .....
I also didn't include the unit description defining the service derived
from TMyBaseServer
Marc
-------------- next part --------------
================================================================================
unit MyDaemon;
interface
uses
daemonapp, Classes, SysUtils, MyBaseServer;
type
TMyDaemon = class(TDaemon)
private
protected
function Install: Boolean; override;
function Execute: Boolean; override;
public
end;
TMyDebugDaemonController = class(TDaemonController)
public
function ReportStatus : Boolean; override;
end;
TMyDaemonThread = class(TDaemonThread)
public
property Terminated;
end;
TMyDaemonMapper = Class(TCustomDaemonMapper)
public
constructor Create(AOwner : TComponent); override;
end;
{ TMyDaemonApplication }
TMyDaemonApplication = class(TDaemonApplication)
private
FDebug: Boolean;
procedure LogEvent(const ALogText: String);
protected
function DoConfig(AParams: TMyCommandParams): Boolean; virtual; abstract;
function DoUpdate: Boolean; virtual; abstract;
function DoDebug: Boolean; virtual;
function ProcessRun: Boolean; virtual; abstract;
procedure CreateDaemonController(var AController : TDaemonController); override;
procedure CreateDaemonInstance(Var ADaemon : TCustomDaemon; DaemonDef : TDaemonDef); override;
procedure DoRun; override;
property Debug: Boolean read FDebug write FDebug;
public
end;
TMyBaseServiceApplication = class(TMyDaemonApplication);
implementation
{ TMyDebugDaemonController }
function TMyDebugDaemonController.ReportStatus: Boolean;
begin
Result := True;
end;
{ TMyDaemonMapper }
constructor TMyDaemonMapper.Create(AOwner: TComponent);
var
D: TDaemonDef;
begin
inherited Create(AOwner);
D := DaemonDefs.Add as TDaemonDef;
D.DisplayName := MyServer.DisplayName;
D.Name := MyServer.Name;
D.DaemonClassName := TMyDaemon.ClassName;
D.WinBindings.ServiceType := stWin32;
end;
{ TMyDaemon }
function TMyDaemon.Install: Boolean;
begin
MyServer.BeforeInstall;
Result := inherited Install;
MyServer.AfterInstall;
end;
function TMyDaemon.Execute: Boolean;
begin
Result := True;
MyServer.Execute;
end;
{ TMyDaemonApplication }
function TMyDaemonApplication.DoDebug: Boolean;
var
T: TThread;
M: TCustomDaemonMapper;
D: TCustomDaemon;
begin
Result := True;
CreateServiceMapper(M);
D := CreateDaemon(M.DaemonDefs[0]);
D.Status := csStartPending;
try
T := TDaemonThread.Create(D);
T.Resume;
T.WaitFor;
FreeAndNil(T);
except
on E : Exception do
D.Logmessage(Format(SErrDaemonStartFailed,[D.Definition.Name,E.Message]));
end;
end;
procedure TMyDaemonApplication.CreateDaemonController(var AController: TDaemonController);
begin
if FDebug
then AController := TMyDebugDaemonController.Create(Self)
else inherited CreateDaemonController(AController);
end;
procedure TMyDaemonApplication.CreateDaemonInstance(var ADaemon: TCustomDaemon; DaemonDef: TDaemonDef);
begin
inherited CreateDaemonInstance(ADaemon, DaemonDef);
MyServer.Daemon := ADaemon;
end;
procedure TMyDaemonApplication.DoRun;
begin
if ProcessRun then Exit;
inherited;
end;
procedure TMyDaemonApplication.LogEvent(const ALogText: String);
begin
WriteLn(AlogText);
end;
procedure InitApplication;
begin
RegisterDaemonClass(TMyDaemon);
RegisterDaemonMapper(TMyDaemonMapper);
end;
initialization
InitApplication;
finalization
end.
================================================================================
unit MyBaseServer;
interface
{$ifndef FPC}
{$define WINDOWS}
{$define CPUI386}
{$endif}
.....
uses
{$ifdef fpc}
daemonapp,
{$else}
SvcMgr, WinSvc,
{$endif}
.....
type
{$ifdef fpc}
{ TMyService }
TMyService = class(TComponent)
private
FDaemon: TCustomDaemon;
FDisplayName: String;
FServiceStartName: String;
FErrCode: DWord;
FWin32ErrorCode: DWord;
protected
function Terminated: Boolean;
function ServiceThread: TThread;
public
procedure AfterInstall; virtual; abstract;
procedure BeforeInstall; virtual; abstract;
procedure Execute; virtual; abstract;
procedure ReportStatus;
property Daemon: TCustomDaemon read FDaemon write FDaemon;
property DisplayName: String read FDisplayName write FDisplayName;
property ServiceStartName: String read FServiceStartName write FServiceStartName;
property ErrCode: DWord read FErrCode write FErrCode;
property Win32ErrCode: DWord read FWin32ErrorCode write FWin32ErrorCode;
end;
{$else fpc}
// delphi part
TMyService = class(TService)
private
procedure ServiceBeforeInstall(Sender: TService);
procedure ServiceAfterInstall(Sender: TService);
procedure ServiceExecute(Sender: TService);
protected
procedure Execute; virtual; abstract;
procedure AfterInstall; virtual; abstract;
procedure BeforeInstall; virtual; abstract;
public
constructor Create(AOwner: TComponent); override;
function GetServiceController: TServiceController; override;
end;
{$endif}
TMyBaseSrv = class(TMyService)
private
.....
var
MyServer: TMyBaseSrv;
implementation
{$ifdef fpc}
uses
MyDaemon;
{$endif}
type
{$ifndef fpc}
TMyBaseServiceApplication = class(TServiceApplication)
private
FDebug: Boolean;
protected
function DoConfig(AParams: TMyCommandParams): Boolean; virtual; abstract;
function DoUpdate: Boolean; virtual; abstract;
function DoDebug: Boolean; virtual;
function ProcessRun: Boolean; virtual; abstract;
property Debug: Boolean read FDebug write FDebug;
public
procedure Run; override;
end;
{$endif}
TMyServiceApplication = class(TMyBaseServiceApplication)
private
protected
function DoConfig(AParams: TMyCommandParams): Boolean; override;
function DoUpdate: Boolean; override;
function ProcessRun: Boolean; override;
public
end;
.....
{ TMyServiceApplication }
{$ifndef MSWINDOWS}
function _GetApplicationName: String;
begin
Result := 'myapp';
end;
{$endif}
function TMyServiceApplication.DoConfig(AParams: TMyCommandParams): Boolean;
begin
Result := True;
......
end;
function TMyServiceApplication.DoUpdate: Boolean;
begin
Result := MyServer.ServiceUpdate;
end;
function TMyServiceApplication.ProcessRun: Boolean;
var
Params: TMyCommandParams;
begin
Result := True;
Params := TMyCommandParams.Create;
try
if Params.GetFlag('update') <> cfUnset
then begin
if DoUpdate then Exit;
end
else if Params.GetFlag('config') <> cfUnset
then begin
if DoConfig(Params) then Exit;
end;
Debug := Params.GetFlag('debug') <> cfUnset
finally
Params.Free;
end;
if Debug
then begin
DoDebug;
Exit;
end;
Result := False;
end;
.....
procedure TMyBaseSrv.Execute;
{$ifndef MSWINDOWS}
const
ERROR_PROCESS_ABORTED = 1;
{$endif}
var
.....
{$ifdef fpc}
TMyDaemonThread(Daemon.DaemonThread).CheckControlMessage(False);
{$else}
ServiceThread.ProcessRequests(False);
{$endif}
.....
{$ifdef fpc}
{ TMyService }
procedure TMyService.ReportStatus;
begin
Daemon.ReportStatus;
end;
function TMyService.ServiceThread: TThread;
begin
Result := TMyDaemonThread(Daemon.DaemonThread);
end;
function TMyService.Terminated: Boolean;
begin
Result := TMyDaemonThread(Daemon.DaemonThread).Terminated;
end;
{$else}
// delphi
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
MyServer.Controller(CtrlCode);
end;
constructor TMyService.Create(AOwner: TComponent);
begin
CreateNew(AOwner, 0);
OnExecute := ServiceExecute;
inherited BeforeInstall := ServiceBeforeInstall;
inherited AfterInstall := ServiceAfterInstall;
end;
function TMyService.GetServiceController: TServiceController;
begin
Result := ServiceController;
end;
procedure TMyService.ServiceAfterInstall(Sender: TService);
begin
AfterInstall;
end;
procedure TMyService.ServiceBeforeInstall(Sender: TService);
begin
BeforeInstall;
end;
procedure TMyService.ServiceExecute(Sender: TService);
begin
Execute;
end;
{ TMyBaseServiceApplication }
function TMyBaseServiceApplication.DoDebug: Boolean;
begin
Result := False;
end;
procedure TMyBaseServiceApplication.Run;
begin
if ProcessRun then Exit;
inherited;
end;
{$endif}
procedure InitApplication;
begin
{$ifdef fpc}
RegisterDaemonApplicationClass(TMyServiceApplication);
{$else}
Application.Free;
Application := TMyServiceApplication.Create(nil);
{$endif}
end;
initialization
InitApplication;
finalization
end.
================================================================================
program MyApp;
{$ifdef fpc}
{$R 'MyApp_version.rc'}
{$else}
{$R 'MyApp_version.res' 'MyApp_version.rc'}
{$endif}
uses
{$ifdef fpc}
interfaces,
daemonapp,
{$else}
svcmgr,
{$endif}
MyBaseServer,
MyServer,
.....
begin
Application.Initialize;
Application.CreateForm(TMySrv, MyServer);
Application.Run;
end.
================================================================================
More information about the lazarus
mailing list