Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1662077
  • 博文数量: 230
  • 博客积分: 10045
  • 博客等级: 上将
  • 技术积分: 3357
  • 用 户 组: 普通用户
  • 注册时间: 2006-12-30 20:40
文章分类

全部博文(230)

文章存档

2011年(7)

2010年(35)

2009年(62)

2008年(126)

我的朋友

分类: 项目管理

2010-05-23 21:36:40

Everything About Plugins



What Are Plugins?

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".

What Are the Advantages of Plugins?

  • They are very portable and easy to deploy. You have to put a DLL in the plugin folder, or register it with a .reg file.
  • They are small. Plugins are very small, but can pack enormous power.
  • And more, but that depends on the plugin framework that is used!

Making Your Own Plugin Framework

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:

  • A small plugin framework that lets plugins add one or a few new options. For example, new menu items in the 'export as' menu.
  • Medium scale plugin framework that lets the plugins add features to the host application, such as new forms, new menu items, and changing the host.
  • Big scale plugin framework. This has to be totaly plugin based, which means that the host just loads the plugins, and then lets the plugins do what they have to do.

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.

Small Plugin Framework

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.

Medium scale plugin framework

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 .

Big Scale Plugin Framework

A really good plugin framework should have the following things:

  • DLL as plugin library. A DLL has to be seen as a plugin library and not as a plugin itself.
  • Plugins must have priority and be overpowering. When there are two plugins with the same key, the one with the higher priority will survive. When building in that system, it will be very easy for plugin coders to even make mods in other plugins. This also makes it unnecessary to delete DLLs if there is a new version of a plugin. Just put the DLL in the plugin folder and the rest is done for you.
  • The host does nothing except load the plugins. All coding has to be done in plugins. By also using plugin overpowering, the application will be very easy to maintain.
  • Plugins should have total control of themselves and all other plugins. In that way, even the plugin loader can be 'modded' by plugins.
  • Plugins should be able to share and change objects. The plugin host should have a storage system for objects that are shared by plugins. These 'shared-objects' can be, for example, forms. These shared objects should also have a priority and be able to be overpowered by other shared-objects.
  • Plugins should be able to communicate with a message system. A plugin has to be able to send a message to all other plugins, where the other plugins can respond to. Or just to send that same message, but only let the plugin which returns the highest priority respond to that event/message.

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.

How Should a Plugin Work?

Here are some basic principles about how a plugin should work:

  • Use others' plugin resources. Don't rewrite a whole, for example, INI parser hardcoded in a plugin. Use the existing one or make a new plugin for it. This will make all plugins use one parser which makes the plugins easier to maintain.
  • Never depend to much on a plugin. Never try to depend to much on another plugin because that plugin can change in newer versions. Rather, try to use interfaces.

Links:


阅读(788) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~