none
Visual Studio 2019(Preview版)を入れるとVisual Studio 2017でEnvDTEが起動しなくなる! RRS feed

  • 質問

  • --------
    自分の環境
    --------

    プロセッサ:Intel(R) Core(TM)i7-4500U CPU @1.80GHz 2.39GHz

    実装メモリ(ram):8.00GB (7.90 GB使用可能)

    OS: Windows 10 Pro /バージョン:1803 (OSビルド:17134.590)

    Visual Studio 2017: Version 15.9.7

    Visual Studio 2019: Version 16.0.0 Preview 3.0

    --------
    発生した現象
    --------

    DTEを使用して実行しているソリューションのパスを取得するプログラムがある。

    ・・・

    EnvDTE.DTE dte = (EnvDTE.DTE)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE")

    String solutionPath = dte.Solution.FullName;

    --------

    このプログラムは従来Visual Studio2017で問題なく動作していた。

    昨日Visual Studio2019のPreviewが安定しているとの情報を受けてこれを同じPCにインストール。

    ここで上述のプログラムを動作させたところ、問題なく動作し、ソリューションパスを返す。

    ところが・・・

    ここで従来作業していたVisual Studio207に戻って同じプログラムを実行すると、

    DTEの取得時に以下のような例外が生じる。

    System.Runtime.InteropServices.COMException: '操作を利用できません (HRESULT からの例外:0x800401E3 (MK_E_UNAVAILABLE))'

    --------

    このプログラムが参照しているDTE関連のパッケージは以下の通り。

    EnvDTE  (バージョン:8.0.0.0)
    EnvDTE100  (バージョン:10.0.0.0)
    EnvDTE80  (バージョン:8.0.0.0)
    EnvDTE90  (バージョン:9.0.0.0)

    --------

    Visual Studio 2019 Preview版をインストールしたことで、DTEに何か干渉が入ったのでしょうか?

    同様の障害報告はざっとGoogleで検索した感じでは見当たりません。

    この問題の回避方法などあれば教えてください。

    ※)当面はVisual Studio 2019で作業せざるを得ません。

    以上、よろしくお願いいたします。


    2019年2月25日 11:09

回答

  • 自己レスです。

    --------

    現象はどうにもなりませんが、Visual Studio 2019 Previewが、そのほかの点では

    安定しているし、かつこのこと自体はVisual Studio 2019については何ら

    障害とならないため、いったんこの質問をクローズします。

    個人的には当面EnvDTEを使用するプログラムの開発は2019を使用して

    継続して開発するつもりです。

    また、このEnvDTEを使用したプログラムを別のVisual Studio 2017しか

    インストールしていないマシンでGITから落として実行すると、問題なく

    EnvDTEは動作します。

    --------

    結論として、起きている現象が全てなのでEnvDTEは今のところ同一PC上では

    最新版のVisual Studio上でしか動作しないようである・・・ということで

    いったんこのスレッドを締めさせていただきます。

    2019年2月27日 9:48
  • GetActiveObjectの説明を読みましょう。

    GetActiveObjectは既に実行中のインスタンスを取得します。
    さらに文字列progIDはレジストリ「コンピューター\HKEY_CLASSES_ROOT\VisualStudio.DTE」を参照します。
    レジストリエディタでVisualStudio.DTEを見ればわかりますが、近くにVisualStudio.DTE.15.0とVisualStudio.DTE.16.0もあるはずです。
    VisualStudio.DTEを呼び出した場合、「コンピューター\HKEY_CLASSES_ROOT\VisualStudio.DTE\CurVer」にどのバージョンを実行させるかも設定されています。VS2019を入れたら「VisualStudio.DTE.16.0」になっているはずです。

    つまり、VisualStudio.DTEを指定してもCurVerに指定しているバージョンしか見つけてはくれません。
    VS2019以外のVSが起動していても関係ありません。
    VS2019が実行していない状態で"VisualStudio.DTE"をGetActiveObjectしたらエラーになります。

    以前から新しいバージョンを入れればCurVerは変更されていくので、今回のVS2019で特別おかしくなったのではありません。

    VS2019以外も入っている環境でVS2019以外のインスタンスを取りたいのであれば、CurVerに目的のバージョンを指定しましょう。
    あるいはGetActiveObjectで明示的にバージョンを指定しましょう。

    namespace ConsoleApplication1
    {
        //Microsoft.VisualStudio.OLE.Interop
        //Microsoft.VisualStudio.Shell.12.0
        //Microsoft.VisualStudio.Shell.Interop
        //Microsoft.VisualStudio.OLE.Interop
    
        using System;
    
        class Program
        {
            static void Main(string[] args)
            {
                const string PROGVER_DEFAULT = "";
                const string PROGVER_VS2013 = "12.0";
                const string PROGVER_VS2015 = "14.0";
                const string PROGVER_VS2017 = "15.0";
                const string PROGVER_VS2019 = "16.0";
    
                string progVer = PROGVER_VS2017;
                string progID = "VisualStudio.DTE" + "."+progVer ;
    
                dynamic dte = null;
                try
                {
                    
                    dte = System.Runtime.InteropServices.Marshal.GetActiveObject(progID);
                }
                catch (System.Runtime.InteropServices.COMException cex)
                {
                    if (cex.ErrorCode == unchecked((int)0x800401E3))
                    {// 起動していないならエラー0x800401E3
    
                        //新たに起動させる
                        var t = Type.GetTypeFromProgID(progID);
                        dte = Activator.CreateInstance(t);
                    }
                }
    
                if (dte != null)
                {
                    dte.MainWindow.Visible = true;
                    Console.WriteLine((string)dte.Version);
    
                    var vsp = dte as Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
                    System.IServiceProvider sp = new Microsoft.VisualStudio.Shell.ServiceProvider(vsp);
    
                    var sso = sp.GetService(typeof(Microsoft.VisualStudio.Shell.Interop.SVsSolutionObject));
                    var so = sso as Microsoft.VisualStudio.Shell.Interop.IVsSolution2;
                    string sd, sf, u;
                    so.GetSolutionInfo(out sd, out sf, out u);
                    if (sd == null)
                    {
                        var temp = System.IO.Path.GetTempFileName();
                        System.IO.File.Delete(temp);
    
                        if (Microsoft.VisualStudio.VSConstants.S_OK == so.CreateSolution(temp, "TestSolution", (uint)Microsoft.VisualStudio.Shell.Interop.__VSCREATESOLUTIONFLAGS.CSF_TEMPORARY))
                        {
                            so.GetSolutionInfo(out sd, out sf, out u);
                        }
                    }
                    Console.WriteLine(sd);
                    Console.WriteLine(sf);
                    Console.WriteLine(u);
                }
    
                Console.ReadKey();
            }
        }
    


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2019年2月28日 11:38

すべての返信

  • 自己レスです。

    --------

    現象はどうにもなりませんが、Visual Studio 2019 Previewが、そのほかの点では

    安定しているし、かつこのこと自体はVisual Studio 2019については何ら

    障害とならないため、いったんこの質問をクローズします。

    個人的には当面EnvDTEを使用するプログラムの開発は2019を使用して

    継続して開発するつもりです。

    また、このEnvDTEを使用したプログラムを別のVisual Studio 2017しか

    インストールしていないマシンでGITから落として実行すると、問題なく

    EnvDTEは動作します。

    --------

    結論として、起きている現象が全てなのでEnvDTEは今のところ同一PC上では

    最新版のVisual Studio上でしか動作しないようである・・・ということで

    いったんこのスレッドを締めさせていただきます。

    2019年2月27日 9:48
  • GetActiveObjectの説明を読みましょう。

    GetActiveObjectは既に実行中のインスタンスを取得します。
    さらに文字列progIDはレジストリ「コンピューター\HKEY_CLASSES_ROOT\VisualStudio.DTE」を参照します。
    レジストリエディタでVisualStudio.DTEを見ればわかりますが、近くにVisualStudio.DTE.15.0とVisualStudio.DTE.16.0もあるはずです。
    VisualStudio.DTEを呼び出した場合、「コンピューター\HKEY_CLASSES_ROOT\VisualStudio.DTE\CurVer」にどのバージョンを実行させるかも設定されています。VS2019を入れたら「VisualStudio.DTE.16.0」になっているはずです。

    つまり、VisualStudio.DTEを指定してもCurVerに指定しているバージョンしか見つけてはくれません。
    VS2019以外のVSが起動していても関係ありません。
    VS2019が実行していない状態で"VisualStudio.DTE"をGetActiveObjectしたらエラーになります。

    以前から新しいバージョンを入れればCurVerは変更されていくので、今回のVS2019で特別おかしくなったのではありません。

    VS2019以外も入っている環境でVS2019以外のインスタンスを取りたいのであれば、CurVerに目的のバージョンを指定しましょう。
    あるいはGetActiveObjectで明示的にバージョンを指定しましょう。

    namespace ConsoleApplication1
    {
        //Microsoft.VisualStudio.OLE.Interop
        //Microsoft.VisualStudio.Shell.12.0
        //Microsoft.VisualStudio.Shell.Interop
        //Microsoft.VisualStudio.OLE.Interop
    
        using System;
    
        class Program
        {
            static void Main(string[] args)
            {
                const string PROGVER_DEFAULT = "";
                const string PROGVER_VS2013 = "12.0";
                const string PROGVER_VS2015 = "14.0";
                const string PROGVER_VS2017 = "15.0";
                const string PROGVER_VS2019 = "16.0";
    
                string progVer = PROGVER_VS2017;
                string progID = "VisualStudio.DTE" + "."+progVer ;
    
                dynamic dte = null;
                try
                {
                    
                    dte = System.Runtime.InteropServices.Marshal.GetActiveObject(progID);
                }
                catch (System.Runtime.InteropServices.COMException cex)
                {
                    if (cex.ErrorCode == unchecked((int)0x800401E3))
                    {// 起動していないならエラー0x800401E3
    
                        //新たに起動させる
                        var t = Type.GetTypeFromProgID(progID);
                        dte = Activator.CreateInstance(t);
                    }
                }
    
                if (dte != null)
                {
                    dte.MainWindow.Visible = true;
                    Console.WriteLine((string)dte.Version);
    
                    var vsp = dte as Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
                    System.IServiceProvider sp = new Microsoft.VisualStudio.Shell.ServiceProvider(vsp);
    
                    var sso = sp.GetService(typeof(Microsoft.VisualStudio.Shell.Interop.SVsSolutionObject));
                    var so = sso as Microsoft.VisualStudio.Shell.Interop.IVsSolution2;
                    string sd, sf, u;
                    so.GetSolutionInfo(out sd, out sf, out u);
                    if (sd == null)
                    {
                        var temp = System.IO.Path.GetTempFileName();
                        System.IO.File.Delete(temp);
    
                        if (Microsoft.VisualStudio.VSConstants.S_OK == so.CreateSolution(temp, "TestSolution", (uint)Microsoft.VisualStudio.Shell.Interop.__VSCREATESOLUTIONFLAGS.CSF_TEMPORARY))
                        {
                            so.GetSolutionInfo(out sd, out sf, out u);
                        }
                    }
                    Console.WriteLine(sd);
                    Console.WriteLine(sf);
                    Console.WriteLine(u);
                }
    
                Console.ReadKey();
            }
        }
    


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2019年2月28日 11:38
  • gekka様、こんにちは、TrailRunner-MFです。お世話になっています。

    サンプルコード付きのご説明本当に有り難うございました。

    おかげさまで無事解決することが出来ました。

    ご提示いただきましたサンプルプログラムは以下のように編集して使用させていただきました。

    1.DTEを使用するプログラムをVisual StudioのTextExplorerから起動しようとしていたので、

    catch (System.Runtime.InteropServices.COMException cex)
    {
      if (cex.ErrorCode == unchecked((int)0x800401E3))
      {// 起動していないならエラー0x800401E3

    の例外トラップは設けず、実行中のVisual Studioから起動できなければそのままスルーにしました。

    2.Visual StudioのバージョンをProgramIDに順番に設定して

    dte = System.Runtime.InteropServices.Marshal.GetActiveObject(progID);

    で初期化します。これが成功したら、dte.FullNameで初期化されたDTEが動いている
    Visual Studioのインストールパスが取得できます。

    これをSystem.Diagnostics.Process.GetCurrentProcess()で取ってきた現在実行中の
    プログラム(=Visual StudioのTestExplorer)と先頭から「\Common7\IDE」までの
    部分一致比較を行い、等しければ現在動いているVisual StudioのDTEとして確定し、
    その後DTEのもつ様々な機能を使用するようにしました。

    アドバイスを頂いてから試行錯誤してちゃんと自分のモノになるまでちょっと時間がかかり
    お返事が遅れてしまいました点、お詫び申し上げます。

    本当に有り難うございました。

    2019年3月4日 17:52