DTE を使って Visual Studio を起動する
Visual Studio 2017 以降では、DTE を使用して Visual Studio を起動するメカニズムは、以前のバージョンの Visual Studio を起動することとは異なります。 この変更が必要になるのは、Visual Studio 2017 以降ではメジャー リリースのサイド バイ サイド インストールがサポートされるためです (たとえば、プレビューとリリース バージョンをサイド バイ サイドでインストールできます)。
この記事の残りの部分では、DTE を使用して Visual Studio 2019 を起動するために使用できるコードを示します。
プロジェクトのセットアップ
動作中のコードを確認するには、次の手順に従ってプロジェクトを作成します。
.NET Framework 用の新しいコンソール アプリ プロジェクトを作成します。
Microsoft.VisualStudio.Setup.Configuration.Interop NuGet パッケージをインストールし、アセンブリへの参照を追加します。
EnvDTE に参照を追加します。
次のコード例を Program.cs ファイルに貼り付けます。
F5 キーを押してプログラムを実行します。 プログラムが終了する前に Visual Studio 2019 が開いていることが確認できるはずです。
コード例
using Microsoft.VisualStudio.Setup.Configuration;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Threading;
namespace ConsoleLauncherApp
{
class Program
{
static void Main(string[] args)
{
EnvDTE.DTE dte = LaunchVsDte(isPreRelease: false);
dte.MainWindow.WindowState = EnvDTE.vsWindowState.vsWindowStateMaximize;
dte.MainWindow.WindowState = EnvDTE.vsWindowState.vsWindowStateMinimize;
dte.MainWindow.WindowState = EnvDTE.vsWindowState.vsWindowStateNormal;
dte.Quit();
}
private static EnvDTE.DTE LaunchVsDte(bool isPreRelease)
{
ISetupInstance setupInstance = GetSetupInstance(isPreRelease);
string installationPath = setupInstance.GetInstallationPath();
string executablePath = Path.Combine(installationPath, @"Common7\IDE\devenv.exe");
Process vsProcess = Process.Start(executablePath);
string runningObjectDisplayName = $"VisualStudio.DTE.16.0:{vsProcess.Id}";
IEnumerable<string> runningObjectDisplayNames = null;
object runningObject;
for (int i = 0; i < 60; i++)
{
try
{
runningObject = GetRunningObject(runningObjectDisplayName, out runningObjectDisplayNames);
}
catch
{
runningObject = null;
}
if (runningObject != null)
{
return (EnvDTE.DTE)runningObject;
}
Thread.Sleep(millisecondsTimeout: 1000);
}
throw new TimeoutException($"Failed to retrieve DTE object. Current running objects: {string.Join(";", runningObjectDisplayNames)}");
}
private static object GetRunningObject(string displayName, out IEnumerable<string> runningObjectDisplayNames)
{
IBindCtx bindContext = null;
NativeMethods.CreateBindCtx(0, out bindContext);
IRunningObjectTable runningObjectTable = null;
bindContext.GetRunningObjectTable(out runningObjectTable);
IEnumMoniker monikerEnumerator = null;
runningObjectTable.EnumRunning(out monikerEnumerator);
object runningObject = null;
List<string> runningObjectDisplayNameList = new List<string>();
IMoniker[] monikers = new IMoniker[1];
IntPtr numberFetched = IntPtr.Zero;
while (monikerEnumerator.Next(1, monikers, numberFetched) == 0)
{
IMoniker moniker = monikers[0];
string objectDisplayName = null;
try
{
moniker.GetDisplayName(bindContext, null, out objectDisplayName);
}
catch (UnauthorizedAccessException)
{
// Some ROT objects require elevated permissions.
}
if (!string.IsNullOrWhiteSpace(objectDisplayName))
{
runningObjectDisplayNameList.Add(objectDisplayName);
if (objectDisplayName.EndsWith(displayName, StringComparison.Ordinal))
{
runningObjectTable.GetObject(moniker, out runningObject);
if (runningObject == null)
{
throw new InvalidOperationException($"Failed to get running object with display name {displayName}");
}
}
}
}
runningObjectDisplayNames = runningObjectDisplayNameList;
return runningObject;
}
private static ISetupInstance GetSetupInstance(bool isPreRelease)
{
return GetSetupInstances().First(i => IsPreRelease(i) == isPreRelease);
}
private static IEnumerable<ISetupInstance> GetSetupInstances()
{
ISetupConfiguration setupConfiguration = new SetupConfiguration();
IEnumSetupInstances enumerator = setupConfiguration.EnumInstances();
int count;
do
{
ISetupInstance[] setupInstances = new ISetupInstance[1];
enumerator.Next(1, setupInstances, out count);
if (count == 1 && setupInstances[0] != null)
{
yield return setupInstances[0];
}
}
while (count == 1);
}
private static bool IsPreRelease(ISetupInstance setupInstance)
{
ISetupInstanceCatalog setupInstanceCatalog = (ISetupInstanceCatalog)setupInstance;
return setupInstanceCatalog.IsPrerelease();
}
private static class NativeMethods
{
[DllImport("ole32.dll")]
public static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);
}
}
}