More than one instance of the same plugin

Can you create and use more than one instance of the same plugin? If so, what is the best way to implement this? Is it best to have a single plugin ModuleManager that contains all instances of the same plugin, or do you need a separate ModuleManager for each instance of the plugin?

Background: I have a Delphi XE5 plugin that encapsulates a CAD-like design tool, and we are embedding this plugin into a C# Winforms app. The Winform app uses the CAD tool plugin to create a quote for the product that was designed in the CAD plugin. You can have multiple quotes open in the Winforms app with each quote having its own instance of the CAD design tool plugin. What is the best way to implement this in the code?

Option 1: Have a singleton design pattern that wraps a single ModuleManager that handles creating multiple instances of the same CAD design tool plugin. Does this even work, and if so, how would I uniquely identify each instance of the same CAD plugin?

Option 2: Each instance of the CAD plugin has its own ModuleManager to which it is the only plugin contained in the ModuleManger.

Thank you.

Yes, you can create multiple instance of the same plugin. So “option 1” will work.

As for identifying instances, we don’t have any built-in mechanism to do so, but you can do this manually using custom interface that will allow to access to an ID field that you need to generate for every instance.

Thank you ejay for your response. I have implemented option 1 above, but now I’m getting some strange behavior when I have two instances of the same plugin created. If I click on buttons in the first plugin instance that create a new CAD object, the new CAD object actually shows up visually in the second plugin instance, but not in the first instance. It appears that the two instances are sharing code. See the attached screenshots.

Do you have any insight as to how this is happening?

My code is currently structured to have a singleton object that manages creating and tracking the multiple instances of the Delphi CAD plugin. I call “ModuleManager.LoadModule()” one time to load the CAD plugin DLL, and then I call “ModuleManager.CreateInstance()” every time I need a new instance of the plugin created (which is then displayed in its own user control and Hydra HostPanel control. Here’s the code:

From within the user control that contains the Hydra Host Panel:

public void LoadSmartDesignPlugin()
{
    if (_PluginInstance != null) return;

    this._PluginInstance = SmartDesignPluginMgr.Instance.GetPlugin(this._PluginInstanceId);
    if (_PluginInstance != null)
        this.PluginHostPanel.HostPlugin(_PluginInstance as IBasePlugin);
}

From the SmartDesignPluginMgr singleton class:

public IHYCrossPlatformPlugin GetPlugin(Guid instanceId)
{
    IHYCrossPlatformPlugin result = null;
    if (this._MyPluginInstances.TryGetValue(instanceId, out result) == false)
    {
        result = this.CreateNewPlugin();
        if (result != null)
            this._MyPluginInstances.Add(instanceId, result);
    }
    return result;
}

private IHYCrossPlatformPlugin CreateNewPlugin()
{
    IHYCrossPlatformPlugin newPlugin = null;
    // Load the plugin DLL if needed.
    if (this._PluginModuleManager.Modules.Count <= 0)
    {
        string sdPluginDllPath = SQ2.DataAccess.DataPaths.SmartDesignPluginDllPath;
        if (System.IO.File.Exists(sdPluginDllPath))
        {
            this._PluginModuleManager.LoadModule(sdPluginDllPath);
        }
    }
    foreach (PluginDescriptor p in this._PluginModuleManager.Plugins)
    {
        newPlugin = this._PluginModuleManager.CreateInstance(p as PluginDescriptor);
        if (newPlugin != null)
            break;
    }
    return newPlugin;
}


Can “this._PluginInstanceId” be the same for multiple instances? In this case you won’t create a new instance but just show an existing one in the different host panel which is wrong.

I’ve just tried this approach with a small sample and it works fine for me, i’ve attached it to this comment so you can take a look.

MultiInstance.zip (15.8 KB)

Thank you for your example project. Your suggestion of checking “this._PluginInstanceId” was my first thought also, but it was being used correctly. But just to be sure, I took your example project and replaced your Delphi plugin with my CAD tool plugin, and I see the same behavior as I outlined above in my previous post.

After some debugging, it appears that global variables defined in the Delphi plugin are shared across multiple instances of the created plugins. For example, in my application, I define a global variable “MainFormPanel” that stores a TFrame control for the main user interface. In this way, the global “MainFormPanel” can be accessed from anywhere in the program to launch certain features or refresh the map area. When a new instance of the plugin is created, this “MainFormPanel” variable gets set to the new plugin’s main TFrame control, but since the “MainFormPanel” variable is being shared across all plugins, you get the strange behavior above where you perform actions in the first plugin instance, but the results show up in the UI of the second plugin. And it’s because the first plugin is using the “MainFormPanel” variable which is actually pointing to the second plugin’s main TFrame control.

Is the sharing of global variables across multiple plugin instances an intended functionality of the Hydra component? And if so, is there a way around it?

I will try and post a simple example project that shows this behavior, but I wanted to get your feedback as soon as I could. Thank again for your time.

Yes global variables can be accessed by all plugin instances from a module, but It is not really related to Hydra, you can think about plugin module as it was standard dll. In order to workaround this problem you’ll need a custom mechanism to store store and share this controls, something like a global list or dictionary.

Thank you ejay for your quick response. That helps explain my issue.

Ejay - Would it be a feasible workaround to create multiple copies of the plugin DLL, and then load a separate DLL for each time I needed a new instance of the plugin? For example in this case above, I would create say 3 copies of the “SmartDesignPlugin.DLL” file. ie: “SmartDesignPlugin1.DLL”, “SmartDesignPlugin2.DLL”, “SmartDesignPlugin3.DLL”. And then within the C# app, I just limit the number of plugin instances to 3, and load whichever one is available if a new instance of the plugin is needed. I realize that this may not be the most elegant fix, but would it work? Thank you again.

This won’t work because all these modules will have plugin with the same name.

My idea was to create 3 separate Hydra plugin projects within XE5 with each one having a different name. Each project would be identical except for its name. Would this work?

Yes, this should work.