C# 以编程方式分离调试器

C# 以编程方式分离调试器,c#,.net,debugging,C#,.net,Debugging,我有一个第三方库,它在内部执行一些操作,导致在连接调试器时,即使在发布模式下,它也会大大减慢速度 我已经找到了关于如何在VisualStudio中通过转到Debug->detach process手动分离调试器的100种解释。然而,我还没有看到有人提供一个例子,在这个例子中,一个程序可以将任何附加的调试器分离到它自己 基本上有分离版本吗?根据,CLR不支持分离进程。但是VisualStudio可以做到这一点。但是这篇文章已经5年了,所以你可以通过pinvoke使用Windows Api吗 BOO

我有一个第三方库,它在内部执行一些操作,导致在连接调试器时,即使在发布模式下,它也会大大减慢速度

我已经找到了关于如何在VisualStudio中通过转到
Debug->detach process
手动分离调试器的100种解释。然而,我还没有看到有人提供一个例子,在这个例子中,一个程序可以将任何附加的调试器分离到它自己

基本上有分离版本吗?

根据,CLR不支持分离进程。但是VisualStudio可以做到这一点。但是这篇文章已经5年了,所以你可以通过pinvoke使用Windows Api吗

BOOL WINAPI DebugActiveProcessStop(
  __in  DWORD dwProcessId
);


[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DebugActiveProcessStop([In] int Pid );
编辑:刚刚尝试了以下操作:在当前进程上,即使提升了权限,也会拒绝访问

手术室里还有什么东西吗


最后是本文,我想visualstudio就是这么做的

假设您知道哪个Visual Studio实例/版本连接到您的进程,您可以按如下方式分离它:

object dt = Marshal.GetActiveObject("VisualStudio.DTE.12.0")
DTE dte = (DTE)dt;
dte.Debugger.DetachAll();
“12”表示Visual Studio 2013版。对于另一个版本,请进行相应更改。这需要对EnvDTE的引用,它通常位于C:\Program Files(x86)\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblys\EnvDTE.dll

这将从VisualStudio实例中分离所有进程,因此,无论出于何种原因,如果VisualStudio附加到除您之外的其他进程,这些进程也将分离。此外,如果打开了多个Visual Studio实例,则可能会得到意外的结果

要小心仅分离当前进程和Visual Studio的正确实例,请使用以下代码:

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using EnvDTE;

public class Test
{
    public static void DetachCurrentProcesses()
    {
        System.Diagnostics.Process[] procs = System.Diagnostics.Process.GetProcessesByName("devenv");

        DTE dte = null;

        foreach (System.Diagnostics.Process devenv in procs) {
            do {
                System.Threading.Thread.Sleep(2000);
                dte = AutomateVS.GetDTE(devenv.Id);
            } while (dte == null);

            IEnumerable<Process> processes = dte.Debugger.DebuggedProcesses.OfType<Process>();

            if (!processes.Any)
                continue;

            int currentID = System.Diagnostics.Process.GetCurrentProcess().Id;

            processes.Where(p => p.ProcessID == currentID).ToList.ForEach(p => p.Detach(false));

            Marshal.ReleaseComObject(dte);
        }
    }
}

/// <summary>
/// Source to this class:  http://blogs.msdn.com/b/kirillosenkov/archive/2011/08/10/how-to-get-dte-from-visual-studio-process-id.aspx
/// </summary>
/// <remarks></remarks>
public class AutomateVS
{
    [DllImport("ole32.dll")]
    private static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);

    public static DTE GetDTE(int processId)
    {
        string progId = "!VisualStudio.DTE.10.0:" + processId.ToString();
        object runningObject = null;

        IBindCtx bindCtx = null;
        IRunningObjectTable rot = null;
        IEnumMoniker enumMonikers = null;

        try
        {
            Marshal.ThrowExceptionForHR(CreateBindCtx(reserved: 0, ppbc: out bindCtx));
            bindCtx.GetRunningObjectTable(out rot);
            rot.EnumRunning(out enumMonikers);

            IMoniker[] moniker = new IMoniker[1];
            IntPtr numberFetched = IntPtr.Zero;
            while (enumMonikers.Next(1, moniker, numberFetched) == 0)
            {
                IMoniker runningObjectMoniker = moniker[0];

                string name = null;

                try
                {
                    if (runningObjectMoniker != null)
                    {
                        runningObjectMoniker.GetDisplayName(bindCtx, null, out name);
                    }
                }
                catch (UnauthorizedAccessException)
                {
                    // Do nothing, there is something in the ROT that we do not have access to.
                }

                if (!string.IsNullOrEmpty(name) && string.Equals(name, progId, StringComparison.Ordinal))
                {
                    Marshal.ThrowExceptionForHR(rot.GetObject(runningObjectMoniker, out runningObject));
                    break;
                }
            }
        }
        finally
        {
            if (enumMonikers != null)
            {
                Marshal.ReleaseComObject(enumMonikers);
            }

            if (rot != null)
            {
                Marshal.ReleaseComObject(rot);
            }

            if (bindCtx != null)
            {
                Marshal.ReleaseComObject(bindCtx);
            }
        }

        return (DTE)runningObject;
    }

}
使用系统;
使用System.Runtime.InteropServices;
使用System.Runtime.InteropServices.ComTypes;
使用EnvDTE;
公开课考试
{
公共静态进程()
{
System.Diagnostics.Process[]procs=System.Diagnostics.Process.getProcessByName(“devenv”);
DTE DTE=null;
foreach(过程中的系统诊断过程开发){
做{
系统线程线程睡眠(2000);
dte=AutomateVS.GetDTE(devenv.Id);
}while(dte==null);
IEnumerable processs=dte.Debugger.DebuggedProcesses.OfType();
如果(!processs.Any)
持续
int currentID=System.Diagnostics.Process.GetCurrentProcess().Id;
processs.Where(p=>p.ProcessID==currentID).ToList.ForEach(p=>p.Detach(false));
元帅发布对象(dte);
}
}
}
/// 
///该类的来源:http://blogs.msdn.com/b/kirillosenkov/archive/2011/08/10/how-to-get-dte-from-visual-studio-process-id.aspx
/// 
/// 
公共类自动机
{
[DllImport(“ole32.dll”)]
私有静态外部int CreateBindCtx(uint保留,out IBindCtx ppbc);
公共静态DTE GetDTE(int processId)
{
字符串progId=“!VisualStudio.DTE.10.0:+processId.ToString();
对象runningObject=null;
IBindCtx bindCtx=null;
IRunningObjectTable rot=null;
IEnumMoniker EnumMoniker=null;
尝试
{
Marshal.throweexceptionforhr(CreateBindCtx(保留:0,ppbc:out bindCtx));
bindCtx.GetRunningObjectTable(out rot);
rot.EnumRunning(耗尽EnumMonikes);
IMoniker[]名字=新IMoniker[1];
IntPtr numberFetched=IntPtr.Zero;
while(EnumMonikes.Next(1,名字对象,numberFetched)==0)
{
IMoniker runningObjectMoniker=名字对象[0];
字符串名称=null;
尝试
{
if(runningObjectMoniker!=null)
{
GetDisplayName(bindCtx,null,out name);
}
}
捕获(未经授权的访问例外)
{
//什么都不做,在腐烂中有我们无法接触到的东西。
}
if(!string.IsNullOrEmpty(name)&&string.Equals(name、progId、StringComparison.Ordinal))
{
Marshal.ThrowExceptionForHR(rot.GetObject(runningObjectMoniker,out runningObject));
打破
}
}
}
最后
{
if(枚举名字对象!=null)
{
Marshal.ReleaseComObject(枚举名字对象);
}
如果(rot!=null)
{
元帅释放对象(rot);
}
如果(bindCtx!=null)
{
Marshal.ReleaseComObject(bindCtx);
}
}
返回(DTE)运行对象;
}
}

正如旁注,我认为“为什么不能在互操作调试中分离”一文特别关注互操作调试,即托管代码和本机代码都在工作。看起来纯粹的托管调试总是支持分离(通过said
ICoreDebug::detach
)。这是我从未尝试过的。不过我现在会的。