Click here to Skip to main content
15,860,861 members
Articles / Programming Languages / C#
Article

Plugins Manager

Rate me:
Please Sign up or sign in to vote.
4.00/5 (6 votes)
22 May 2008CPOL3 min read 50.3K   1.9K   62   9
A plugins manager class to manage a plugins structure

Introduction

The extension of the application functionality is managed through the use of plugins. I used different methods with different frameworks, and now I have come to. NET. I've created a library that performs the following tasks:

  • Load the plugins definitions through an XML file
  • Load and initialize the plugin object
  • Call the object at the end for resetting the plugin data

The project is developed with SharpDevelop.

Plugins Interface Description

The plugin object interface is defined as follows:

C#
public interface ILBPlugin
{
  bool Initialize ();
  bool Release    ();
}

This is the interface that must be implemented by the plugin to be loaded. The methods are:

  • Initialize() - This method is called when the object is loaded from the plugin manager within the method LoadPlugin().
  • Release() - This method is called when the plugin manager removes the object from the list with the method UnloadPlugin().

With this interface, we can implement any kind of plugin, which can be loaded from the plugins manager. To have added functionality, you can implement in the object the interfaces defined by the application.

Definitions File

The definitions file is used from the plugins manager to get the plugins definitions for loading the assembly and getting other information. The structure of this file is as follows:

  • <Plugins> - Root node
    • <Plugin> - Node for the plugin attribute. In this node, the following attributes should be defined:
      • Name - Attribute for defining the name of the plugin. This is used for loading the plugin
      • Path - Path of the plugin assembly relative to the PluginPath properties of the plugins manager
      • Assembly - Name of the assembly to load
      • Version - Version of the plugin object
      • ObjectName - Name of the object with namespace

An example is:

XML
<?xml version="1.0"?>
<Plugins>
  <Plugin Name="Test1"
           Path="Test1"
           Assembly="Test1.dll"
           Version="1.0"
           ObjectName="Test1.Test1Plugin"/>
</Plugins>

This definition will be encapsulated in an object of type Plugin. All these objects are added in a list in the plugins manager and it is possible to get this list from the manager

Plugins Manager

The plugins manager core is implemented in the class PluginsManager and is used for all aspects of plugins management. This class has the following properties and methods:

Properties

  • DefinitionsFile - Is used to set the plugins definitions file. By default, the file is 'Plugins.xml' and is located in the same folder of the application
  • Provider - Is used to set an object of type ILBPluginManager for redirecting the messages of the manager when running operations
  • PluginsPath - Main path of the plugins library relative to the application path
  • LastMessaggeError - Last occurred message string
  • Plugins - Array of the plugins definitions
  • PluginsObjects - Array of the loaded plugins objects
  • ShowMessages - Flag to enable the visibility of the messages

Methods

  • GetPlugin - Is used for requesting a plugin object from the plugin name. Returns an object of type Plugin
  • LoadPlugin - Is used for loading a plugin object. Returns an object of type ILBPlugin
  • UnloadPlugin - Is used for unloading a plugin object
  • LoadPluginsConfig - Is used for loading the definitions file

Example

In the download zip, there is an example on how to use the library to load a plugin that returns control to be included in the main application form. For the application interfaces, create a library that contains only the interface definition. You can use the library from other plugins that can be loaded from the application. The main steps are as follows:

  • Create an instance of PluginsManager in the main form
  • Load the definitions file in the constructor of the main form or when the form is loaded
  • Load the plugin/s when the form is loaded or with a command
  • Unload the plugins with a command, or when the application is closed
C#
//---------------------------------------------------
// Main form
//---------------------------------------------------
using System;
using System.IO;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using LBSoft.PluginManager;
using TestInterface;

namespace PluginTest
{
public partial class MainForm : Form
                              , ILBPluginsManager
                              , ITestProvider
{
  private PluginsManager piMng = new PluginsManager();
  private ILBPlugin      pi    = null;

  public MainForm()
  {
    InitializeComponent();

    piMng.Provider = this;
    piMng.ShowMessages = false;
    piMng.LoadPluginsConfig ();
  }

  void menuExit_Click(object sender, EventArgs e)
  {
    this.piMng.UnloadPlugin ( this.pi );
    this.Close();
  }

  void menuLoadPlugin_Click(object sender, EventArgs e)
  {
    this.pi = piMng.LoadPlugin ( "Test1");
    if ( this.pi == null )
      return;

    ITestInterface piTest = pi as ITestInterface;

    piTest.Provider = this;
    Control ctrl = piTest.PluginControl;

    ctrl.Dock = System.Windows.Forms.DockStyle.Fill;
    ctrl.Location = new System.Drawing.Point(0, 24);
    ctrl.Name = "test1Control";
    ctrl.Size = new System.Drawing.Size(510, 314);
    ctrl.TabIndex = 0;

    this.panelCtrl.Controls.Add ( piTest.PluginControl );
  }

  public void OutputMessage( string message, bool addEndLine )
  {
    this.OutputMessage ( message, addEndLine, MessageType.Normal );
  }

  public void OutputMessage( string message, bool addEndLine, MessageType type )
  {
    MessageBoxIcon mi = MessageBoxIcon.None;
    switch ( type )
    {
      case MessageType.Error:
        mi = MessageBoxIcon.Error;
        break;

      case MessageType.Warning:
        mi = MessageBoxIcon.Warning;
        break;                        
    }

    MessageBox.Show ( message, this.GetType().Name, MessageBoxButtons.OK, mi );       
  }

  public void Message( string msg )
  {
    this.OutputMessage ( msg, false );
  }
}

//---------------------------------------------------
// TestInterface.dll
//---------------------------------------------------
using System;
using System.Windows.Forms;

namespace TestInterface
{
  public interface ITestProvider
  {
    void Message ( string msg );
  }

  public interface ITestInterface
  {
    Control PluginControl { get; }
    ITestProvider Provider { set; get; }
  }
}

//---------------------------------------------------
// Plugin
//---------------------------------------------------
using System;
using System.Windows.Forms;
using LBSoft.PluginManager;
using TestInterface;

namespace Test1
{
  public class Test1Plugin : ILBPlugin
                           , ITestInterface
  {
    private Test1Control  control  = new Test1Control();
    private ITestProvider provider = null;

    public Test1Plugin()
    {
    }

    public bool Initialize()
    {
      return true;
    }

    public bool Release()
    {            
      return true;
    }

    public Control PluginControl 
    { 
      get { return this.control; }
    }

    public ITestProvider Provider 
    { 
      set { this.provider = value; this.control.Provider = value; }
      get { return this.provider; }
    }
  }

  public partial class Test1Control : UserControl
  {
    private ITestProvider provider = null;

    public Test1Control()
    {
      InitializeComponent();
    }

    public ITestProvider Provider 
    { 
      set { this.provider = value; }
      get { return this.provider; }
    }

    void btnCheck_Click(object sender, EventArgs e)
    {
      if ( this.Provider != null )
        this.Provider.Message ( "Click on Test1 plugin" );
    }
  }
}

Conclusion

I know this is a simple approach to management with a plugin of an application but it can be a basis for the extension of applications using external modules. Any constructive criticism or help to improve the code will be appreciated.

History

  • 1.0 (22 May 2008)
    • Initial release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Promax Srl
Italy Italy
Software developer with over 16 years of experience, specializing on MFC/C++, C# and software architecture


Company : Promax S.r.l.


Comments and Discussions

 
Questioncompile error Pin
Cool Smith12-Feb-12 9:30
Cool Smith12-Feb-12 9:30 
GeneralYou may want to take a look at SCSF Pin
Magnus Werner26-May-08 20:44
Magnus Werner26-May-08 20:44 
GeneralRe: You may want to take a look at SCSF Pin
Luca Bonotto26-May-08 23:15
Luca Bonotto26-May-08 23:15 
GeneralAdd-In Framework Pin
Keith Malwitz23-May-08 19:34
Keith Malwitz23-May-08 19:34 
GeneralRe: Add-In Framework Pin
Luca Bonotto23-May-08 21:30
Luca Bonotto23-May-08 21:30 
Questionyour plug-in architectue and AppDomains ? Pin
BillWoodruff22-May-08 13:11
professionalBillWoodruff22-May-08 13:11 
AnswerRe: your plug-in architectue and AppDomains ? Pin
Luca Bonotto22-May-08 19:49
Luca Bonotto22-May-08 19:49 
GeneralRe: your plug-in architectue and AppDomains ? Pin
Andreas Kroll27-May-08 1:16
Andreas Kroll27-May-08 1:16 
GeneralRe: your plug-in architectue and AppDomains ? Pin
Luca Bonotto27-May-08 2:30
Luca Bonotto27-May-08 2:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.