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:
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:
="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 operationsPluginsPath
- 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
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 );
}
}
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; }
}
}
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