将C#中的调试器附加到另一个进程

时间:2012-08-04 20:39:01

标签: c# debugging

我希望能够自动附加调试器,例如:System.Diagnostics.Debugger.Launch(),而不是当前进程到另一个命名进程。我有一个进程名称和PID来识别其他进程。

这可能吗?

4 个答案:

答案 0 :(得分:26)

修改 GSerjo提供了正确的解决方案。我想就如何改进它(和解释)分享一些想法。我希望我的改进答案对遇到同样问题的其他人有用。


将VS调试器附加到进程

手动

  1. 打开Windows任务管理器( Ctrl + Shift + Esc )。
  2. 转到标签Processes
  3. 右键单击该过程。
  4. 选择Debug
  5. 或者,在Visual Studio中,选择Debug > Attach to Process...

    结果将取决于您是否有权访问源代码。

    自动使用C#

      

    请注意:以下代码在某些意义上是脆弱的,   例如Visual Studio版本号,是硬编码的。请记住这一点   如果您打算发布您的计划。

    首先,在项目中添加对EnvDTE的引用(右键单击解决方案资源管理器中的references文件夹,添加引用)。在下面的代码中,我将只显示不寻常的using指令;省略了using System等普通的。

    由于您是interacting with COM,因此您需要确保使用STAThreadAttribute修饰Main方法(应用程序的入口点)。

    然后,您需要define the IOleMessageFilter Interface,这将允许您与定义的COM方法进行交互(请注意ComImportAttribute)。我们需要访问消息过滤器,以便我们可以在Visual Studio COM组件阻止其中一个调用时重试。

    using System.Runtime.InteropServices;
    
    [ComImport, Guid("00000016-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IOleMessageFilter
    {
        [PreserveSig]
        int HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo);
    
        [PreserveSig]
        int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType);
    
        [PreserveSig]
        int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType);
    }
    

    现在,我们需要实现此接口以处理传入的消息:

    public class MessageFilter : IOleMessageFilter
    {
        private const int Handled = 0, RetryAllowed = 2, Retry = 99, Cancel = -1, WaitAndDispatch = 2;
    
        int IOleMessageFilter.HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo)
        {
            return Handled;
        }
    
        int IOleMessageFilter.RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType)
        {
            return dwRejectType == RetryAllowed ? Retry : Cancel;
        }
    
        int IOleMessageFilter.MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType)
        {
            return WaitAndDispatch;
        }
    
        public static void Register()
        {
            CoRegisterMessageFilter(new MessageFilter());
        }
    
        public static void Revoke()
        {
            CoRegisterMessageFilter(null);
        }
    
        private static void CoRegisterMessageFilter(IOleMessageFilter newFilter)
        {
            IOleMessageFilter oldFilter;
            CoRegisterMessageFilter(newFilter, out oldFilter);
        }
    
        [DllImport("Ole32.dll")]
        private static extern int CoRegisterMessageFilter(IOleMessageFilter newFilter, out IOleMessageFilter oldFilter);
    }
    

    我将返回值定义为常量以获得更好的可读性,并重构整个事情以消除MSDN示例中的一些重复,所以我希望你会发现它不言自明。 extern int CoRegisterMessageFilter是我们与非托管邮件过滤器代码的连接 - 您可以read up on the extern keyword at MSDN

    现在剩下的就是一些说明用法的代码:

    using System.Runtime.InteropServices;
    using EnvDTE;
    
    [STAThread]
    public static void Main()
    {
        MessageFilter.Register();
        var process = GetProcess(7532);
        if (process != null)
        {
            process.Attach();
            Console.WriteLine("Attached to {0}", process.Name);
        }
        MessageFilter.Revoke();
        Console.ReadLine();
    }
    
    private static Process GetProcess(int processID)
    {
        var dte = (DTE)Marshal.GetActiveObject("VisualStudio.DTE.10.0");
        var processes = dte.Debugger.LocalProcesses.OfType<Process>();
        return processes.SingleOrDefault(x => x.ProcessID == processID);
    }
    

答案 1 :(得分:12)

检查出来

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using EnvDTE;
using NUnit.Framework;

namespace UnitTests
{
    [TestFixture]
    public class ForTest
    {
        [STAThread]  
        [Test]
        public void Test()
        {
            var dte = (DTE) Marshal.GetActiveObject("VisualStudio.DTE.10.0");
            MessageFilter.Register();

            IEnumerable<Process> processes = dte.Debugger.LocalProcesses.OfType<Process>();
            var process = processes.SingleOrDefault(x => x.ProcessID == 6152);
            if (process != null)
            {
                process.Attach();
            }
        }
    }

    public class MessageFilter : IOleMessageFilter
    {
        //
        // Class containing the IOleMessageFilter
        // thread error-handling functions.

        // Start the filter.

        //
        // IOleMessageFilter functions.
        // Handle incoming thread requests.

        #region IOleMessageFilter Members

        int IOleMessageFilter.HandleInComingCall(int dwCallType,
                                                 IntPtr hTaskCaller, int dwTickCount, IntPtr
                                                                                          lpInterfaceInfo)
        {
            //Return the flag SERVERCALL_ISHANDLED.
            return 0;
        }

        // Thread call was rejected, so try again.
        int IOleMessageFilter.RetryRejectedCall(IntPtr
                                                    hTaskCallee, int dwTickCount, int dwRejectType)
        {
            if (dwRejectType == 2)
            // flag = SERVERCALL_RETRYLATER.
            {
                // Retry the thread call immediately if return >=0 & 
                // <100.
                return 99;
            }
            // Too busy; cancel call.
            return -1;
        }

        int IOleMessageFilter.MessagePending(IntPtr hTaskCallee,
                                             int dwTickCount, int dwPendingType)
        {
            //Return the flag PENDINGMSG_WAITDEFPROCESS.
            return 2;
        }

        #endregion

        public static void Register()
        {
            IOleMessageFilter newFilter = new MessageFilter();
            IOleMessageFilter oldFilter = null;
            CoRegisterMessageFilter(newFilter, out oldFilter);
        }

        // Done with the filter, close it.
        public static void Revoke()
        {
            IOleMessageFilter oldFilter = null;
            CoRegisterMessageFilter(null, out oldFilter);
        }

        // Implement the IOleMessageFilter interface.
        [DllImport("Ole32.dll")]
        private static extern int
            CoRegisterMessageFilter(IOleMessageFilter newFilter, out
                                                                     IOleMessageFilter oldFilter);
    }

    [ComImport, Guid("00000016-0000-0000-C000-000000000046"),
     InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IOleMessageFilter
    {
        [PreserveSig]
        int HandleInComingCall(
            int dwCallType,
            IntPtr hTaskCaller,
            int dwTickCount,
            IntPtr lpInterfaceInfo);

        [PreserveSig]
        int RetryRejectedCall(
            IntPtr hTaskCallee,
            int dwTickCount,
            int dwRejectType);

        [PreserveSig]
        int MessagePending(
            IntPtr hTaskCallee,
            int dwTickCount,
            int dwPendingType);
    }
}

答案 2 :(得分:7)

更简单的方法。

public static void Attach(DTE2 dte)
        {
            var processes = dte.Debugger.LocalProcesses;
            foreach (var proc in processes.Cast<EnvDTE.Process>().Where(proc => proc.Name.IndexOf("YourProcess.exe") != -1))
                proc.Attach();
        }

        internal static DTE2 GetCurrent()
        {
            var dte2 = (DTE2)Marshal.GetActiveObject("VisualStudio.DTE.12.0"); // For VisualStudio 2013

            return dte2;
        }

用法:

Attach(GetCurrent());

答案 3 :(得分:4)

选项是运行; vsjitdebugger.exe -p ProcessId

可以使用Process.Start在c#app中执行此操作。