Programmatically detach debugger

前端 未结 2 502
礼貌的吻别
礼貌的吻别 2021-01-18 02:35

I have a 3rd party library that is doing something internally that causes it to slow down greatly when the debugger is attached, even in release mode.

I have found 1

相关标签:
2条回答
  • 2021-01-18 03:08

    According to Why can't you detach in interop-debugging?, the CLR doesn't support detaching of processes. However Visual Studio can do it. But the article is 5 years old so can you use DebugActiveProcessStop from the Windows Api via pinvoke?

    BOOL WINAPI DebugActiveProcessStop(
      __in  DWORD dwProcessId
    );
    
    
    [DllImport("kernel32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool DebugActiveProcessStop([In] int Pid );
    

    Edit: Just tried this: On the current process it gives Access Denied even if elevated.

    Also is there anything in the CLR Managed Debugger (mdbg) Sample 2006 or 2011 version

    Finally this article explains what you need to do to use ICorDebug::Detach and I suppose visual studio does do this.

    0 讨论(0)
  • 2021-01-18 03:09

    Assuming you know which instance/version of Visual Studio is attached to your process, you can detach it as follows:

    object dt = Marshal.GetActiveObject("VisualStudio.DTE.12.0")
    DTE dte = (DTE)dt;
    dte.Debugger.DetachAll();
    

    The "12" is for version 2013 of Visual Studio. For another version, change accordingly. This requires a reference to EnvDTE, which is usually located at C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies\EnvDTE.dll

    This will dettach ALL processes from that instance of Visual Studio, so if, for whatever reason, Visual Studio was attached to other processes in addition to yours, those processes would also become detached. Furthermore, you may get unexpected results if you have more than one instance of Visual Studio opened.

    To be careful to only detach the current proccess and only the right instance of Visual Studio, use the following code:

    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;
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题