private static DTE? GetDebuggerHostDte()

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;
                    }
                }
            }
        }