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

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

这可能吗?

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


将VS调试器附加到进程

手动

  1. 打开Windows任务管理器( Ctrl + Shift + Esc )。
  2. 转到选项卡Processes
  3. 右键单击该过程。
  4. 选择Debug

或者,在Visual Studio中,选择“ Debug > Attach to Process...

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

自动使用C#

注意事项:以下代码是脆弱的,因为某些值(例如Visual Studio版本号)是硬编码的。 如果您计划分发您的计划,请记住这一点。

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

因为您正在与COM交互,所以您需要确保使用STAThreadAttribute修饰Main方法(应用程序的入口点)。

然后,您需要定义IOleMessageFilter接口 , 该接口允许您与定义的COM方法进行交互(请注意ComImportAttribute )。 我们需要访问消息filter,以便我们可以在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是我们与非托管消息filter代码的连接 – 您可以在MSDN上阅读extern关键字 。

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

 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(); return processes.SingleOrDefault(x => x.ProcessID == processID); } 

看一下这个

 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 processes = dte.Debugger.LocalProcesses.OfType(); 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); } } 
  • 如何:创建并附加到Visual Studio的另一个实例
  • 如何:修复“应用程序忙”和“被调用者拒绝调用”错误

更简单的方法。

 public static void Attach(DTE2 dte) { var processes = dte.Debugger.LocalProcesses; foreach (var proc in processes.Cast().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()); 

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

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