Managing Plugin Instances (Delphi)

The key component of a Hydra host application is the module manager. For VCL projects you can use the THYModuleManager component and for FireMonkey the THYFMXModuleManager.

These components provide several methods that allow you to manage plugin instances, so let's take a look at these.

Creating new instances

The module manager has three different methods to create a new instance of the plugin:

  • CreateInstance - Creates an instance of the plugin with the specified name and returns a reference to an IInterface.
  • CreateVisualPlugin - Creates an instance of the visual plugin with the specified name and returns a reference to the IHYVCLVisualPlugin. It can also automatically show the plugin in the provided container.
  • CreateNonVisualPlugin - Creates an instance of a non-visual plugin with the specified name and returns a reference to the IHYVCLNonVisualPlugin.

The following example shows how to create an instance of a visual plugin:

TMainForm = class(TForm)
  [..]
  private
    fVisualPlugin: IHYVCLVisualPlugin;
  end;

[..]
procedure TMainForm.FormCreate(Sender: TObject);
begin
  ModuleManager.LoadModule('ModuleName.dll');
  ModuleManager.CreateVisualPlugin('VisualPluginName', fVisualPlugin, Panel1);
end;
TMainForm = class(TForm)
  [..]
  private
    fVisualPlugin: IHYFMXVisualPlugin;
  end;

[..]
procedure TMainForm.FormCreate(Sender: TObject);
begin
  ModuleManager.LoadModule('ModuleName.dll');
  ModuleManager.CreateVisualPlugin('VisualPluginName', fVisualPlugin, Panel1);
end;
TMainForm = class(TForm)
  [..]
  private
    fVisualPlugin: IHYCrossPlatformVisualPlugin;
  end;

[..]
procedure TMainForm.FormCreate(Sender: TObject);
var
  Temp: IInterface;
begin
  ModuleManager.LoadModule('ModuleName.dll');
  ModuleManager.CreateInstance('VisualPluginName', Temp);
  if Supports(Temp, IHYCrossPlatformVisualPlugin, fVisualPlugin) then
    fVisualPlugin.ShowParented(Panel1.Handle);
end;

You can do the same thing by using the CreateInstance method:

procedure TMainForm.FormCreate(Sender: TObject);
var
  Temp: IInterface;
begin
  ModuleManager.LoadModule('ModuleName.dll');
  ModuleManager.CreateInstance('VisualPluginName', Temp);
  if Supports(Temp, IHYVCLVisualPlugin, fVisualPlugin) then
    fVisualPlugin.ShowParented(Panel1);
end;
procedure TMainForm.FormCreate(Sender: TObject);
var
  Temp: IInterface;
begin
  ModuleManager.LoadModule('ModuleName.dll');
  ModuleManager.CreateInstance('VisualPluginName', Temp);
  if Supports(Temp, IHYFMXVisualPlugin, fVisualPlugin) then
    fVisualPlugin.ShowParented(Panel1);
end;
procedure TMainForm.FormCreate(Sender: TObject);
var
  Temp: IInterface;
begin
  ModuleManager.LoadModule('ModuleName.dll');
  ModuleManager.CreateInstance('VisualPluginName', Temp);
  if Supports(Temp, IHYCrossPlatformVisualPlugin, fVisualPlugin) then
    fVisualPlugin.ShowParented(Panel1.Handle);
end;

Lifetime

By default all Hydra plugins use reference counting to manage the plugin's life, and when the number of references reaches zero, the plugin and all of its resources are freed.

Hydra does not directly control the plugin's lifetime, so it's the job of the user's code to store the plugin's references to keep them alive. Take a look at the following code:

  TMainForm = class(TForm)
  [..]
  private
    fVisualPlugin: IHYVCLVisualPlugin;
  end;

  ModuleManager.CreateVisualPlugin('VisualPluginName', fVisualPlugin, Panel1);

In this snippet, we are using the fVisualPlugin field to store the reference to the plugin instance and keep the plugin alive.

Instance References

When you create a plugin, Hydra stores a weak reference to the instance. Since all those references are weak, they won't prevent the plugin from being destroyed. You can use them to get access to plugin instances in some scenarios, however, please keep in mind that they are not guaranteed to be alive, so use them with extreme caution.

  • property InstanceCount - Returns the number of instances
  • property Instances[Index] - Returns a reference (IHYVCLPlugin) with a specified index

For example:

var
  Resources: IMyCustomResources;
begin
  if Supports(ModuleManager.Instances[0], IMyCustomResources, Resources) then
    Resources.LoadResource('MyCustomResource');
end;

Tracking References

In some scenarios using a variable for a single instance isn't the best approach, so you need something that can help you track references.

Delphi provides a special class called TInterfaceList, which is designed to store a list of interfaces and manage their reference count properly.

For example:

TMainForm = class(TForm)
  [..]
  private
    fInterfaces: TInterfaceList;
  end;

[..]
procedure TMainForm.FormCreate(Sender: TObject);
begin
  fInterfaces := TInterfaceList.Create;
end;

procedure TMainForm.NewInstanceClick(Sender: TObject);
var
  Temp: IHYNonVisualPlugin;
begin
  ModuleManager.CreateNonVisualPlugin('NonVisualPluginName', Temp);
  fInterfaces.Add(Temp as IInterface);
end;

fInterfaces.Add will store the interface in the list and keep a reference to this instance until it is removed.

Destroying Instances

In general, "destroying an instance" means decreasing the reference count to zero. This can be done in a couple of ways:

  TMainForm = class(TForm)
  [..]
  private
    fVisualPlugin: IHYVisualPlugin;
  end;

{1} fVisualPlugin := nil;
{2} fVisualPlugin._Release;
{3} ModuleManager.ReleaseInstance(fVisualPlugin);
  1. Assign nil to an instance.
  2. Call the _Release method. The first and second method are doing exactly the same thing.
  3. Use the ReleaseInstance method of the module manager. This not only releases the instance, but also removes it from the internal list of instances.

All three ways are valid and can be used in your own applications, however, only when you use the ReleaseInstance method, it is guaranteed that the instance will be removed from the module manager's instance list.

Please note that you must release all instances of a plugin before unloading the module, otherwise Hydra will throw an exeption.