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