正在加载

C#实现支持插件与二次开发的应用程序编写

| 2008年5月23日星期五

CreditDKMILAN副本这两天一直在研究这个插件功能的实现,总结一些心得吧。

首先是应该定义插件应该实现的接口,接口里面是插件需要实现的功能与提供的内容。我是这么设计的:

首先是建立一个新的类库,用于把我们支持的插件的类型都以接口的形式放进去。比如我现在为我的Service Master设计了以下几个插件类型:外观插件,功能插件,系统信息插件,其他类型插件。目前接口设计如下



然后在原有的软件项目(ServiceMaster)中添加了一个插件检测的类,这个类用于检测已经放到Plugin文件夹下的插件。
 
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.IO;
using System.Collections;
namespace ServiceMaster
{
public static class PluginCheck
{
public static IPluginMenu[] getAllPluginsMenu()
{
IPluginInfo[] plugins = getAllPluginsInfo();
List menus = new List();
foreach (IPluginInfo plugin in plugins)
{
if (plugin is IPluginMenu)
menus.Add((IPluginMenu)plugin);
}
return menus.ToArray();
}
public static IPluginInfo[] getAllPluginsInfo()
{
if (Directory.Exists(Directory.GetCurrentDirectory() + @"\Plugin"))
{
string[] files = Directory.GetFiles(Directory.GetCurrentDirectory() + @"\Plugin");
List dlls = new List();
foreach(string file in files)
{
FileInfo info = new FileInfo(file);
if (info.Extension == ".dll")
dlls.Add(getPluginClass(info.Name, "PluginInfo"));
}
return dlls.ToArray();
}
else
{
Directory.CreateDirectory(Directory.GetCurrentDirectory() + @"\Plugin");
return new IPluginInfo[0];
}
}
public static IPluginInfo getPluginClass(string filename,string className)
{
Assembly ass = null;
try
{
ass = Assembly.LoadFrom(@"plugin\" + filename);
}
catch (BadImageFormatException)
{
return null;
}
string nspace=System.IO.Path.GetFileNameWithoutExtension(filename);
Type search = ass.GetType(nspace + "." + className);
if (search==null)
return null;
Object o = Activator.CreateInstance(search);
IPluginInfo info = (IPluginInfo)o;
return info;
}
}
}
 
然后的工作就是就是编写插件了。

得益于.Net平台的CLR,在VS上写出的所有的类库都是可以用的,不管你是用C++还是C#还是其他

就以C#为例说一下写一个插件的步骤


  • 建一个类库

  • 在引用里面添加我们写好的PluginSupport.dll

  • 然后建一个类,类名一定是PluginInfo.cs。记得一定加上using ServcieMaster

  • 然后让这个类实现上面的任意一个或者多个继承于IPluginInfo的接口(也可以只实现IPluginSysInfo,但是那样的话我的ServiceMaster只能认出来是一个插件,但是没有实际功能)

  • 完善功能

  • 编译,生成DLL

  • 把生成的插件放到ServiceMaster的Plugin文件夹下

  • 运行ServiceMaster


这是一个示例的插件
using System;
using System.Collections.Generic;
using System.Text;
using ServiceMaster;
using System.Reflection;

namespace testPlugin
{
public class PluginInfo:IPluginMenu
{
#region IPluginInfo 成员

string IPluginInfo.AutherWebUrl
{
get
{
return "http://dkmilan.72pines.com";
}
}

string IPluginInfo.Author
{
get
{
return "DKMILAN";
}
}

string IPluginInfo.Name
{
get
{
return "TestPlugin";
}
}

string IPluginInfo.Version
{
get { return "1.0.0.0"; }
}
#endregion

#region IPluginMenu 成员

System.Windows.Forms.ToolStripMenuItem IPluginMenu.PluginMenu
{
get
{
System.Windows.Forms.ToolStripMenuItem MenuOne = new System.Windows.Forms.ToolStripMenuItem();
System.Windows.Forms.ToolStripMenuItem MenuTwo = new System.Windows.Forms.ToolStripMenuItem();
System.Windows.Forms.ToolStripMenuItem topMenu = new System.Windows.Forms.ToolStripMenuItem();
//
// MenuOne
//
MenuOne.Name = "MenuOne";
MenuOne.Size = new System.Drawing.Size(148, 22);
MenuOne.Text = "Hello!";
MenuOne.Click += new System.EventHandler(MenuOne_Click);
//
// MenuTwo
//
MenuTwo.Name = "MenuTwo";
MenuTwo.Size = new System.Drawing.Size(148, 22);
MenuTwo.Text = "Hello 2~";
MenuTwo.Click += new System.EventHandler(MenuTwo_Click);
//
// topMenu
//
topMenu.Name = "topMenu";
topMenu.Size = new System.Drawing.Size(148, 22);
topMenu.Text = "插件菜单";
//
topMenu.DropDownItems.Add(MenuOne);
topMenu.DropDownItems.Add(MenuTwo);
return topMenu;
}
}

#endregion

private void MenuOne_Click(object sender, EventArgs e)
{
System.Windows.Forms.MessageBox.Show("Enjoy ServiceMaster!");
}
private void MenuTwo_Click(object sender, EventArgs e)
{
System.Windows.Forms.MessageBox.Show("My Plugin!");
}
}
}

如果你喜欢本文,把它分享到 Twitter / 校内 / 鲜果 / Digg
或者把它收藏到 Delicious

1 comments:

匿名 说...

这个代码贴的养眼~