使用 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);
}
}
}