全部博文(230)
分类: 项目管理
2010-05-23 21:36:40
Plugins are pieces of code (often ATLs or .NET DLLs) that intergrate with a host application, by being in a certain folder or being registrated, and has (partial) control of the execution of the host program.
A very good example of a program that uses plugins is the Microsoft development environment. VB.NET, C++, Crystal Reports, and maybe other programs installed into that environment are basicly plugins. They are loaded when the environment is started and then they can do their thing (adding menu items, adding project types, loading itself...). MDE (Microsoft development environment) is a good example of a plugin-based application. When you should remove all the plugins (Crystal Reports, VB.NET...) and start it, it would just show an empty form.
Not all plugins are meant to change the whole host that much as in MDE. Sometimes, plugins are just for simple routines. For example, take milkshape3d. Milkshape3d is a 3d model editor; milkshape3d plugins can add new "save as.. filetypes".
Making a plugin framework isn't hard. It is very easy, when you do it right. Before you can make it, you must make a plan for it. What has it got to do, what do I want it to let do... These are the plugin framework types you can consider:
There is a big difference. Making a small plugin framework that just adds a new option in, for example, a menu is not hard to program, but it keeps plugins very limited. It also requires much less coding, and there aren't many things to go wrong.
Here is an example of a small plugin framework (note that I left big gaps; that's because it is meant as an example, written in VB 6).
'code for the mainform of an application
sub LoadPlugins
'this will be the sub launched when the plugins have to load
dim plugins as new collection
plugins = getdllsfromfolder (app.path + "\plugins")
'I won't write down this function because it has nothing to do
'with plugins
dim plugp as string
dim plug as object
for each plugp in plugins
set plug = createobject (getbasename(plugp) + ".pluginmain")
'creates an instance of the pluginmain class in the plugin dll.
plug.addmenuitems (me) 'will let the plugin be able to run the
'addmenu item sub in this form by
'passing the object reference
next
end sub
sub addmenu(caption as string, key as string)
'this sub is run by a plugin when it wants to create a menu.
redim preserve MNUPlugins(ubound(MNUPlugins)+1)
set MNUPlugins(ubound(MNUPlugins) = new menuitem
MNUPlugins.caption = caption
MNUPlugins.tag = key 'this is the key used to let the plugin
'know that the menu item is pressed
end sub
public sub MNUPlugins_click(index as long)
'This is just a copy of the previous code for getting the
'plugins. This isn`t a good way to do it
'The best way is to store it in arrays
dim plugins as new collection
plugins = getdllsfromfolder (app.path + "\plugins")
'I won't write down this function because it has nothing to do
'with plugins
dim plugp as string
dim plug as object
for each plugp in plugins
set plug = createobject (getbasename(plugp) + ".pluginmain")
'creates an instance of the pluginmain class in the plugin DLL.
plug.menuitempressed(MNUPlugins(index).tag)
'All plugins are warned that a menu item is pressed and the
'plugins which has made the menu item (which it can identify
'because it has left a key, which is now returned, can respond
next
end sub
'----CODE FOR THE PLUGIN DLL's class pluginmain----
public sub addmenuitems(host as object)
host.addmenu("Some menu caption", "somemnucpt")
end sub
public sub menuitempressed(menukey as string)
select case menukey
case "somemnucpt"
msgbox "pressed"
end select
end sub
As you can see, that plugin framework does its job, but is very static.
Here is the code of a plugin of FL Studio. FL Studio is a program by Micheal Houston and me and may not be copied in any way. (The code is in VB.NET 2003.) As you can see, the plugins have more room, but still can't do everything.
Imports System.Windows.Forms
Public Class myPlugin
Implements FLStudio.IFLStudioPlugin
Private studio As FLStudio.IFLStudio
Private myMenu As MenuItem
Private myTab As TabPage
Public Sub initialize(ByVal FLStudio As FLStudio.IFLStudio) _
Implements FLStudio.IFLStudioPlugin.initialize
studio = FLStudio
myMenu = New MenuItem("Test Plugin")
studio.addMenu(myMenu)
myTab = New TabPage("Test Tab")
studio.addTab(myTab)
End Sub
Public Function pluginName() As String Implements _
FLStudio.IFLStudioPlugin.pluginName
Return "myPlugin"
End Function
Public Function description() As String Implements _
FLStudio.IFLStudioPlugin.description
Return "An example FLStudio Plugin"
End Function
Public Sub unload() Implements FLStudio.IFLStudioPlugin.unload
studio.removeMenu(myMenu)
studio.removeTab(myTab)
End Sub
Public ReadOnly Property MustLoad() As Boolean _
Implements FLStudio.IFLStudioPlugin.MustLoad
Get
Return False
End Get
End Property
Public ReadOnly Property Invalid() As Boolean _
Implements FLStudio.IFLStudioPlugin.Invalid
Get
Return False
End Get
End Property
Public Property configuration() As FLStudio.PluginConfiguration _
Implements FLStudio.IFLStudioPlugin.configuration
Get
End Get
Set(ByVal Value As FLStudio.PluginConfiguration)
End Set
End Property
End Class
There can be as many plugin classes in a dotnet assembly that is put in the plugin folder as you want. They will be recognized as a plugin when they use the IFLStudioPlugin interface. The plugin host's plugin loader isn't included. If you want to take a look at it, e-mail me .
A really good plugin framework should have the following things:
I have made, with some other programmers, a few plugin frameworks that are based on this principle. The big advantage is flexibility; the disadvantage is the big chance that coders aren't going to use this right, and make it impossible for themselves.
The first one I made was in Visual Basic 6.0. It uses ActiveX DLLs as plugins. You can find the code, and download .
The second one I made is made in Visual Basic.NET, and uses .NET assemblies as plugins. I will only give the interfaces used by the pluginframework host and of the plugins:
This code is copyrighted
'plugin interfaces, and classes used as interface.
'this is almost complete and shouldn't change in later versions
Public Interface UMSPlugin
'info part
Function getinfo() As Collection
Sub setinfo(ByVal info As Collection)
'registration part and unload part
Sub registerplugin(ByVal host As UMSHost)
Sub unloadplugin()
'interaction part
Function msgpriority(ByVal key As String) As Long
Sub message(ByVal key As String, Optional ByVal _
parameters As Collection = Nothing)
End Interface
Public Interface UMSHost
'info part
Function getinfo() As Collection
'plugins
Overloads Sub AddPlugin(ByVal PluginInterface As UMSPlugin)
Overloads Sub AddPlugin(ByVal Path As String, Optional ByVal _
PluginKey As String = "*")
Overloads Sub AddPlugin(ByVal key As String, ByVal _
PluginInstance As Object, Optional ByVal priority _
As Long = 0)
Function GetPlugin(ByVal key As String) As UMSPlugin
Function GetPlugins() As Collection
Sub RemovePlugin(ByVal key As String)
'shared objects
Overloads Sub AddSharedObject(ByVal obj As Object,_
ByVal key As String, _
Optional ByVal priority _
As Long = 0, _
Optional ByVal extrainfo As _
Collection = Nothing)
Overloads Sub AddSharedObject(ByVal sharedobject As SharedObject)
Function GetSharedObject_Wrapper(ByVal key As String) _
As SharedObject
Function GetSharedObject(ByVal key As String) As Object
Function GetSharedObjects() As SharedObject()
Sub RemoveSharedObject(ByVal key As String)
'Global values
Overloads Sub AddGlobalValue(ByVal GlobalValue As GlobalValue)
Overloads Sub AddGlobalValue(ByVal key As String, _
ByVal value As Object, _
Optional ByVal priority As Long = 0)
Function GetGlobalValue(ByVal key As String) As GlobalValue
Sub RemoveGlobalValue(ByVal key As String)
'plugin communication
Sub Message(ByVal key As String, _
Optional ByVal parameters As Collection = Nothing, _
Optional ByVal prioritybound As Boolean = False)
End Interface
Public Class SharedObject
'info
Public key As String
Public priority As Long
'additional, for extra info about this shared object
Public info As Collection
'object itself
Public obj As Object
End Class
Public Class GlobalValue
'info
Public key As String
Public priority As Long
Public value As Object
End Class
A few other programmers and I are going to make a Universal Modding Studio with this plugin framework.
Here are some basic principles about how a plugin should work: