打开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

双击代码全选
1
2
3
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

双击代码全选
1
void OnStartupComplete(ref Array custom)

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

  3)OnAddInsUpdate

  C# Code - Method Signature

双击代码全选
1
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

双击代码全选
1
void OnBeginShutdown(ref Array custom)

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

  5)OnDisconnection

  C# Code - Method Signature

双击代码全选
1
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。

Add-In运行机制解析(下)相关推荐

  1. Visual Studio 2008 可扩展性开发(三):Add-In运行机制解析(下)

    前言 在上篇Add-In运行机制解析(上)中,我分析了Add-In向导生成的代码,从中我们知道只要创建一个类库,它包含实现了IDTExtensibility2接口的类,然后为其建立.addin配置文件 ...

  2. 微信小程序运行机制解析

    在微信小程序诞生之前,最流行的技术应该是Hybrid 混合开发.Hybrid 混合开发有两个优势,一是跨平台,二是热更新.而微信小程序就更像是运行在微信这个特定环境下的 Hybrid 技术. 接下来从 ...

  3. OpenStack Neutron运行机制解析概要

    问题导读: 1.有OpenVswitch为什么还会有Linux Bridge? 2.整个运行流程是怎样的? 3.什么是TAP设备? 自从开学以来,玩OpenStack也已经3个月了,这段时间主要把精力 ...

  4. cocos2d-x C++ 原始工程引擎运行机制解析

    新建一个工程,相信感兴趣的同学都想知道cocos引擎都是如何运行的 想知道是如何运行的,看懂四个文件即可 话不多说,上代码: 1.首先解释 AppDelegate.h 1 #ifndef _APP_D ...

  5. 最全面梳理 JS 运行机制解析与浏览器页面渲染的核心流程

    最近这几年,云计算的普及和 HTML5 技术的快速发展,越来越多的应用转向了浏览器 / 服务器(B/S)架构,这种改变让浏览器的重要性与日俱增,视频.音频.游戏几大核心场景也都在逐渐往 Web 使用场 ...

  6. Kubernetes核心组件运行机制

    Kubernetes基础架构 由上图可知,Kubernetes基础架构由Master和node组成 控制面Master节点主要包含以下组件: kube-apiserver:负责对外提供集群各类资源的增 ...

  7. kubelet运行机制及架构分析

    背景 在对kubernetes 管理的容器进行监控时涉及到了cAdvisor,而cAdvisor 又运行在kublet中,在这里记录一下kubelet 相关的介绍 简介 kubelet 是在每个 No ...

  8. LINUX下FORK的运行机制详细解析

    摘要:由于fork函数运行机制的复杂性,造就了当两个fork并排时,问题就变得很复杂.解这个题的关键,一是要对linux下进程的机制有一定认识,二是抓住上文提到的几个关于fork的关键点. 今天一位朋 ...

  9. 第42课: Spark Broadcast内幕解密:Broadcast运行机制彻底解密、Broadcast源码解析、Broadcast最佳实践

    第42课:  Spark Broadcast内幕解密:Broadcast运行机制彻底解密.Broadcast源码解析.Broadcast最佳实践 Broadcast在机器学习.图计算.构建日常的各种算 ...

最新文章

  1. 分段线性学习率extend_with_piecewise_linear_lr
  2. javascript中Math.random()产生随机数总结
  3. emc整改措施及案例_12.5EMC一点通||EMC整改措施
  4. 正则验证金额大于等于0,并且只到小数点后2位
  5. linux 路由表设置 之 route 指令详解
  6. 结构为键值的map_在Java中增加Map值的最有效方法-只需搜索键一次
  7. 88. [ExtJS2.1教程-5]ToolBar(工具栏)
  8. Apache ab 使用说明
  9. fiddler一直报错502
  10. c#json对象转数组_如何将Json数组转换为C#中的对象列表
  11. 计算机学院实验室安全管理办法,计算机科学学院实验室安全管理制度
  12. linux点亮硬盘locat,Linux中locate whereis which find grep5种查询命令总结
  13. recy拖动item
  14. linux查看mono进程,linux mono环境
  15. 计算机开机配置失败6,win7开机配置windows update失败怎么跳过?-win7配置update失败,安全模式还是配置失败...
  16. 想撩产品小姐姐?你必须学会的这篇产品经理必读文章,如何构建电商产品认知体系?
  17. forward与sendRedirect区别
  18. BWA处理WES文件
  19. go语言下载gin失败解决方案
  20. 论文阅读:FlowNet 2.0: Evolution of Optical Flow Estimation with Deep Networks

热门文章

  1. 曲线(信息学奥赛一本通-T1435)
  2. 组合数学 —— 组合数取模 —— 逆元与递推打表
  3. 谁考了第k名(信息学奥赛一本通-T1176)
  4. 15 CO配置-控制-内部订单-维护分配结构
  5. 9.7 LSMW程序导出/导入操作手册-录屏
  6. pytorch5:pytorch常用激活函数图像绘制
  7. 剖析Caffe源码之InputLayer
  8. 深度残差收缩网络:(三)网络结构
  9. ES6+REACT+MIXIN
  10. elementUI 分页组件的使用 - 踩坑篇