Inicio de Visual Studio con DTE
A partir de Visual Studio 2017, el mecanismo para iniciar Visual Studio mediante DTE es diferente a iniciar versiones anteriores de Visual Studio. Este cambio es necesario porque Visual Studio 2017 y versiones posteriores admiten instalaciones en paralelo de versiones principales (por ejemplo, puede tener una versión preliminar y una versión de versión instalada en paralelo).
El resto de este artículo muestra el código que puede usar para iniciar Visual Studio 2019 mediante DTE.
Configuración del proyecto
Para ver el código de inicio en acción, cree un proyecto siguiendo estos pasos.
Cree un proyecto de aplicación de consola para .NET Framework.
Instale el paquete NuGet Microsoft.VisualStudio.Setup.Configuration.Interop y agregue una referencia al ensamblado.
Agregue una referencia a EnvDTE.
Pegue el código de ejemplo siguiente en el archivo Program.cs .
Pulse F5 para ejecutar el programa. Debería ver que Visual Studio 2019 está abierto antes de que se cierre el programa.
Ejemplo de código
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);
}
}
}