您的位置:首页 > 其它

VS.Net插件制作初级教程

2007-08-29 17:37 465 查看
[align=left]VS.Net插件制作初级教程
作者:东方蜘蛛 2002年5月[/align]
 
 
 
 
 概述:
  本文假定您对C#、VB.Net、CLR等有一定的了解,并具备一些基本的编码知识
不管微软目前的VS.NET IDE工具有多强大,但是对开发人员而言,总有一些自己希望有的功能却没有具备,出于这点考虑,VS.Net IDE提供了一个易用的工具,允许开发人员拓展自己所需的功能,这也就是我们今天所提的插件,插件的制作非常简单,而且可以使用任何.Net支持的语言如VB、C#、C、C++等等,本文描述了插件的工作方式,将通过建立一个文本编辑插件实例来展示。它有一个简单的功能:在当前文本里插入当前日期。 如果您目前已经开始使用微软VS.Net的RTM版本,您肯定知道微软在这个工具里包装了很多新的功能和工具,对于一个代码编辑工具而言,那实在是没什么地方可以挑剔了,可惜开发人员眼中几乎没有十全十美的这方面的工具,原因无他,很多人都希望这个开发工具包含了自己想象的功能,可是微软也做不到这一点,幸好它留了让开发人员自由发挥的空间,我想这点已经足够了。好了,现在让我们开始吧。

 开始
    插件和宏都有扩展IDE的能力,对于插件而言,由于是被编译的,一旦发布就无法被修改,因而保护了自己的知识产权。插件能做到与IDE的无逢嵌合,比如可以定义自己的工具栏,修改菜单命令的状态,甚至可以帮助下的ABOUT对话框中加上自己个性化的东西。有关创建一个插件的详细步骤可以在微软的站点里找到,也可以查看SDK里的帮助,里面也有详细的介绍,由于是向导式的,这里,我只重复一些关键性的步骤。
    1、  打开MicroSoft Visual Studio .Net工具,新建一扩展性项目,取名为TextUtil,如下图所示。这里假定你使用的是中文版本。

    2、 点击确定以后会开始出现欢迎向导页面,点下一步选择使用的语言,这里我们选择C#,再下一步选择支持的应用程序,选好以后继续点击下一步设定名称和说明,接着出现如下页面设定外接程序(插件)的选项。 

设置好以后继续下一步,设置“帮助”中的“关于”信息,最后单击完成,我们的向导操作就大功告成了。
3、  接下来向导会自动创建一个Connect.cs文件,让我们来看一下里面的东东
(1)Connect::Connect 这个构造函数用于您的简单的初始化。
(2)Connect::OnConnection 这个方法是在IDE装载您创立的ADD-IN的时候执行的,您应该在这里初始化您的插件,告诉IDE你创建的命令,指定键盘绑定等等。
(3)Connect::QueryStatus IDE调用这个命令以知道当前哪个命令合适,根据不同的情况做不同的响应。
(4)Connect:Exec IDE用这个命令来执行您刚刚所创建的命令。

这里我们创建一个简单的命令:InsertDate,这个命令的用途是在当前光标的位置插入当前的日期,.Net包含了一个同样功能的宏示例,这样,您可以看到他们的异曲同工之妙。这个命令很简单,您只要稍微修改一下头上所示的Exec函数里的东西就可以了。
我们把

handled = true;

替换成

handled = InsertDate();

然后实现如下InsertDate的代码:
    // InsertDate
// Insert the current date in my favorite format.
//
bool InsertDate()
{
  if (null != applicationObject.ActiveDocument)
  ((TextSelection)applicationObject.ActiveDocument.Selection).Text
    = DateTime.Now.ToString("dd-MMM-yyyy");
  return true;
}

虽然很简单,但这的确就是一个插件了

现在我们就可以运行它了,按一下F5,我们看到启动了一个新的IDE实例。点击工具——》外接程序管理器,弹出如下窗口。

选择文本编辑插件左边的复选框,点确定以后装载插件。

现在我们可以让它为我们做点事情了,随意打开一个工程,打开一个代码文件,按Ctrl+Alt+A调出命令窗口,IDE提供了自动完成的功能,打一个Te以后就会出现如下界面:

按一下回车,看到了什么?在当前位置插入了当前日期了吧,呵呵。(未完待续)

 VS.Net插件制作进阶教程
    本文将通过一个实例来展现复杂的插件的制作方式,本实例是模拟用户的DOS环境,出发点是当我们在制作控制台输出程序的时候,有时候没看清楚结果屏幕就关闭了,当然我们有一些其他的解决办法,比如让程序继续等待等等,但这里,我们只做演示用,您可以自己扩展它,:)
    如果您看过VS.Net插件制作的初级教程,那对你理解本文将产生帮助,如果没有,您也可以通过自己的实践来达到初级教程的目的。
    我们先新建一个名为Command的ADD-IN工程。如果您对这个步骤不熟悉,请看一下初级教程。
    现在我们建立一个用户控件,如左下图排版样式。注意,下图是运行以后的样式,为了省空间,所以直接拿过来了。

  
 
  本程序的运行机理是使用Process来模拟用户的DOS命令,当用户选中项目中的EXE文件以后(由于默认我们无法看到BIN目录下的东西,所以请点一下SHOW ALL FILES选择),此插件侦测到用户选中的是EXE文件以后,会自动从隐藏状态变成显示状态,如左上图,程序自动填充了当前文件的路径信息和命令名称,我们所需要做的只是选择可执行文件而已(程序已经做了筛选),我们也可以通过点击选取路径按钮或者双击路径文本框来选择运行项目以外的程序,点了执行命令以后,RICHTEXT控件里将展示程序的运行结果,这样一晃而过的东西就变成“永恒”啦,呵呵。

来看代码吧,来看关键的执行命令的代码。 
[align=left]private void Start()[/align]
[align=left]         {[/align]
[align=left]              Process p = new Process();[/align]
[align=left]              StreamWriter sw;[/align]
[align=left]              StreamReader sr;[/align]
[align=left]              StreamReader err;             [/align]
[align=left]              ProcessStartInfo psI = new ProcessStartInfo("cmd");[/align]
[align=left]              psI.UseShellExecute = false;[/align]
[align=left]              psI.RedirectStandardInput = true;[/align]
[align=left]              psI.RedirectStandardOutput = true;[/align]
[align=left]              psI.RedirectStandardError = true;[/align]
[align=left]              psI.CreateNoWindow = true;[/align]
[align=left]              p.StartInfo = psI;      

              p.Start();[/align]
[align=left]              sw = p.StandardInput;[/align]
[align=left]              sr = p.StandardOutput;[/align]
[align=left]              err = p.StandardError;    

              sw.AutoFlush = true;[/align]
[align=left]              if (this.txtCommandname.Text != "")[/align]
[align=left]              {[/align]
[align=left]                   //切换到当前目录[/align]
[align=left]                   sw.WriteLine("cd "+this.txtPathInfo.Text);[/align]
[align=left]                   sw.WriteLine(this.localdrive);[/align]
[align=left]                   sw.WriteLine(this.txtCommandname.Text);[/align]
[align=left]              }[/align]
[align=left]              else[/align]
[align=left]                   //execute default command[/align]
[align=left]                   sw.WriteLine("dir c://"); [/align]
[align=left]              sw.Close();[/align]
[align=left]              this.txtResult.AppendText(sr.ReadToEnd());[/align]
[align=left]              this.txtResult.AppendText(err.ReadToEnd()); [/align]
         } 
[align=left]         public void SetCommandInfo(string strPath)[/align]
[align=left]         {[/align]
[align=left]              int endposition = strPath.LastIndexOf("//");[/align]
[align=left]              int startposition = strPath.IndexOf("//",0,strPath.Length); [/align]
[align=left]              string path = strPath.Substring(0,endposition);[/align]
[align=left]              string filename = strPath.Substring(endposition+1);[/align]
[align=left]              this.txtPathInfo.Text = path;[/align]
[align=left]              this.txtCommandname.Text = filename;              [/align]
[align=left]              this.localdrive = strPath.Substring(0,startposition);[/align]
         } 
    点击执行以后就是执行Start这个函数,关于PROCESS的更详细的信息请看一下MSDN里的帮助,这里我们看到程序利用了CMD作为入口,就象在开始菜单——运行里面打CMD一样,接着程序利用DOS命令切换到当前目录,然后执行程序,最后再是读出程序的执行结果,总而言之,这部分代码比较简单。 
另外一个函数是做改变当前程序设置用的。 
接下来看我们这次的主体Connect.CS里的东西 
[align=left]public void Exec(string commandName, EnvDTE.vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)[/align]
[align=left]         {[/align]
[align=left]              handled = false;[/align]
[align=left]              if(executeOption == EnvDTE.vsCommandExecOption.vsCommandExecOptionDoDefault)[/align]
[align=left]              {[/align]
[align=left]                   if(commandName == "Command.Connect.Command")[/align]
[align=left]                   {[/align]
[align=left]                       if (this.doscommand == null)[/align]
[align=left]                       {[/align]
[align=left]                            this.ShowWindow();[/align]
[align=left]                       }[/align]
[align=left]                       else[/align]
[align=left]                       {[/align]
[align=left]                            this.window.Activate();[/align]
[align=left]                       }[/align]
[align=left]                       handled = true;[/align]
[align=left]                       return;[/align]
[align=left]                   }[/align]
[align=left]              }[/align]
         }
    这个是主体程序,可以看到主要是根据当前控件是否已经实例化来决定是否执行ShowWindow函数,如果已经是的话,将直接调用装载控件的窗体。这里的doscommand就是刚刚我们创建的控件的一个引用。
[align=left]private void ShowWindow()[/align]
[align=left]         {[/align]
[align=left]              object objTemp = null;[/align]
[align=left]              try[/align]
[align=left]              {[/align]
[align=left]                   string guid = "{C7520611-4791-41a9-9AE8-178F78844C2E}";[/align]
[align=left]                   window = applicationObject.Windows.CreateToolWindow(addInInstance,"EastSpider.Command.DOSCommand","EastSpider.Command.DOSCommand",guid,ref objTemp); [/align]
[align=left]                   if (window.IsFloating)[/align]
[align=left]                   {[/align]
[align=left]                       window.Height = 700;[/align]
[align=left]                       window.Width = 800;[/align]
[align=left]                   } [/align]
[align=left]                   AddToMainWindow(window);[/align]
[align=left]                   window.Visible = true; [/align]
[align=left]                   selectionEvents = (EnvDTE.SelectionEvents)applicationObject.Events.SelectionEvents;[/align]
[align=left]                   selectionEvents.OnChange += new EnvDTE._dispSelectionEvents_OnChangeEventHandler(this.SelectionOnChange); [/align]
[align=left]                   this.doscommand = (EastSpider.Command.DOSCommand)objTemp;[/align]
[align=left]              } [/align]
[align=left]              catch[/align]
[align=left]              {[/align]
[align=left]              }[/align]
         } 
[align=left]private void AddToMainWindow(Window win)[/align]
[align=left]         {[/align]
[align=left]              Window mainWindow = applicationObject.MainWindow;[/align]
[align=left]              Windows windows = applicationObject.Windows;[/align]
[align=left]              LinkedWindows lw = mainWindow.LinkedWindows;[/align]
[align=left]              if ( lw != null ) [/align]
[align=left]              {[/align]
[align=left]                   if ( win.AutoHides != true)[/align]
[align=left]                       lw.Add(win);[/align]
[align=left]              }[/align]
         } 
这两段程序建立了装载控件的窗体,并自动“靠边隐藏”,:) 
[align=left]private bool IsExeFileSelected()
         {
              EnvDTE.SelectedItems selectedItems = applicationObject.SelectedItems;[/align]
[align=left]              EnvDTE.SelectedItem selectedItem = selectedItems.Item(1); [/align]
[align=left]              if ( selectedItem == null )[/align]
[align=left]                   return false;[/align]
[align=left]              EnvDTE.ProjectItem projectItem = selectedItem.ProjectItem;[/align]
[align=left]              if ( projectItem == null )[/align]
[align=left]                   return false;[/align]
[align=left]              string fullName = projectItem.get_FileNames(1);[/align]
[align=left]              string ext = System.IO.Path.GetExtension(fullName);[/align]
[align=left]              if (string.Compare(ext, ".exe", true) != 0)[/align]
[align=left]                   return false;[/align]
[align=left]              else[/align]
[align=left]                   return true;[/align]
[align=left]         } [/align]
[align=left]         private void SelectionOnChange()[/align]
[align=left]         {[/align]
[align=left]              if ( ( applicationObject.SelectedItems.Count == 1  ) && IsExeFileSelected())[/align]
[align=left]              {[/align]
[align=left]                   window.Visible = true;[/align]
[align=left]                   doscommand.SetCommandInfo(applicationObject.SelectedItems.Item(1).ProjectItem.get_FileNames(1));[/align]
[align=left]              }[/align]
         } 
    这两段代码是判断当前是否选择了唯一的可执行文件,如果是,把参数传递给控件类里用于改变当前默认设置,这样,就做到了用户只需选择文件,程序就可自动做出反应。 
注意:出于程序的需要(Connect.cs里创建窗体的时候),我给控件类指定了ProgId 和 Guid,如下: 
[align=left][ProgId("EastSpider.Command.DOSCommand"),Guid("C7520611-4791-41a9-9AE8-178F78844C2E")][/align]
public class DOSCommand : System.Windows.Forms.UserControl
……. 
    将命名空间与类型名组合在一起可以为类自动生成 ProgId。然而,这可能产生无效的 ProgId,具体的信息请参考一下MSDN吧。 
  由于代码比较多,这里不能一一全部奉上了,以上的代码已经完全能实现我所说的功能了,剩下的一些零碎的东西我相信大家自己补充一下肯定不成问题,关于公共环境对象模型(EnvDTE 类型库)等相关的信息,请大家还是参考一下MSDN里面的东西,由于大部分代码都是自动生成的,我们所要的只是引用而已,我也不介绍了。我会在适当的时间发布整个工程,请关注http://www.dev-club.com/club/bbs/main.asp?boardid=115,关于工程的实例,请到这里下载ftp://devclub:devclub@202.106.155.102/,关于插件的更多资源,请参考这里http://msdn.microsoft.com/vstudio/downloads/automation.asp,希望这两个实例能对你有些帮助,我是东方蜘蛛。
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息