Question

I have project group in Delphi XE2 which function is to load plugins from packages. I created these projects:

  • PluginInterface.bpl – package with interfaces to plugins and to MainForm
    • UClassManager.pas – plugins manager
    • UPlugin.pas – plugins interface
  • MultiPlug2.exe – Main Form with configurable menu
    • MainUnit.pas (*.dfm) – MainForm (MDI Owner)
    • etc... – some forms (e.g. Splash, Database Login)
  • TestPlugin.bpl – Test plugin
    • UTestPlugin.pas – Test Plugin Interface
    • TestForm.pas (*.dfm) – Test Form (MDI Child).

Here are some listings.

I have problem with

procedure TMainForm.RefreshPluginsList;
var
  Pair: TPair<string, TMenuItem>;
  I: integer;
begin
  for I := 0 to ClassManager.Count - 1 do
    RegisterPlugin(ClassManager[i]);
  for Pair in MenuDict do
    Pair.Value.Visible := Pair.Value.Count > 0;
end;

where ClassManager.Count is always zero, so RegisterPlugin is never called. What should I do to make it 1 and to register my plugin properly?

EDIT: I removed Handles.Add(LoadPackage('PluginInterface.bpl')) as suggested. This didn't help. I see 2 instances of Manager when tracing program.

Was it helpful?

Solution

Looks like you made your EXE without using BPLs - either "Use Runtime Packages" is off, or common shared PluginInterface package is not in "Required" list.

Another possible (but less probable) reason is using weak packaging - which also mean that UClassManager unit (including extra instances of ClassManager function and variable) would be copied into every binary. http://docwiki.embarcadero.com/RADStudio/XE5/en/Using_the_Weak_Packaging_Directive

You can not and should not load that package dynamically - because the link to UClassManager should be made in compile-time already. Hence LoadPackage('PluginInterface.bpl') is redundant at best and breaking at worst and should be removed.

I think you did not do it, so now you have TWO instances of ClassManager - one in EXE and another in DLL. You can check for it issuing commands like

ShowMessage(IntToHex(Integer(Pointer(ClassManager()))))

in EXE and both BPLs and seeing what those instances really were.

Read manual or some Delphi textbook about using Runtime Packages. Few examples:

After properly bulding your project you can check whether your EXE actually make use of unit UClassManager from the BPL rather than making its own independent clone of it.

You can look into imported functions table and DLL dependency tree of the EXE, so to see whether EXE really does call UClassManager initialization function from the proper BPL. Some programs allowing doing this:

One more option is to use "Project / Analyze" command from Delphi IDE menu and check "show packages" option to see which binary file contains which unit. You can find this command after installing Project Analyzer package which is part of Jedi CodeLib as http://jcl.sf.net


PS. Since you use XE2, i suggest you to avoid using TList with binary pointers and dangerous unchecked typecasts. You better base your TClassManager upon good old TClassList (already existed in Delphi 5 and maybe even earlier) or upon TList<TPlugin>

PPS. Since you're using XE2 and dynamically loading/unloading BPLs, avoid in your packages constants (or pre-initialized variables) of array [...] of string type. They are being destroyed. I have some ideas why that might happen and how it was fixed in XE3/4 but am somewhat lazy to implement a patch. I just switched to array [....] of PChar constants for that matter.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top