服务基础知识

服务是两个 VSPackage 之间的协定。 一个 VSPackage 提供一组特定的接口,供另一个 VSPackage 使用。 Visual Studio 本身是 VSPackage 的集合,它为其他 VSPackage 提供服务。

例如,可以使用 SVsActivityLog 服务获取 IVsActivityLog 接口,该接口可用于写入活动日志。 有关详细信息,请参阅 如何:使用活动日志

Visual Studio 还提供一些未注册的内置服务。 VSPackage 可以通过提供服务替代来替换内置或其他服务。 任何服务都只允许一个服务替代。

服务没有可发现性。 因此,必须知道要使用的服务的服务标识符(SID),并且必须知道它提供哪些接口。 服务的参考文档提供了此信息。

  • 提供服务的 VSPackage 称为服务提供商。

  • 提供给其他 VSPackage 的服务称为全局服务。

  • 仅对实现它们的 VSPackage 或它创建的任何对象可用的服务称为本地服务。

  • 替代其他包提供的内置服务或服务的服务称为服务替代。

  • 服务或服务替代是按需加载的,也就是说,当服务提供的服务由另一个 VSPackage 请求时加载服务提供商。

  • 为了支持按需加载,服务提供商将其全局服务注册到 Visual Studio。 有关详细信息,请参阅 “如何:提供服务”。

  • 获取服务后,使用 QueryInterface (非托管代码)或强制转换(托管代码)获取所需的接口,例如:

    GetService(typeof(SVsActivityLog)) as IVsActivityLog;
    
  • 托管代码按服务类型引用服务,而非托管代码按其 GUID 引用服务。

  • 当 Visual Studio 加载 VSPackage 时,它将服务提供商传递给 VSPackage,以便向 VSPackage 授予对全局服务的访问。 这称为 VSPackage 的“坐” 。

  • VSPackage 可以是他们创建的对象的服务提供程序。 例如,窗体可能会将颜色服务的请求发送到其框架,该请求可能会将请求传递给 Visual Studio。

  • 完全嵌套或不站点的托管对象可能要求 GetGlobalService 直接访问全局服务。

使用 GetGlobalService

有时,可能需要从工具窗口或控件容器获取服务,但尚未进行站点设置,或者已使用不知道所需服务的服务提供商进行站点。 例如,你可能想要从控件内部写入活动日志。 有关这些方案和其他方案的详细信息,请参阅 “如何:对服务进行故障排除”。

可以通过调用静态 GetGlobalService 方法来获取大多数 Visual Studio 服务。

GetGlobalService 依赖于在首次从包派生的任何 VSPackage 时初始化的缓存服务提供程序。 必须保证满足此条件,否则请为 null 服务做好准备。

幸运的是, GetGlobalService 大部分时间都正常工作。

  • 如果 VSPackage 仅向另一个 VSPackage 提供已知服务,则请求服务的 VSPackage 将位于提供该服务的 VSPackage 加载之前。

  • 如果工具窗口由 VSPackage 创建,则 VSPackage 将位于创建工具窗口之前。

  • 如果控件容器由由 VSPackage 创建的工具窗口托管,则 VSPackage 将位于创建控件容器之前。

从工具窗口或控制容器中获取服务

  • 在构造函数、工具窗口或控件容器中插入此代码:

    IVsActivityLog log = Package.GetGlobalService(typeof(SVsActivityLog)) as IVsActivityLog;
        if (log == null) return;
    

    此代码获取 SVsActivityLog 服务并将其转换为 IVsActivityLog 接口,该接口可用于写入活动日志。 有关示例,请参阅 如何:使用活动日志