Recent

Author Topic: Communication between packages  (Read 5126 times)

CCRDude

  • Hero Member
  • *****
  • Posts: 596
Communication between packages
« on: June 01, 2017, 11:29:56 am »
I've extended the Lazarus IDE with a few own packages (vcs, codesigning, installer, PasDoc comments).

Now I've reached a situation where I would like to use others, if they exist - meaning optional.

One specific example: my installer package should codesign a created installer, using the existing codesigning package if possible.

  • My first idea was that I could simply add laz-codesigning-helper as a requirement to laz-installer-helper, but I'm looking into a more independent method.
  • An ugly next idea was some kind of IPC, where the codesigning part would either answer, or not.
  • Then, I thought about interfaces. Sadly, I haven't really used them a lot. I could use RegisterClass/FindClass and an interface, but that doesn't give me access to my singleton yet, since interfaces would not support class functions.

Any suggestions on how to best implement this optional dependency?

Phil

  • Hero Member
  • *****
  • Posts: 2737
Re: Communication between packages
« Reply #1 on: June 01, 2017, 02:24:31 pm »
Any suggestions on how to best implement this optional dependency?

For your example, (1) would be fine since installer and signing are so closely related. In fact, I can't imagine why you would create and installer and not sign it if the certificate and means of signing are available.

And even in the more general case, if one package can call another, that means they're related in some way, so again, it seems like (1) would be acceptable.

For (2), does Lazarus support any kind of communication between packages? They are in the same executable, so that simplifies things a little bit, but I don't recall ever hearing any discussion on this idea.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Communication between packages
« Reply #2 on: June 01, 2017, 02:45:09 pm »
Don't bother. Create a new package that will need both the signing and installer packages that will auto sign the created installer. If you have both packages then install the 3rd if not inform the user what is missing or ask permission to download the required packages from the online package manager. It is as simple as that with packages. You need to know what is installed what license it has and exactly what it does.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

sky_khan

  • Guest
Re: Communication between packages
« Reply #3 on: June 01, 2017, 03:05:16 pm »
If all are your packages you can use interfaces in a base package which all your packages will include it as requirement.
Something like these: ( its just an example in concept, not compilable)
in basepackage
Code: Pascal  [Select][+][-]
  1. unit ccrdude_packagebase;
  2. interface
  3.   {$interfaces corba}
  4.    type
  5.    IInstaller = interface
  6.       procedure Install(...);
  7.    end;
  8.  
  9.    TGetInstallerEvent = function: IInstaller;
  10.  
  11. function getInstaller: IInstaller;
  12.  
  13. var
  14.   OnGetInstaller : TGetInstallerEvent=nil;
  15.  
  16. implementation
  17.  
  18. function getInstaller: IInstaller;
  19. begin
  20.   Result:=nil;
  21.   if Assigned(OnGetInstaller) then Result:=OnGetInstaller;
  22. end;
  23.  


in installer package
Code: Pascal  [Select][+][-]
  1. unit ccrdude_installer;
  2. interface
  3. uses ccrdude_packagebase;
  4. type
  5.   TInstaller = class(TObject,IInstaller);
  6.   public
  7.       procedure Install(...);
  8.   end;
  9.  
  10. implementation
  11. var
  12.   SingleInstaller : TInstaller=nil;
  13.  
  14. function getInstaller: IInstaller;
  15. begin
  16.   if SingleInstaller= nil then
  17.     SingleInstaller:=TInstaller.Create;
  18.   Result:=SingleInstaller;
  19. end;
  20.  
  21.  
  22. initialization
  23.   ccrdude_packagebase.OnGetInstaller :=@getInstaller;
  24. finalization
  25.   SingleInstaller.Free;
  26. end.
  27.  

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9794
  • Debugger - SynEdit - and more
    • wiki
Re: Communication between packages
« Reply #4 on: June 01, 2017, 03:25:45 pm »
Well your are facing to issues here.

1) Detecting the other package
2) communicating


Lets say your installer wants to find the code signer, and your installer then calls the codesigner. (you can do it the other way round if you want)

1)
I don't know if the IDEIntf exposes access to the packagemanager. That would be one way, if available.
But actually you do not need this. See next point, it will contain a solution.

2)
I would create a CodeSignerInterface package.
This exports a base class, (with virtual abstract methods), that cover all the functionality that you want to reach from other packages

The codesigner package defines a class that inherits from the above class, and implements all the methods.
- Package codesigner depends on  CodeSignerInterface
- CodeSignerInterface does not have dependencies (well rtl, etc), so it is very small.

 
Your Installer uses CodeSignerInterface too.
It can make all the calls that it needs.

Now back to point 1, the installer needs the instantiated object that codesigner created (the one with the actual implementation.

So in  CodeSignerInterface declare a public variable
CodeSignerObject: TCodeSignerInterface = nil;

If the codesigner package is installed, it will set this object.
So other packages can check.

Only you must make sure that the check happens after codesigner had a change to set it.
So codesigner can set it in its registration.
The other packages will check, when they need it (eg on an action by a user)

If they need it in registration, then additionallyyou can have a list of callbacks,
and codesigner will call them. That is only if codesigner did not already set the object.

----------------
Parts of this are in SourceEditorIntf (part of IDEIntf)

CCRDude

  • Hero Member
  • *****
  • Posts: 596
Re: Communication between packages
« Reply #5 on: June 01, 2017, 04:25:56 pm »
@Phil: but what about people who do not have a certificate for signing? They would still need to install the signing package, even though they don't need it at all, except for the dependency.

@taazz: that third package sounds like a very good idea. Would still need to use RegisterClass/FindClass, to be able to know whether to show the "Sign installer after building it" option in the options frame, but that third simple package could easily make the connection!

@SkyKhan: A base package is something I would like to avoid, but thanks for the insight on using interfaces :)

@Martin_fr: another interesting concept, thank you! I use a class function to access (and initialize if necessary) the one instance btw. Using your approach, the base package would always need to be installed. Compared to that, I favour taazz approach of a package that only those that want both packages need to install.

Phil

  • Hero Member
  • *****
  • Posts: 2737
Re: Communication between packages
« Reply #6 on: June 01, 2017, 04:31:34 pm »
@Phil: but what about people who do not have a certificate for signing? They would still need to install the signing package, even though they don't need it at all, except for the dependency.

In this case, what about just combining the two packages? Is there any benefit to having two separate packages? Obviously there's at least one downside.


sky_khan

  • Guest
Re: Communication between packages
« Reply #7 on: June 01, 2017, 04:59:01 pm »
Well, if you dont use a base package you miss the opportunity of communicate with contract(using a common class or interface) but fine then you need a dynamic approach. You may use published methods like below but this has a disadvantage of being slower
Code: Pascal  [Select][+][-]
  1. type
  2.   TInstallMethod = procedure (data:pointer;out msg:string) of object;
  3.  
  4. procedure TForm1.Button1Click(Sender: TObject);
  5. var
  6.   C : TPersistentClass;
  7.   O : TPersistent;
  8.   M : TMethod;
  9.   msg : string;
  10. begin
  11.   C:=FindClass('TInstaller');
  12.   if Assigned(C) then
  13.   begin
  14.     O:=TComponentClass(C).Create(nil);
  15.     try
  16.       M.Code:=C.MethodAddress('Install');
  17.       if Assigned(M.Code) then
  18.       begin
  19.         M.Data:=O;
  20.         TInstallMethod(M)(Pointer($1234),msg);
  21.         ShowMessage(msg);
  22.       end;
  23.     finally
  24.      O.Free;
  25.     end;
  26.   end;
  27. end;              
  28.  

Code: Pascal  [Select][+][-]
  1. unit uinstall;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6. uses
  7.   Classes, SysUtils;
  8.  
  9. type
  10.   { TInstaller }
  11.   TInstaller = class(TComponent)
  12.   published
  13.     procedure Install(data:pointer;out msg:string);virtual;
  14.   end;
  15.  
  16. implementation
  17.  
  18. { TInstaller }
  19. procedure TInstaller.Install(data: pointer;out msg:string);
  20. begin
  21.   msg:=Format('Your data is %p',[data]);
  22. end;
  23.  
  24. initialization
  25.   RegisterClass(TInstaller);
  26. finalization
  27.   UnRegisterClass(TInstaller);
  28. end.
  29.  

CCRDude

  • Hero Member
  • *****
  • Posts: 596
Re: Communication between packages
« Reply #8 on: June 01, 2017, 05:27:33 pm »
In this case, what about just combining the two packages? Is there any benefit to having two separate packages? Obviously there's at least one downside.

In the thread were I showed my codesigning package, there was the legit remark that codesigning certificates do not come for free, so many developers do not use them.
The installer engines my other package supports (InnoSetup, NSIS, WiX Toolkit) are all free, so could of interest to more users.
Since they're primarily for my own use, I could of course just combine them, but since I also want to share and have the code public on gitlab, I'm trying to think on how to make this "good" ;)

I've now implemented the third-package method from taazz.

@SkyKhan: wow! That's what I was looking for when I started this thread!
Slow is not really a problem here, since building the installer takes many seconds, signing it takes many seconds also, so a few milliseconds more in the one call leading from one to the other is of no relevance :)

Your example shows a new object here, but I guess it's pretty much the same with class functions that would give me the existing singleton instance :)

Many thanks for the input from everyone here, this helped me solve this pretty fast!

sky_khan

  • Guest
Re: Communication between packages
« Reply #9 on: June 01, 2017, 05:50:41 pm »
You're welcome. I dont know if class function pointers are supported but you can mimic "class function"s in old way like below. In this case you'll need to call getInstance dynamicaly to get singleton instance.
Code: Pascal  [Select][+][-]
  1. type
  2.   { TInstaller }
  3.   TInstaller = class(TComponent)
  4.   published
  5.     procedure Install(data:pointer;out msg:string);virtual;
  6.     function getInstance:TComponent;virtual;
  7.   end;
  8.  
  9. implementation
  10.  
  11. var
  12.   Instance : TInstaller = nil;
  13.  
  14. { TInstaller }
  15. procedure TInstaller.Install(data: pointer;out msg:string);
  16. begin
  17.   msg:=Format('Your data is %p',[data]);
  18. end;
  19.  
  20. function TInstaller.getInstance: TComponent;
  21. begin
  22.   if Instance=nil then Instance:=TInstaller.Create(nil);
  23.   Result:=Instance;
  24. end;
  25.  
  26. initialization
  27.   RegisterClass(TInstaller);
  28. finalization
  29.   UnRegisterClass(TInstaller);
  30.   Instance.Free;
  31. end.
  32.  

CCRDude

  • Hero Member
  • *****
  • Posts: 596
Re: Communication between packages
« Reply #10 on: June 01, 2017, 07:33:54 pm »
I dont know if class function pointers are supported

I can confirm this works (in Lazarus 1.6.4) for class methods :)
Here's a tiny test program based on your example.

sky_khan

  • Guest
Re: Communication between packages
« Reply #11 on: June 01, 2017, 07:43:42 pm »
Nice. Now you have all information you need to accomplish the goal on your mind :)

 

TinyPortal © 2005-2018