Spuštění sady Visual Studio pomocí DTE
Počínaje sadou Visual Studio 2017 se mechanismus spouštění sady Visual Studio pomocí DTE liší od spouštění předchozích verzí sady Visual Studio. Tato změna je nezbytná, protože Visual Studio 2017 a novější podporuje souběžné instalace hlavních verzí (například můžete mít nainstalovanou verzi Preview a verzi vydané verze vedle sebe).
Zbývající část tohoto článku ukazuje kód, který můžete použít ke spuštění sady Visual Studio 2019 pomocí DTE.
Nastavení projektu
Pokud chcete zobrazit spouštěcí kód v akci, vytvořte projekt pomocí následujícího postupu.
Vytvořte nový projekt konzolové aplikace pro rozhraní .NET Framework.
Nainstalujte balíček NuGet Microsoft.VisualStudio.Setup.Configuration.Interop NuGet a přidejte odkaz na sestavení.
Přidejte odkaz na EnvDTE.
Vložte ukázkový kód, který následuje, do souboru Program.cs.
Stisknutím klávesy F5 program spusťte. Před ukončením programu by se měla zobrazit otevřená sada Visual Studio 2019.
Příklad kódu
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);
}
}
}