Library tutorials & articles
Writing Plugin-Based Applications
- Introduction
- The Interfaces & First Plugin
- The Host Application
- Wrapping Up
The Host Application
We create a new project, of type Windows Application. The first thing to do is reference the class library we just created, and set the build output to the same directory.
The main content of this article is the process of examining DLLs to see if they contain plugins, storing the information about what plugins are available, and instantiating and using them. To do this, I will provide a class, PluginServices.vb, which will encapsulate all these things.
To get our list of plugins, we use the function FindPlugins which accepts a string containing the directory to search in, and a string with the full name of the interface we're looking for classes that implement. This function enumerates over all files with the extension .dll in the directory supplied, loads them using Assembly.LoadFrom() and passes execution to another function to examine the assembly.
Public Shared Function FindPlugins(ByVal strPath As String, ByVal strInterface As _
String) As AvailablePlugin()
Dim Plugins As ArrayList = New ArrayList()
Dim strDLLs() As String, intIndex As Integer
Dim objDLL As [Assembly]
'Go through all DLLs in the directory, attempting to load them
strDLLs = Directory.GetFileSystemEntries(strPath, "*.dll")
For intIndex = 0 To strDLLs.Length - 1
Try
objDLL = [Assembly].LoadFrom(strDLLs(intIndex))
ExamineAssembly(objDLL, strInterface, Plugins)
Catch e As Exception
'Error loading DLL, we don't need to do anything special
End Try
Next
'Return all plugins found
Dim Results(Plugins.Count - 1) As AvailablePlugin
If Plugins.Count <> 0 Then
Plugins.CopyTo(Results)
Return Results
Else
Return Nothing
End If
End Function
Once all files have been examined, the function returns an array of type AvailablePlugin if some were found, or Nothing if none were found. As you can see, this function calls ExamineAssembly to inspect a loaded assembly.
The ExamineAssembly function enumerates all types exported by the loaded assembly, and uses the GetInterface() method of each type to see if it implements our interface. Conveniently, this method takes a string containing the fully qualified name of the interface. In this case, it's "PluginSample.Interfaces.IPlugin" we're looking for. If a type is found that implements the interface, an entry is added to the ArrayList with the full path of the DLL and the full name of the class.
Private Shared Sub ExamineAssembly(ByVal objDLL As [Assembly], _
ByVal strInterface As String, ByVal Plugins As ArrayList)
Dim objType As Type
Dim objInterface As Type
Dim Plugin As AvailablePlugin
'Loop through each type in the DLL
For Each objType In objDLL.GetTypes
'Only look at public types
If objType.IsPublic = True Then
'Ignore abstract classes
If Not ((objType.Attributes And TypeAttributes.Abstract) = _
TypeAttributes.Abstract) Then
'See if this type implements our interface
objInterface = objType.GetInterface(strInterface, True)
If Not (objInterface Is Nothing) Then
'It does
Plugin = New AvailablePlugin()
Plugin.AssemblyPath = objDLL.Location
Plugin.ClassName = objType.FullName
Plugins.Add(Plugin)
End If
End If
End If
Next
End Sub
Lastly, we write the function that will be used to create an instance of a plugin where needed. It accepts an AvailablePlugin structure and returns an Object, to be casted to the appropriate type by the calling procedure.
Public Shared Function CreateInstance(ByVal Plugin As AvailablePlugin) As Object
Dim objDLL As [Assembly]
Dim objPlugin As Object
Try
'Load dll
objDLL = [Assembly].LoadFrom(Plugin.AssemblyPath)
'Create and return class instance
objPlugin = objDLL.CreateInstance(Plugin.ClassName)
Catch e As Exception
Return Nothing
End Try
Return objPlugin
End Function
Related articles
Related discussion
-
How to write a query set to excel using vb.net
by BarbaMariolino (1 replies)
-
Very Urgent regarding deleting the images from a folder
by rameshbandi (2 replies)
-
Block Accessing MSSQL 2000
by militia (0 replies)
-
.NET Developer in Ghana Required....
by sysview (0 replies)
-
Sending SMS to mobile using secure gateway from VB.net 2008 c#
by pratikasthana17 (0 replies)
Related podcasts
-
xpert to Expert: Inside Concurrent Basic (CB)
"Concurrent Basic extends Visual Basic with stylish asynchronous concurrency constructs derived from the join calculus. Our design advances earlier MSRC work on Polyphonic C#, Comega and the Joins Library. Unlike its C# based predecessors, CB adopts a simple event-like syntax familiar to VB progr...
hi
when i run the host i found this error : Warning 1 Could not resolve this reference. Could not locate the assembly "Interfaces". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors. Plugin 1
"PluginSample.Interfaces.IPlugin" is not defined
can u help me to splve this problem
thanks
!--removed tag-->Just add event handlers to the menu items before returning from InitializeMenu, e.g.
[quote]menu1.Click += new EventHandler (nameOfCallbackFunction);[/quote]
I found a very easy way to add controls to the host.
Dim Menu As New ToolStrip
Dim menu1 As New ToolStripMenuItem("Plugin")
menu1.DropDown = CreateCheckImageContextMenuStrip("Calculate")
Menu.Items.Add(menu1)
Menu.Dock = DockStyle.Top
Return Menu
End Function
Me.ToolStripContainer1.TopToolStripPanel.Controls.Add(objPlugin.InitializeMenu)
The only thing i did not figure out yet is how to handle when you click on the control.
I rewrote your application in C# and everthing works except one thing.
After loading assembly and creating plugin instance I am casting plugin instance to plugin interface and I get excepion "Specified cast is not valid"
I have no idea what is wrong.
I needed the plug in functionality to swap and update plug-ins on a regular basis, for an ASP.Net application. However, it seems I must shut down the site completely to replace an existing plug-in with a new version...
Great article!
This will come in very handy with an application I have in mind
Just a note about using this in VB2005 (I'm using Express edition right now, hopefully I'll upgrade):
The CreateInstance method of the PluginServices works fine, and does return an instance of the class that can be used but only when put into an Object type.
You don't have the full list of functions and subroutines available to you using the object.
When using the DirectCast, to cast the instance to an variable declared as the Interface - it doesn't like that cast and throws an exception.
To fix this do what Prozac mentiond - change the references of [Assembly].LoadFrom() to [Assembly].LoadFile() and it works fine.
Thanks for the great article!
I think your article is great, i'm looking for it for months, and finally...
I just have a question:
If I want that a plugin add a button ont the host form, is it possible? can you help me please?
thanks in advance,
Ivan
The complete code is available in the source code, however I'll post it for you anyway.
Public Structure AvailablePlugin
Public AssemblyPath As String
Public ClassName As String
End Structure
Enjoy!
I noticed that when I used [Assembly].LoadFrom(), it kept on loading the first plugin that was initially loaded,
to fix this; use [Assembly].LoadFile() insted.
DotNet Framework 1.1, Visual Studio 2003, Visual Basic.NET.
I can't get AvailablePlugin to work. VB.NET reports that
"Type 'AvailablePlugin' is not defined." Has anyone else had this problem?
Hi.
I've been trying to find the way of doing an application with pluggable components over vb6, but have not found any help. I read the subject of this article and was very excited but when I realized it was about .net I got frustrated. Could you please explain me how it is possible to make a plugin-based app in vb6.
Thanx
malloc
This thread is for discussions of Writing Plugin-Based Applications.