0
点赞
收藏
分享

微信扫一扫

Add-In运行机制解析(下)

三次方 2022-12-06 阅读 173


打开VS,开始第二回合的观察。由于选择了在VS启动时加载,所以此时触发了OnConnection,connectMode为ext_cm_Startup,也就是说是在VS启动时加载的;之后连续触发了OnAddinsUpdate和OnStartupComplete,只有设置为在VS启动时加载才可能触发该事件。至此,5个事件都已经触发过了。

  比较有意思的是OnAddinsUpdate。现在打开Add-In Manager,改变另一个Add-In的设置,点击确定,该事件也会触发,这就是前面所说的“所有Add-In的集合状态发生改变的时候”。

  由前面的介绍可以了解到,实现IDTExtensibility2接口是每个Add-In的核心所在。但是仅仅这些显然还不够。我们不仅需要知道VS合适启动、卸载或改变了Add-In,我们还要能够在这些时候访问VS,否则开发VS的Add-In也就没意义了。这就用到了VS的自动化对象模型(Automation Object Model)。

  VS自动化对象模型简介

  在Connect.cs文件的顶部using部分,可以看到两个命名空间:EnvDTE和EnvDTE80。EnvDTE表示开发环境工具扩展(Environment Development Tools Extensibility,常简称为DTE),就是在这里定义了VS的自动化对象模型(以下简称AOM)。而EnvDTE80的80表示8.0版本的AOM,其实还有一个表示9.0版本的EnvDTE90,但没有引用进来。

  简单说一下它们的关系。EnvDTE表示VS2005之前的DTE版本,在每个版本中微软都会修复一些bug或添加新的功能,到了VS2005,微软使用了EnvDTE80表示新版本的变化(包括修复和增强),同时对于那些旧版本中已经存在的类,在后面加了一个数字2表示该类的新版本,如CodeFunction2表示是EnvDTE80中的新类型,而CodeFunction则表示EnvDTE中对应的那个类。EnvDTE90与此类似,比如Solution3、Solution2和Solution分别表示三个版本中表示解决方案的类。对于这些不同版本的类,微软的做法是用新版本的类继承旧的版本,然后进行扩展。

  但是相对于EnvDTE80与EnvDTE之间的变化,EnvDTE90的变化要小很多。大部分时候EnvDTE80就够用了,所以默认情况下,Connect.cs文件没有引用EnvDTE90。以后当你看到带着2或3后缀的类型,就能明白它的来历了。下面是AOM的结构图(点击查看大图):

​​  图片看不清楚?请点击这里查看原图(大图)。​​ 

  不出意外的是,结构很复杂。原因有二:首先VS本身很复杂,DTE用来表示VS中的元素,不能不复杂;其次,AOM和DTE源自COM,在.NET和COM间的互操作增强一些额外的工作。不过不用担心,这些类封装得非常之好,用起来还是比较容易的。

  这个类型结构的顶端是DTE/DTE2,它是所有其它类型的容器。DTE主要包含5部分内容:解决方案和项目、命令(Command)、事件、文档、调试器,通过这些,我们就能够操作VS的方方面面(可以先看一下图中类的名字)。在后续的随笔中,你将看到这些内容的详细用法。

  再议IDTExtensibility2接口

  现在回到IDTExtensibility2接口,仔细了解一下它的各个方法。

  1)OnConnection

  在实现这个接口的时候,我们需要获得DTE对象,这样才能操作VS,这件事要在OnConnection中去做。

  C# Code - Method Signature

双击代码全选

public   void  OnConnection( object  application, ext_ConnectMode connectMode, 

             object  addInInst,  ref  Array custom)

  application参数持有AOM根对象的引用,它同时实现了EnvDTE.DTE和EnvDTE80.DTE2接口,所以在我们的例子中,它被转换为DTE2。connectMode参数告诉Add-In是以何种方式加载的,它的值来自Extensibility.ext_ConnectMode枚举:

  ext_cm_AfterStartup:在VS启动之后加载

  ext_cm_Startup:在VS启动之时加载

  ext_cm_External:在VS外部加载(VS已经不再使用该值)

  ext_cm_CommandLine:从命令行加载

  ext_cm_Solution:在解决方案内加载

  ext_cm_UISetup:在建立用户界面时加载

  我们可以根据该参数值的不同进行相应的操作,比如如果是ext_cm_UISetup,可以在菜单上添加一条命令(就像Add-In向导所做的那样)。

  Add-In本身是AddIn接口的一个实例,addInInst参数持有该实例的引用,我们可以将该值保存下来备用。最后,IDTExtensibility2接口的每个方法都有一个custom参数,Add-In的宿主环境可以通过它来传递宿主相关的信息,不过VS总是传递一个空的数组(汗。。。)。

  2)OnStartupComplete

  OnStartupComplete事件仅仅在Add-In随VS启动加载的时候才会触发。

  C# Code - Method Signature

双击代码全选

void  OnStartupComplete( ref  Array custom)

  如果一个Add-In随VS启动而加载,OnConnection并非总是进行初始化的好地方——比如,Add-In加载的较早,而Add-In需要访问的VS组件尚未加载完毕。

  3)OnAddInsUpdate

  C# Code - Method Signature

双击代码全选

void  OnAddInsUpdate( ref  Array custom)


  在某个Add-In被加载或卸载的时候,OnAddInsUpdate事件会触发。OnAddInsUpdate事件没有提供被加载或卸载Add-In的信息,不过我们有办法获取到。大体原理是:通过DTE.AddIns/DTE2.AddIns集合我们能够获取到所有的Add-In,里面的元素类型为AddIn,AddIn有个Connected属性,用以表示该Add-In是否处于加载状态,我们在首次触发OnAddInsUpdate事件的时候记录所有Add-In的状态,在下次触发的时候就知道那些Add-In状态改变了,这里就不再给出代码了。

  4)OnBeginShutDown

  C# Code - Method Signature

双击代码全选

  void  OnBeginShutdown( ref  Array custom)

  如果在一个Add-In运行的时候关闭VS,OnBeginShutDown事件会触发。我们在这个时候可以做一些必要的清理工作。

  5)OnDisconnection

  C# Code - Method Signature

双击代码全选

void  OnDisconnection(ext_DisconnectMode disconnectMode,  ref  Array custom)

  在Add-In的生命周期结束的时候,OnDisconnection事件会触发。它跟OnBeginShutDown事件的不同之处在于,这里结束的是Add-In而不是VS。disconnectMode参数的值来自Extensibility.ext_DisconnectMode枚举:

  ext_dm_HostShutdown:因为VS关闭而卸载

  ext_dm_UserClosed:在VS运行时卸载

  ext_dm_UISetupComplete:在用户界面创建完毕后卸载

  ext_dm_SolutionClosed:在解决方案关闭时卸载

  它的作用类似于ext_ConnectMode,我们可以根据Add-In卸载方式的不同采取不同的动作。

  唔,至此Add-In的事件和生命周期介绍完毕。

  我们身在何处?

  本文主要介绍了VS Add-In的事件和生命周期,通过这些知识,我们能够知道在何时获取需要的信息;同时还简单介绍了VS自动化对象模型。加上Add-In运行机制解析(上),我们应当对Add-In的运行机制有个基本的了解,为接下来的开发打下基础。到现在我们还不足以写出真正有用的Add-In,从下一篇开始我将介绍如何开发真正有用的Add-In。

举报

相关推荐

0 条评论