in src/Microsoft.VisualStudio.Extensibility.Testing.Xunit.Shared/Harness/VisualStudioInstance.cs [119:198]
private static DTE? GetDebuggerHostDte()
{
var currentProcessId = Process.GetCurrentProcess().Id;
var checkedProcesses = new List<int>();
// Check ancestor processes first to avoid checking the DTE for unrelated processes when possible
foreach (var process in GetAncestorProcesses(Process.GetCurrentProcess()))
{
if (process.ProcessName != "devenv")
{
continue;
}
if (TryGetDteForAttachedDebugger(process, currentProcessId) is { } dte)
{
return dte;
}
checkedProcesses.Add(process.Id);
}
foreach (var process in Process.GetProcessesByName("devenv"))
{
if (checkedProcesses.Contains(process.Id))
{
continue;
}
if (TryGetDteForAttachedDebugger(process, currentProcessId) is { } dte)
{
return dte;
}
}
return null;
static DTE? TryGetDteForAttachedDebugger(Process process, int currentProcessId)
{
var dte = IntegrationHelper.TryLocateDteForProcess(process);
if (dte?.Debugger?.DebuggedProcesses?.OfType<EnvDTE.Process>().Any(p => p.ProcessID == currentProcessId) ?? false)
{
return dte;
}
return null;
}
static IEnumerable<Process> GetAncestorProcesses(Process process)
{
for (var current = TryGetParentProcess(process); current is not null; current = TryGetParentProcess(current))
{
yield return current;
}
static unsafe Process? TryGetParentProcess(Process process)
{
PROCESS_BASIC_INFORMATION pbi = default;
var returnLength = 0U;
var status = PInvoke.NtQueryInformationProcess((HANDLE)process.Handle, PROCESSINFOCLASS.ProcessBasicInformation, &pbi, (uint)Marshal.SizeOf<PROCESS_BASIC_INFORMATION>(), &returnLength);
if (status != 0)
{
return null;
}
if (pbi.InheritedFromUniqueProcessId == IntPtr.Zero)
{
return null;
}
try
{
return Process.GetProcessById(pbi.InheritedFromUniqueProcessId.ToInt32());
}
catch
{
return null;
}
}
}
}