VS.Net插件制作初级教程
作者:东方蜘蛛 2002年5月 |
|||
本文假定您对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实例。点击工具——》外接程序管理器,弹出如下窗口。
选择文本编辑插件左边的复选框,点确定以后装载插件。
本程序的运行机理是使用Process来模拟用户的DOS命令,当用户选中项目中的EXE文件以后(由于默认我们无法看到BIN目录下的东西,所以请点一下SHOW ALL FILES选择),此插件侦测到用户选中的是EXE文件以后,会自动从隐藏状态变成显示状态,如左上图,程序自动填充了当前文件的路径信息和命令名称,我们所需要做的只是选择可执行文件而已(程序已经做了筛选),我们也可以通过点击选取路径按钮或者双击路径文本框来选择运行项目以外的程序,点了执行命令以后,RICHTEXT控件里将展示程序的运行结果,这样一晃而过的东西就变成“永恒”啦,呵呵。
来看代码吧,来看关键的执行命令的代码。
private void Start()
{
Process p = new Process();
StreamWriter sw;
StreamReader sr;
StreamReader err;
ProcessStartInfo psI = new ProcessStartInfo("cmd");
psI.UseShellExecute = false;
psI.RedirectStandardInput = true;
psI.RedirectStandardOutput = true;
psI.RedirectStandardError = true;
psI.CreateNoWindow = true;
p.StartInfo = psI;
p.Start();
sw = p.StandardInput;
sr = p.StandardOutput;
err = p.StandardError;
sw.AutoFlush = true;
if (this.txtCommandname.Text != "")
{
//切换到当前目录
sw.WriteLine("cd "+this.txtPathInfo.Text);
sw.WriteLine(this.localdrive);
sw.WriteLine(this.txtCommandname.Text);
}
else
//execute default command
sw.WriteLine("dir c://");
sw.Close();
this.txtResult.AppendText(sr.ReadToEnd());
this.txtResult.AppendText(err.ReadToEnd());
}
public void SetCommandInfo(string strPath)
{
int endposition = strPath.LastIndexOf("//");
int startposition = strPath.IndexOf("//",0,strPath.Length);
string path = strPath.Substring(0,endposition);
string filename = strPath.Substring(endposition+1);
this.txtPathInfo.Text = path;
this.txtCommandname.Text = filename;
this.localdrive = strPath.Substring(0,startposition);
}
点击执行以后就是执行Start这个函数,关于PROCESS的更详细的信息请看一下MSDN里的帮助,这里我们看到程序利用了CMD作为入口,就象在开始菜单——运行里面打CMD一样,接着程序利用DOS命令切换到当前目录,然后执行程序,最后再是读出程序的执行结果,总而言之,这部分代码比较简单。
另外一个函数是做改变当前程序设置用的。
接下来看我们这次的主体Connect.CS里的东西
public void Exec(string commandName, EnvDTE.vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
{
handled = false;
if(executeOption == EnvDTE.vsCommandExecOption.vsCommandExecOptionDoDefault)
{
if(commandName == "Command.Connect.Command")
{
if (this.doscommand == null)
{
this.ShowWindow();
}
else
{
this.window.Activate();
}
handled = true;
return;
}
}
}
这个是主体程序,可以看到主要是根据当前控件是否已经实例化来决定是否执行ShowWindow函数,如果已经是的话,将直接调用装载控件的窗体。这里的doscommand就是刚刚我们创建的控件的一个引用。
private void ShowWindow()
{
object objTemp = null;
try
{
string guid = "{C7520611-4791-41a9-9AE8-178F78844C2E}";
window = applicationObject.Windows.CreateToolWindow(addInInstance,"EastSpider.Command.DOSCommand","EastSpider.Command.DOSCommand",guid,ref objTemp);
if (window.IsFloating)
{
window.Height = 700;
window.Width = 800;
}
AddToMainWindow(window);
window.Visible = true;
selectionEvents = (EnvDTE.SelectionEvents)applicationObject.Events.SelectionEvents;
selectionEvents.OnChange += new EnvDTE._dispSelectionEvents_OnChangeEventHandler(this.SelectionOnChange);
this.doscommand = (EastSpider.Command.DOSCommand)objTemp;
}
catch
{
}
}
private void AddToMainWindow(Window win)
{
Window mainWindow = applicationObject.MainWindow;
Windows windows = applicationObject.Windows;
LinkedWindows lw = mainWindow.LinkedWindows;
if ( lw != null )
{
if ( win.AutoHides != true)
lw.Add(win);
}
}
这两段程序建立了装载控件的窗体,并自动“靠边隐藏”,:)
private bool IsExeFileSelected()
{ EnvDTE.SelectedItems selectedItems = applicationObject.SelectedItems;
EnvDTE.SelectedItem selectedItem = selectedItems.Item(1);
if ( selectedItem == null )
return false;
EnvDTE.ProjectItem projectItem = selectedItem.ProjectItem;
if ( projectItem == null )
return false;
string fullName = projectItem.get_FileNames(1);
string ext = System.IO.Path.GetExtension(fullName);
if (string.Compare(ext, ".exe", true) != 0)
return false;
else
return true;
}
private void SelectionOnChange()
{
if ( ( applicationObject.SelectedItems.Count == 1 ) && IsExeFileSelected())
{
window.Visible = true;
doscommand.SetCommandInfo(applicationObject.SelectedItems.Item(1).ProjectItem.get_FileNames(1));
}
}
这两段代码是判断当前是否选择了唯一的可执行文件,如果是,把参数传递给控件类里用于改变当前默认设置,这样,就做到了用户只需选择文件,程序就可自动做出反应。
注意:出于程序的需要(Connect.cs里创建窗体的时候),我给控件类指定了ProgId 和 Guid,如下:
[ProgId("EastSpider.Command.DOSCommand"),Guid("C7520611-4791-41a9-9AE8-178F78844C2E")]
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:[email protected]/,关于插件的更多资源,请参考这里 http://msdn.microsoft.com/vstudio/downloads/automation.asp,希望这两个实例能对你有些帮助,我是东方蜘蛛。
|