Introduction
In the .NET framework 3.5, you have a lot of functionality for writing your custom plug-ins of add-ins for your own application. In the .NET framework 2.0 you have not. I was searching a time on the Internet to find out how to do this. Finally I got something, but the description was not completely clear to me, so I figured out how to deal with this. In this post, I wrote in detail how to get your (host) application plug-in enabled. The sample enclosed is written on Visual Studio 2008
The idea is that you have your host application, you plug-in dll and in between an interface. I started with a simple host application, called ThePluginDemo.exe.This application has one form with a menu and a status bar on it. The plugin we will create, add a new menu option called "My Plugins" with a menu item under it called "Plugin Demo". Ok, let's start.
1. Pre-configuration of host application
On the "My Project"details, the
root namespace is edited to
PluginDemo.Presentation and the Output Path is changed to
..\Output\.
Note: All the projects in this solution will have the same output path, so you don't have to copy/paste the new dll's and stuff when you did a rebuild action.
2. Creating the interface
1. Add a new project to the solution:
An Empty Project was selected, the .NET Framework 2.0 option was selected in the drop down box on the top right corner of the window, and the project was called PluginInterfaces
2. On the "My Project" details , the
Root namespace is changed to
PluginDemo.Interfaces, the application type is changed to Class
Library and also the Output Path is changed to
..\Output\.
3. A new VB-class file was added and the default code was replaced to:
Imports System
Imports System.Windows.Forms
Public Interface IPlugin
Sub AddMenuItems(ByVal target As MenuStrip)
End Interface
The sub
AddMenuItems is the procedure that will be called later on to add the new menu item of the plugin.
Don't forget to add a reference to system.windows.forms.
4. On the project ThePluginDemo (= host application), add a reference to PluginInterfaces.
3. Create the Plug-in project
1. A new, empty project (on .NET framework 2.0) was added to the solution with the name
MyPlugin,
Root namespace PluginDemo.Plugins, Output Path
..\Output\.
2. References to
PluginInterfaces and
system.windows.forms were added.
3. A new VB-class file was added, called
MyFirstPlugin. The code of the file was edited so it looks like:
Imports PluginDemo.PluginInterfaces
Imports System.Windows.Forms
Public Class MyFirstPlugin
Implements IPlugin
Public Sub AddMenuItems( _
ByVal target As MenuStrip) _
Implements _
PluginInterfaces.IPlugin.AddMenuItems
End Sub
End Class
A procedure was added which will be called when pressing on the menu item created by this plugin:
Public Sub miPluginDemo_Clicked( _
ByVal sender As Object, _
ByVal e As EventArgs)
MessageBox.Show("Plugin Demo menu item clicked!")
End Sub
Note: the parameters sender and e are needed, otherwise the method does not have a signature compatible with delegate 'Delegate Sub EventHandler(...)'.
4. The following code was added to this class and is responsible for adding new menu options:
Private mainMenu As MenuStrip
Public Sub AddMenuItems( _
ByVal target As MenuStrip) _
Implements PluginInterfaces.IPlugin.AddMenuItems
' Store target menu strip in a local variable
mainMenu = target
' Check if the report plugin menu item already exists
If Not mainMenu.Items.ContainsKey("miMyPluginDemo") Then
' Create the report plugin menu item
Dim reportMenu As New ToolStripMenuItem("My Plugins")
reportMenu.Name = "miMyPluginDemo"
mainMenu.Items.Add(reportMenu)
End If
' Create a ToolStripMenuItem as submenu item with an event
Dim mi As New ToolStripMenuItem
mi.Name = "miPluginDemo"
mi.Text = "Plugin Demo"
' Attach a handler that fires a procedure
AddHandler (mi.Click), AddressOf miPluginDemo_Clicked
' Add the toolstripmenuitem to the mainmenu/report
AddMenuItemToReportMenu(mi)
End Sub
' Procedure to add a ToolStripMenuItem to the mainmenu/report
' location.
Private Sub AddMenuItemToReportMenu( _
ByVal mi As ToolStripMenuItem)
Dim tsmi As ToolStripMenuItem
tsmi = CType(mainMenu.Items.Item("miMyPluginDemo") _
, ToolStripMenuItem)
tsmi.DropDownItems.Add(mi)
End Sub
4. Create a plug-in XML file
To load the plugin dynamically, a XML file will be created that lists the available plugins. In this example, just one plugin dll.
1. A new
XML file was added to the
MyPlugin project and is called
PluginList.xml
2. The content was edited, so it looks like:
1
PluginDemo.Plugins.MyFirstPlugin
MyPlugin
ID: a sequence number and should be unique when you have more than one plugin you want to use.
Type: the namespace of the MyPlugin project followed by the class name that contains the plugin functionality you want to use.
File: the name of the file created by building the MyPlugin project (without extension).
3. The file properties of this XML file were edited to:
Build action = None; Copy to Output Directory = Copy Always
5. Load plugin in host application
Finally, we edit the host application so it will load the plugin dynamically.
1. Imports to the
PluginInterface and to system.reflection were added:
Imports PluginDemo.PluginInterfaces
Imports System.Reflection
2. A
new dataset object was added with filename
Plugins.xsd.
A DataTable was added and named PluginTool (see also the tag in the xml file)
Three columns were added:
* Name: ID; DataType: System.Int32; Unique: True
* Name: Type; DataType: System.String
* Name: File; DataType: System.String
3. On the mainform, two private variable were declared to hold the content of the XML document as created in step 4.
Private pluginXml As Plugins
Private pluginList As ArrayList
4. Finally, a procedure was added to load the plugin(s). The call to this procedure was placed in the form onload event.
Private Sub LoadPlugins()
' Create a new instance of the plugins
pluginXml = New Plugins
Try
' Try to load the XML file with the
' available(plugin(s)) information
pluginXml.ReadXml("PluginList.xml")
' Create a new instance of an ArrayList
Me.pluginList = New ArrayList
' Step through all available PluginTools,
' read from the XML file and add them to
' the(ArrayList)
Dim r As Plugins.PluginToolRow
For Each r In pluginXml.PluginTool
Dim a As Assembly = Assembly.Load(r.File)
Dim t As Type = a.GetType(r.Type)
Dim p As IPlugin = _
CType(Activator.CreateInstance(t) _
, IPlugin)
Me.pluginList.Add(p)
Next
For Each o As Object In Me.pluginList
Dim p As IPlugin = DirectCast(o, IPlugin)
p.AddMenuItems(Me.MainMenu)
Next
' Show statusbar message when plugin(s)
' is (are) (succesfully) loaded
tsStatus1.Text = "Plugin(s) loaded."
Catch ex As Exception
' Show statusbar message when loading
' plugin(s) failed
tsStatus1.Text = "Plugin(s) not loaded."
End Try
End Sub
5. This is it! We are done. Running the application shows the plugin loaded.
The complete solution can you download here:
ThePluginDemo.zip.
Good luck!