我从事的一个项目在测试期间启动了本地流程。除其他功能外,它还会启动运行.NET网站的IISExpress实例。
我可以通过将调试器手动附加到IISExpress进程来调试网站代码。但是,我想自动执行此手动步骤。
下面是我到目前为止的代码。似乎确实找到了要附加的过程(即调用了Attach2
)。但是,即使调用了Attach2
,网站代码中的断点仍然没有被击中(它们显示为带有白色填充的红色圆圈)。
我在做什么错了?
public class DebuggerHelper
{
[DllImport("ole32.dll")]
private static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);
public static bool TryAttachProcessesToVisualStudioDebuggingCurrentProcess(params int[] processIds)
{
var notAttached = processIds.Length;
var currentProcessId = System.Diagnostics.Process.GetCurrentProcess().Id;
IBindCtx bindCtx = null;
IRunningObjectTable runningObjectTable = null;
IEnumMoniker enumMonikers = null;
try
{
Marshal.ThrowExceptionForHR(CreateBindCtx(0, out bindCtx));
bindCtx.GetRunningObjectTable(out runningObjectTable);
runningObjectTable.EnumRunning(out enumMonikers);
enumMonikers.Reset();
var numFetched = IntPtr.Zero;
var monikers = new IMoniker[1];
while (enumMonikers.Next(1, monikers, numFetched) == 0)
{
monikers[0].GetDisplayName(bindCtx, null, out var runningObjectName);
runningObjectTable.GetObject(monikers[0], out var runningObjectVal);
if (runningObjectVal is EnvDTE80.DTE2 dte
&& runningObjectName.StartsWith("!VisualStudio.DTE.15.0"))
{
foreach (EnvDTE80.Process2 debuggedProcess in dte.Debugger.DebuggedProcesses)
{
if (debuggedProcess.ProcessID == currentProcessId)
{
foreach (EnvDTE80.Process2 localProcess in dte.Debugger.LocalProcesses)
{
if (processIds.Contains(localProcess.ProcessID))
{
localProcess.Attach();
notAttached--;
}
}
}
}
}
}
return notAttached == 0;
}
finally
{
if (enumMonikers != null)
{
Marshal.ReleaseComObject(enumMonikers);
}
if (runningObjectTable != null)
{
Marshal.ReleaseComObject(runningObjectTable);
}
if (bindCtx != null)
{
Marshal.ReleaseComObject(bindCtx);
}
}
}
}
编辑:似乎有些附加,但有些地方失败了。我得到以下信息:
答案 0 :(得分:0)
原来,调试器是作为本地进程而不是托管进程附加到IISExpress的。更改代码以改为使用Attach2
并指定托管后,它可以按预期工作。
更新后的工作代码(可能不需要其他一些更改,而仅仅是故障排除过程的结果)
public class DebugHelper
{
[DllImport("ole32.dll")]
static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);
[DllImport("ole32.dll")]
static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);
public static bool AttachTo(params int[] processIds)
{
var notAttached = processIds.Length;
var maybeDebuggedProcessId = System.Diagnostics.Process.GetCurrentProcess().Id;
IRunningObjectTable runningObjectTable = null;
IEnumMoniker enumMoniker = null;
IBindCtx bindCtx = null;
try
{
CreateBindCtx(0, out bindCtx);
GetRunningObjectTable(0, out runningObjectTable);
runningObjectTable.EnumRunning(out enumMoniker);
var monikers = new IMoniker[1];
var numFetched = IntPtr.Zero;
while (enumMoniker.Next(1, monikers, numFetched) == 0)
{
monikers[0].GetDisplayName(bindCtx, null, out var runningObjectName);
runningObjectTable.GetObject(monikers[0], out var runningObjectVal);
if (runningObjectVal is DTE2 dte
&& dte.Debugger is Debugger2 debugger
&& runningObjectName.StartsWith("!VisualStudio.DTE.15.0"))
{
foreach (Process2 debuggedProcess in dte.Debugger.DebuggedProcesses)
{
if (debuggedProcess.ProcessID == maybeDebuggedProcessId)
{
var def = debugger.Transports.Item("Default");
var engines = new List<Engine>();
foreach (Engine engine in def.Engines)
{
engines.Add(engine);
}
var debugEngine = new[]
{
engines.Single(x => x.Name == "Managed (v4.6, v4.5, v4.0)")
};
foreach (Process2 localProcess in dte.Debugger.LocalProcesses)
{
if (processIds.Contains(localProcess.ProcessID))
{
localProcess.Attach2(debugEngine);
notAttached--;
}
}
break;
}
}
}
}
return notAttached == 0;
}
finally
{
if (bindCtx != null) Marshal.ReleaseComObject(bindCtx);
if (runningObjectTable != null) Marshal.ReleaseComObject(runningObjectTable);
if (enumMoniker != null) Marshal.ReleaseComObject(enumMoniker);
}
}
}