private static bool AttachVs()

in src/AttachVS/AttachVs.cs [78:181]


    private static bool AttachVs(Process vs, int pid)
    {
        IBindCtx bindCtx = null;
        IRunningObjectTable runninObjectTable = null;
        IEnumMoniker enumMoniker = null;
        try
        {
            var r = CreateBindCtx(0, out bindCtx);
            Marshal.ThrowExceptionForHR(r);
            if (bindCtx == null)
            {
                Trace($"BindCtx is null. Cannot attach VS.");
                return false;
            }
            bindCtx.GetRunningObjectTable(out runninObjectTable);
            if (runninObjectTable == null)
            {
                Trace($"RunningObjectTable is null. Cannot attach VS.");
                return false;
            }

            runninObjectTable.EnumRunning(out enumMoniker);
            if (enumMoniker == null)
            {
                Trace($"EnumMoniker is null. Cannot attach VS.");
                return false;
            }

            var dteSuffix = ":" + vs.Id;

            var moniker = new IMoniker[1];
            while (enumMoniker.Next(1, moniker, IntPtr.Zero) == 0 && moniker[0] != null)
            {

                moniker[0].GetDisplayName(bindCtx, null, out string dn);

                if (dn.StartsWith("!VisualStudio.DTE.") && dn.EndsWith(dteSuffix))
                {
                    object dbg, lps;
                    runninObjectTable.GetObject(moniker[0], out object dte);

                    // The COM object can be busy, we retry few times, hoping that it won't be busy next time.
                    for (var i = 0; i < 10; i++)
                    {
                        try
                        {
                            dbg = dte.GetType().InvokeMember("Debugger", BindingFlags.GetProperty, null, dte, null);
                            lps = dbg.GetType().InvokeMember("LocalProcesses", BindingFlags.GetProperty, null, dbg, null);
                            var lpn = (System.Collections.IEnumerator)lps.GetType().InvokeMember("GetEnumerator", BindingFlags.InvokeMethod, null, lps, null);

                            while (lpn.MoveNext())
                            {
                                var pn = Convert.ToInt32(lpn.Current.GetType().InvokeMember("ProcessID", BindingFlags.GetProperty, null, lpn.Current, null));

                                if (pn == pid)
                                {
                                    lpn.Current.GetType().InvokeMember("Attach", BindingFlags.InvokeMethod, null, lpn.Current, null);
                                    return true;
                                }
                            }
                        }
                        catch (COMException ex)
                        {
                            Trace($"ComException: Retrying in 250ms.\n{ex}");
                            Thread.Sleep(250);
                        }
                    }
                    Marshal.ReleaseComObject(moniker[0]);

                    break;
                }

                Marshal.ReleaseComObject(moniker[0]);
            }
            return false;
        }
        finally
        {
            if (enumMoniker != null)
            {
                try
                {
                    Marshal.ReleaseComObject(enumMoniker);
                }
                catch { }
            }
            if (runninObjectTable != null)
            {
                try
                {
                    Marshal.ReleaseComObject(runninObjectTable);
                }
                catch { }
            }
            if (bindCtx != null)
            {
                try
                {
                    Marshal.ReleaseComObject(bindCtx);
                }
                catch { }
            }
        }
    }