zoukankan      html  css  js  c++  java
  • 【Visual Studio】在VS2012中使用VSXtra

    最近工作中需要把之前为VS 2010写的扩展迁移到VS 2012上。在将工程版本改为VS2012之后,代码没有修改,直接编译通过,也可以安装到VS2012上。

    不过,在实际使用的时候,却报错,提示“The framework has not been sited!”。调试后发现,这个错误是我们在IDE开发中用到的VSXtra报出的。错误的报错位置是在SiteManager的GetGlobalService方法中:

            // --------------------------------------------------------------------------------------------
            /// <summary>
            /// Gets a global service with the specified address and behavior type.
            /// </summary>
            /// <typeparam name="SInterface">Address type of the service</typeparam>
            /// <typeparam name="TInterface">Behavior (endpoint) type of the service</typeparam>
            /// <returns>The service instance obtained.</returns>
            // --------------------------------------------------------------------------------------------
            public static TInterface GetGlobalService<SInterface, TInterface>()
                where TInterface : class
                where SInterface : class
            {
                if (!HasGlobalServiceProvider)
                    throw new InvalidOperationException("The framework has not been sited!");
                var ti = GlobalServiceProvider.GetService<SInterface, TInterface>();
                if (ti == null)
                    throw new NotSupportedException(typeof(SInterface).FullName);
                return ti;
            }

    从代码可以看到,异常抛出的条件是在GlobalServiceProvider不存在的时候。那么这个HasGlobalServiceProvider属性是什么样的呢:

            // --------------------------------------------------------------------------------------------
            /// <summary>
            /// Gets the flag indicating if the SiteManager has already a global service provider or not.
            /// </summary>
            // --------------------------------------------------------------------------------------------
            public static bool HasGlobalServiceProvider
            {
                get { return (GlobalServiceProvider != null); }
            }

    看来是判断GlobalServiceProvider是否为null。那么,是谁负责设置这个GlobalServiceProvider的呢?我们通过Find All References可以发现这个属性是在SuggestGlobalServiceProvider方法中被设置的,这个方法有多个重载,跟踪一下,需要调用到的是这个:

            // --------------------------------------------------------------------------------------------
            /// <summary>
            /// Suggests a DTE2 object as the global service provider for SiteManager.
            /// </summary>
            /// <param name="dte2">DTE2 object as a global service provider candidate.</param>
            // --------------------------------------------------------------------------------------------
            public static void SuggestGlobalServiceProvider(DTE2 dte2)
            {
                SuggestGlobalServiceProvider(dte2 as IOleServiceProvider);
            }

    而这个SuggestGlobalServiceProvider则是在一个叫做TryToGetServiceProviderFromCurrentProcess的关键方法中被调用到的(部分代码省略):

            private static void TryToGetServiceProviderFromCurrentProcess(string vsMoniker)
            {
                ......
    
                string ideMoniker = String.Format(vsMoniker, Process.GetCurrentProcess().Id);
    
                ......
                while (enumMoniker.Next(1, moniker, IntPtr.Zero) == 0)
                {
                    string displayName;
                    moniker[0].GetDisplayName(ctx, moniker[0], out displayName);
                    if (displayName == ideMoniker)
                    {
                        // --- Got the IDE Automation Object
                        Object oDTE;
                        rot.GetObject(moniker[0], out oDTE);
                        dte = oDTE as DTE2;
                        if (dte != null) break;
                    }
                }
    
                SuggestGlobalServiceProvider(dte);
            }

    其大概意思是从当前进程中获取一些信息,跟通过传入的vsMoniker格式化之后的一个字符串进行比对,如果名字是一样的,则通过它获取VS IDE的DTE实例。那么,这个vsMoniker是个什么东东?又是谁调用了这个方法呢?

        // --------------------------------------------------------------------------------------------
        /// <summary>
        /// Monikers of possible DTE objects. Right now VS 2008 and VS 2010 is handled.
        /// </summary>
        // --------------------------------------------------------------------------------------------
        private static readonly List<string> VSMonikers =
          new List<string>
            {
              "!VisualStudio.DTE.9.0:{0}",
              "!VisualStudio.DTE.10.0:{0}"
            };
    
        // --------------------------------------------------------------------------------------------
        /// <summary>
        /// The static constructor automatically tries to assign the SiteManager static class to a site
        /// that accesses VS IDE global services.
        /// </summary>
        // --------------------------------------------------------------------------------------------
        static SiteManager()
        {
          foreach (string moniker in VSMonikers)
          {
            TryToGetServiceProviderFromCurrentProcess(moniker);
            if (HasGlobalServiceProvider) return;
          }
        }

    看到这儿,我们也明白了,敢情VSXtra这儿写死了几个字符串{ "!VisualStudio.DTE.9.0:{0}", "!VisualStudio.DTE.10.0:{0}" },跟VS版本相关,而VS2012的版本号是11,这里没有,所以当然找不到DTE Instance了。

    最简单的修改版本,添加一个VS2012的版本号:"!VisualStudio.DTE.11.0:{0}",运行测试OK。

    不过,对于这种hard-code的写法笔者是看着很不爽,那么,有没动态获取已经安装的VS版本的方法呢?答案是:有,通过注册表。

    于是最后的代码修改如下:

            // --------------------------------------------------------------------------------------------
            /// <summary>
            /// Monikers of possible DTE objects. Right now VS 2008 and VS 2010 is handled.
            /// </summary>
            // --------------------------------------------------------------------------------------------
            private static readonly IEnumerable<string> VSMonikers;
    
            // --------------------------------------------------------------------------------------------
            /// <summary>
            /// The static constructor automatically tries to assign the SiteManager static class to a site
            /// that accesses VS IDE global services.
            /// </summary>
            // --------------------------------------------------------------------------------------------
            static SiteManager()
            {
                var vsRegKey = Registry.CurrentUser
                    .OpenSubKey("Software")
                    .OpenSubKey("Microsoft")
                    .OpenSubKey("VisualStudio");
                var installedNames = vsRegKey.GetSubKeyNames().Where(x => !x.Contains("Exp") && !x.Contains("_Config"));
                VSMonikers = installedNames.Select(x => "!VisualStudio.DTE." + x + ":{0}").ToArray();
    
                foreach (string moniker in VSMonikers)
                {
                    TryToGetServiceProviderFromCurrentProcess(moniker);
                    if (HasGlobalServiceProvider) return;
                }
            }

    附:修改后的VSXtra

  • 相关阅读:
    selenium python (十五)控制滚动条操作
    selenium python (十四)上传文件的处理
    selenium python (十三)对于分页的处理
    selenium python (十二)下拉框的处理
    selenium python (十一)alert/confirm/prompt的处理(js中的弹出框)
    selenium python (十)浏览器多窗口处理
    selenium python (九)对话框处理
    selenium python (八)定位frame中的对象
    企业分布式微服务云SpringCloud SpringBoot mybatis (三) 服务消费者(Feign)
    企业分布式微服务云SpringCloud SpringBoot mybatis (二)服务消费者(rest+ribbon)
  • 原文地址:https://www.cnblogs.com/RMay/p/VSXtra_for_VS2012.html
Copyright © 2011-2022 走看看