On 15-5-2020 23:54, Bo Berglund via lazarus wrote:
On Fri, 15 May 2020 21:26:43 +0200, Marc Weustink via lazarus
<[email protected]> wrote:
On May 14, 2020 10:21:22 AM GMT+02:00, Bo Berglund via lazarus
<[email protected]> wrote:
On Tue, 12 May 2020 13:49:08 +0200, Marc Weustink via lazarus
<[email protected]> 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
================================================================================
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.
================================================================================
--
_______________________________________________
lazarus mailing list
[email protected]
https://lists.lazarus-ide.org/listinfo/lazarus