SharpDevelop Addin(插件树) 使用方法

SharpDevelop Addin(插件树) 使用方法

  

   在经历了N多次的迷茫和郁闷后,今天终于明白了Addin这个东东怎么使用。下面为大家总结一下我研究的过程,希望大家看过我的文档后,研究Addin这 个的东西不再这么痛苦拉。而且可以更快的了解插件树是怎么运行的.好了,废话不多说了,下面言归正传。

  

   Addin作为SharpDevelop的核心组件,它提供了一种插件树的机制来调用插件组成整个应用程序。我将把Addin的核心代码从SharpDevelop中分离出来,然后作为单独的工程。

  

  全部的过程大概分这么两个部分:

  一、 从SharpDevelop中分离出Addin的代码。

  二、 新建一个工程作为调用插件树的主程序。

  三、 新建一个插件以供程序调用。

  

  

  第一部分 分离出插件树的核心代码

  那么首先来讲讲怎么从SharpDevelop中导出Core工程到2003

  

  1. 我们要导出代码首先就必须得到它的源码,源码可以在SharpDevelop的官方网站http://www.icsharpcode.com/OpenSource/SD/Download/ 中下载。

   2. 在下载完程序之后你可以在src/Main/Core 目录下找到Core.prjx这个文件(此文件是SharpDevelop的工程文件),使用SharpDevelop打开此文件,这时候整个Core项 目就加载到SharpDevelop(Core为整个SharpDevelop的核心工程,其中包括了插件树、服务和属性)。由于 SharpDevelop目前调试还没有.net2003方便,所以我们把程序导出为.Net2003的格式可以通过SharpDevelop的 “文件-》输出工程——》选择你要输出的文件夹”来导出整个项目。

  3. 在输出成功后用.Net2003加载刚才输出的解决方案然后编译,这样就可以在输出目录下的bin/debug目录下找到 ICSharpCode.Core.dll这个文件了(此文件为整个插件树的核心组件,在后面的插件树应用中全部都是引用的该组件)。

  4. 拷贝CoreKey.key这个文件到当前项目的目录下。

  

  在经过上述三个步骤之后,整个Addin的代码就从SharpDevelop代码中分离出来了,是不是很简单啊 ^_^。

  

  

  第二部分 建造一个新工程来利用插件树的机制加载插件

  刚才第一部分我们讲解了如何分离出插件树的核心代码,此部分我将讲解怎么在应用程序中利用插件树的机制来加载插件。

  

  1. 首先新建一个Windows应用程序AddinMain。

  2. 在刚才新建的项目中删除Form1然后添加一个类AddinsMain。

  3. 引用ICSharpCode.Core.dll组件(要得到此组件请看第一部分)。

  4. 当上述三个步骤完成后就开始编码工作了,把下面的代码Copy到AddinsMain类中。

  

  /********************************************************************

  * *

  * AddinsMain 运行插件树的主程序 *

  * Vincen *

  * vincen@vip.sina.com *

  * 2004-11-28 *

  *********************************************************************/

  

  using System;

  using System.IO;

  using System.Diagnostics;

  using System.Reflection;

  using System.Drawing;

  using System.Collections;

  using System.Windows.Forms;

  using System.Resources;

  using System.Xml;

  using System.Threading;

  using System.Runtime.Remoting;

  using System.Security.Policy;

  

  //引用Core的命名空间

  using ICSharpCode.Core.Properties;

  using ICSharpCode.Core.AddIns.Codons;

  using ICSharpCode.Core.AddIns;

  using ICSharpCode.Core.Services;

  

  namespace AddinMain

  {

  /// <summary>

  /// AddinsMain 的摘要说明。

  /// </summary>

  public class AddinsMain

  {

  public AddinsMain()

  {

  //

  // TODO: 在此处添加构造函数逻辑

  //

  }

  

  /// <summary>

  /// 整个程序的入口点

  /// </summary>

  [STAThread()]

  public static void Main(string[] args)

  {

  //查找ADDIN的主目录 默认情况下目录为当前目录的../Addin/

  bool ignoreDefaultPath = false;

  string [] addInDirs = AddInSettingsHandler.GetAddInDirectories(out ignoreDefaultPath);

  AddInTreeSingleton.SetAddInDirectories(addInDirs, ignoreDefaultPath);

  

  ArrayList commands = null;

  try

  {

  //启动默认的系统服务

  ServiceManager.Services.AddService(new Resource());

  

  //启动后台服务

  ServiceManager.Services.InitializeServicesSubsystem("/Workspace/Services");

  

  //在程序开始运行时首先加载的插件

  commands = AddInTreeSingleton.AddInTree.GetTreeNode("/Workspace/Autostart").BuildChildItems(null);

  for (int i = 0; i < commands.Count; ++i)

  {

  ((ICommand)commands[i]).Run();

  }

  }

  catch (XmlException e)

  {

  MessageBox.Show("不能加载 XML :" + Environment.NewLine + e.Message);

  return;

  }

  catch (Exception e)

  {

  MessageBox.Show("加载出错 :" + Environment.NewLine + e.ToString());

  return;

  }

  }

  }

  }

  下面为大家解释一下这段代码的意思

  bool ignoreDefaultPath = false;

  string [] addInDirs = AddInSettingsHandler.GetAddInDirectories(out ignoreDefaultPath);

  AddInTreeSingleton.SetAddInDirectories(addInDirs, ignoreDefaultPath);

   此段代码的意思是查找插件树配置文件的路径,它首先去调用AddInSettingsHandler.GetAddInDirectories() 方法(AddInSettingsHandler类在后面介绍)查找App.Config中的AddInDirectories这一项,如果在配置文件中 不存在这一项的话就返回空值。

  当调用AddInTreeSingleton.SetAddInDirectories(addInDirs, ignoreDefaultPath)方法时如果addInDirs为空的话那么插件树配置文件的默认路径为 ../Addin/。

  

   ServiceManager.Services.AddService(new Resource());

  在找到插件树配置文件路径后首先要启动一个默认的资源服务Resource(该服务为系统的默认服务,必须启动,否则程序将无法运行)。

  

  ServiceManager.Services.InitializeServicesSubsystem("/Workspace/Services");

  在启动完程序的默认服务后就开始启动自定义服务了。所有默认服务都是在配置文件的/Workspace/Services扩展点中。

  

  commands = AddInTreeSingleton.AddInTree.GetTreeNode("/Workspace/Autostart").BuildChildItems(null);

  for (int i = 0; i < commands.Count; ++i)

  {

  ((ICommand)commands[i]).Run();

  }

  这段代码就是程序启动时加载前台插件了,/Workspace/Autostart是系统自动运行命令的扩展点路径,定义在这个路径下的插件会在系统启动的时候自动运行。

  

  5. 经过上述的步骤后插件就可以被加载了,不过这个时候程序还不能编译,应为我们的Resource类和AddInSettingsHandler类都没有添加。

  下面我们首先添加AddInSettingsHandler类,该类为插件树控制类。

  代码如下:

  /******************************************************************

   * *

   * AddInSettingsHandler 插件树控制类 *

   * Vincen *

   * vincen@vip.sina.com *

   * 2004-11-28 *

   * *

  ********************************************************************/

  

  using System;

  using System.Configuration;

  using System.Collections;

  using System.Xml;

  

  

  namespace AddinMain

  {

   /// <summary>

   /// AddInSettingsHandler 的摘要说明。

   /// </summary>

   public class AddInSettingsHandler : System.Configuration.IConfigurationSectionHandler

   {

   public AddInSettingsHandler()

   {

   }

  

   public object Create(object parent, object configContext, System.Xml.XmlNode section)

   {

   ArrayList addInDirectories = new ArrayList();

   XmlNode attr = section.Attributes.GetNamedItem("ignoreDefaultPath");

   if (attr != null)

   {

   try

   {

   addInDirectories.Add(Convert.ToBoolean(attr.Value));

   }

   catch (InvalidCastException)

   {

   addInDirectories.Add(false);

   }

   }

   else

   {

   addInDirectories.Add(false);

   }

  

   XmlNodeList addInDirList = section.SelectNodes("AddInDirectory");

   foreach (XmlNode addInDir in addInDirList)

   {

   XmlNode path = addInDir.Attributes.GetNamedItem("path");

   if (path != null)

   {

   addInDirectories.Add(path.Value);

   }

   }

   return addInDirectories;

   }

  

   public static string[] GetAddInDirectories(out bool ignoreDefaultPath)

   {

    ArrayList addInDirs = System.Configuration.ConfigurationSettings.GetConfig("AddInDirectories") as ArrayList;

   if (addInDirs != null)

   {

   int count = addInDirs.Count;

   if (count <= 1)

   {

   ignoreDefaultPath = false;

   return null;

   }

   ignoreDefaultPath = (bool) addInDirs[0];

   string [] directories = new string[count-1];

   for (int i = 0; i < count - 1; i++)

   {

   directories[i] = addInDirs[i+1] as string;

   }

   return directories;

   }

   ignoreDefaultPath = false;

   return null;

   }

   }

  }

  

  添加完AddInSettingsHandler类后下面我们将添加资源服务类。

  首先在项目中添加一个AddInSettingsHandler类,然后COPY下列代码到该类中,该类继承了AbstractService类和实现了IResourceService接口。

  using System;

  using System.IO;

  using System.Windows.Forms;

  using System.Collections;

  using System.Threading;

  using System.Resources;

  using System.Drawing;

  using System.Diagnostics;

  using System.Reflection;

  using System.Xml;

  

  using ICSharpCode.Core.Properties;

  using ICSharpCode.Core.AddIns.Codons;

  using ICSharpCode.Core.AddIns;

  using ICSharpCode.Core.Services;

  

  namespace AddinMain

  {

   /// <summary>

   /// Resource 的摘要说明。

   /// </summary>

   public class Resource:AbstractService,IResourceService

   {

   public Resource()

   {

   //

   // TODO: 在此处添加构造函数逻辑

   //

   }

   #region IResourceService 成员

  

   public void RegisterAssembly(Assembly assembly)

   {

   // TODO: 添加 Resource.RegisterAssembly 实现

   }

  

   public string GetString(string name)

   {

   // TODO: 添加 Resource.GetString 实现

   return null;

   }

   #endregion

   }

  }

  在完成上述步骤后编译程序,怎么样,是不是编译成功了,嘻嘻!写的好累啊,抽支烟回来!

  

  第三部分 新建一个插件

  

   在经过第一部分和第二部分之后下面将新建一个插件给AddMain调用。

  

  1.在刚才的解决方案中添加一个类库项目HelloWorld。

  2.在HelloWorld项目中新建一个窗体Form1。

  3.再新建一个类HelloWorldCommand,该类是作为反射来调用HelloWorld窗体用的,代码如下:

  using System;

  using System.Windows.Forms;

  using System.CodeDom.Compiler;

  using ICSharpCode.Core.AddIns;

  using ICSharpCode.Core.AddIns.Codons;

  

  namespace HelloWorld

  {

   /// <summary>

   /// HelloFormCommand 的摘要说明。

   /// </summary>

   public class HelloFormCommand:ICSharpCode.Core.AddIns.Codons.ICommand

   {

   public HelloFormCommand()

   {

   //

   // TODO: 在此处添加构造函数逻辑

   //

   }

   #region ICommand 成员

  

   public object Owner

   {

   get

   {

   // TODO: 添加 HelloFormCommand.Owner getter 实现

   return null;

   }

   set

   {

   // TODO: 添加 HelloFormCommand.Owner setter 实现

   }

   }

  

   public void Run()

   {

   // TODO: 添加 HelloFormCommand.Run 实现

   Application.Run(new Form1());

   }

  

   #endregion

   }

  }

  

  该类实现了ICSharpCode.Core.AddIns.Codons.ICommand接口。

  

  public void Run()

   {

   // TODO: 添加 HelloFormCommand.Run 实现

   Application.Run(new Form1());

   }

  

  这里面最重要的就是Run方法了,在该方法中运行我们刚刚新建的Form1窗体。

  

  好了,到了这个时候我们只差最后100米的距离了就是插件树的配置文件了。刚刚我们讲过插件树的配置文件默认路径是../Addin/目录下,那么我们在该目录下建立一个Hello. Addin文件,下面我们来讲解下该文件的格式。

  <AddIn name = "AddinTreeView"

   author = "SimonLiu"

   copyright = "GPL"

   url = "http://www.icsharpcode.net"

   description = "Display AddinTree"

   version = "1.0.0">

  

   <Runtime>

   <Import assembly="../../../HelloWorld/bin/Debug/HelloWorld.dll"/>

   </Runtime>

   <Extension path = "/Workspace/Autostart">

   <Class id = "HelloWorld"

   class = "HelloWorld.HelloCommand"/>

   </Extension>

  </AddIn>

  

   在配置文件中,Runtime节指定了插件功能模块所在的库文件HelloWorld.dll的具体路径,在Extension节中指定了扩展点路径 /Workspace/Autostart(该路径是指在程序运行时自动运行该插件),然后在Extension内指定了它的ID、Command类名。 保存此配置文件运行程序,是不是Form1出来了啊,呵呵 很简单吧。

  

  总结

   经过我的“废话连篇”想必各位都看烦了吧不过最后还是得罗嗦最后几句,回顾整个过程,首先我们从SharpDevelop中分离出了Addin的核心代 码,然后新建了一个主体工程利用Addin的机制来调用插件,最后我们新建了一个插件然后被调用,应为SharpDevelop本身的代码有些复杂,而且 我也只像分离出他的插件树代码来用,所以我精简啦很多SharpDevelop的代码。为了方便起见我在这里只是作了一个最简单的示例程序,当然了大家可 以扩展这个示例程序。至于怎么像SharpDevelop那样把所有的插件挂接到一个主界面中,本人正在研究ing…,等研究出来后马上会把研究的心得贴 上来,敬请期待

 

源文档 <http://www.wangchao.net.cn/bbsdetail_54103.html>

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值