Steve said:
Kind of a strange question... I have a VB.NET 2.0 solution containing
a main project (my EXE) and a number of other projects (class DLLs)
that are "plug-ins" to the main app. These plugins get installed
depending on each user's requirements.
I'd like to implement a function in one plugin that only executes if
another plugin is present. Typically, for one plugin to access a
second plugin, I need to set a reference at design-time to the second
project within the first project. However, to create this new
function, I can't be sure the second plugin will exist. I want to
determine the existence of the second plugin (DLL) at run-time, and if
present, create a reference to it that will allow the first plugin to
access functionality within the second.
For a plug in type app, each plug in should reference a plugin
*interface* and not the plugin it self. That way the plugin that
depends on another plugin need not reference the particular dll of the
other plugin. It just references the Interface. It would then, as
Ghost said, ask the host app (probably through another interface) if
the other plugin is installed. And if so, access it through the
interface. One other consideration is the order in which the plugins
are loaded. To me it would be safer to not start the plugins until
they are all loaded by the host. Or at least when the first plugin
requests the other plugin, if it is not loaded yet by the host, the
host can load it right then. (Did *that* make sense?)
Perhaps some pseudo code would help. The Host app implements the IHost
interface. Which has a GetPlugin method (it may have more methods).
It then looks in some folder on the hard drive or perhaps checks a
config file to find out where the plugin assemblies are located and
loads each one, adds it to the list of loaded plugins, and then calls
its execute method to start it. It passes in a reference to itself
(IHost) to each plugin.
Inside the plugin, if it needs services from the host, it can use the
IHost interface to call methods or make requests of the host. The code
below is pretty crude. You would need to make sure that it is safe for
each plugin to call the host at the same time or otherwise coordinate
access by each plugin.
HostInterface:
Public Interface IHost
Public Function GetPlugin(pluginName As String) As IPlugin
End Interface
PlugInInterface:
Public Interface IPlugin
Dim PluginName As String
Public Sub Execute(host As IHost)
'Add other methods here
End Interface
HostInterface and PluginInterface could reside in the same assembly.
Plugins:
'PluginOne.dll
'PluginOne only needs to reference the interface IPlugin assembly
Public Class PluginOne : Implements IPlugin
Dim PluginName As String
Private _host As IHost
Public Sub New()
PluginName = "Plugin1"
End Sub
Public Sub Execute(host As IHost) Implements IPlugin.Execute
_host = host
End Sub
End Class
'PluginTwo.dll
'Plugin 2 needs to see if Plugin1 is loaded but it still only needs
'to referecne IPlugin assembly and not the actual plugin dll
Public Class PluginTwo : Implements IPlugin
Dim PluginName As String
Private _host As IHost
Public Sub New()
PluginName = "Plugin2"
End Sub
Public Sub Execute(host As IHost) Implements IPlugin.Execute
_host = host
'Find out if the other plugin is loaded. This should probably
be a parameter in
'a config file in case the name of Plugin1 ever changes.
IPlugin plugin1 = _host.GetPlugin("Plugin1")
If plugin1 IsNot Nothing Then
'Do something with the other plugin here
End If
End Sub
End Class
'Host App
Public Class Host : Implements IHost
Public Shared Sub Main(args() As String)
Dim _instance As New Host()
_instance.Execute()
End Sub
'Check my generics syntax
Private _plugins As Dictionary(Of String, Of IPlugin)
Public Sub New()
_plugins = New Dictionary(Of String, Of IPlugin)()
End Sub
Public Sub Execute()
'Run the host here
LoadPlugins() 'Loads the plugins into its dictionary
End Sub
Public Function GetPlugin(name As String) As IPlugin
If _plugins.ContainsKey(name) Then
Return _plugins(name)
Else
'plugin not found in our list
'Try to load it here and if successful, return it else
return Nothing
End If
End Function
Private Sub LoadPlugins()
'populate the _plugins dictionary
For Each Dll In Some Folder
IPlugin p = Activator.CreateInstance() 'Creates an
instance of the plugin
_plugins.Add(p.PluginName, p) 'Add the plugin to our
list
p.Execute(Me) 'Execute the plugin, pass in the IHost
Next
End Sub
End Class
Whew! That was pretty long winded, but hopefully you will glean
something good from it! This is not necessarily the *only* way to
implement a plugin type architecture, but it should give you some
ideas.
Good Luck
Chris