in src/Microsoft.VisualStudio.Extensibility.Testing.Xunit.Shared/Harness/VisualStudioInstanceFactory.cs [326:412]
private static async Task<Process> StartNewVisualStudioProcessAsync(string installationPath, Version version, string? rootSuffix, ImmutableList<string> extensionFiles)
{
var vsExeFile = Path.Combine(installationPath, @"Common7\IDE\devenv.exe");
var vsRegEditExeFile = Path.Combine(installationPath, @"Common7\IDE\VsRegEdit.exe");
var temporaryFolder = Path.Combine(Path.GetTempPath(), "vs-extension-testing", Path.GetRandomFileName());
Assert.False(Directory.Exists(temporaryFolder));
Directory.CreateDirectory(temporaryFolder);
var installerAssemblyPath = ExtractInstallerAssembly(version, temporaryFolder);
var integrationTestServiceExtension = ExtractIntegrationTestServiceExtension(temporaryFolder);
var extensions = extensionFiles.Add(integrationTestServiceExtension);
try
{
var arguments = string.Join(
" ",
$"\"{rootSuffix}\"",
$"\"{installationPath}\"",
string.Join(" ", extensions.Select(extension => $"\"{extension}\"")));
var installProcessStartInfo = CreateSilentStartInfo(installerAssemblyPath, arguments);
installProcessStartInfo.RedirectStandardError = true;
installProcessStartInfo.RedirectStandardOutput = true;
using var installProcess = Process.Start(installProcessStartInfo);
var standardErrorAsync = installProcess.StandardError.ReadToEndAsync();
var standardOutputAsync = installProcess.StandardOutput.ReadToEndAsync();
installProcess.WaitForExit();
if (installProcess.ExitCode != 0)
{
var messageBuilder = new StringBuilder();
messageBuilder.AppendLine($"VSIX installer failed with exit code: {installProcess.ExitCode}");
messageBuilder.AppendLine();
messageBuilder.AppendLine($"Standard Error:");
messageBuilder.AppendLine(await standardErrorAsync.ConfigureAwait(true));
messageBuilder.AppendLine();
messageBuilder.AppendLine($"Standard Output:");
messageBuilder.AppendLine(await standardOutputAsync.ConfigureAwait(true));
throw new InvalidOperationException(messageBuilder.ToString());
}
}
finally
{
File.Delete(integrationTestServiceExtension);
Directory.Delete(temporaryFolder, recursive: true);
}
if (version.Major >= 16)
{
// Make sure the start window doesn't show on launch
Process.Start(CreateSilentStartInfo(vsRegEditExeFile, $"set \"{installationPath}\" \"{rootSuffix}\" HKCU General OnEnvironmentStartup dword 10")).WaitForExit();
}
var vsLaunchArgs = string.Empty;
if (!string.IsNullOrWhiteSpace(rootSuffix))
{
vsLaunchArgs += $"/rootsuffix \"{rootSuffix}\"";
}
// BUG: Currently building with /p:DeployExtension=true does not always cause the MEF cache to recompose...
// So, run clearcache and updateconfiguration to workaround https://devdiv.visualstudio.com/DevDiv/_workitems?id=385351.
if (version.Major >= 12)
{
Process.Start(CreateSilentStartInfo(vsExeFile, $"/clearcache {vsLaunchArgs}")).WaitForExit();
}
Process.Start(CreateSilentStartInfo(vsExeFile, $"/updateconfiguration {vsLaunchArgs}")).WaitForExit();
Process.Start(CreateSilentStartInfo(vsExeFile, $"/resetsettings General.vssettings /command \"File.Exit\" {vsLaunchArgs}")).WaitForExit();
// Make sure we kill any leftover processes spawned by the host
IntegrationHelper.KillProcess("DbgCLR");
IntegrationHelper.KillProcess("VsJITDebugger");
IntegrationHelper.KillProcess("dexplore");
var process = Process.Start(vsExeFile, vsLaunchArgs);
Debug.WriteLine($"Launched a new instance of Visual Studio. (ID: {process.Id})");
return process;
ProcessStartInfo CreateSilentStartInfo(string fileName, string arguments)
{
return new ProcessStartInfo(fileName, arguments) { CreateNoWindow = true, UseShellExecute = false };
}
}