[英]Can I programmatically attach a running .NET 6 process to a running instance of Visual Studio debugger?
我正在調試一個 IPC 邏輯,其中一個 .NET 6 個進程正在啟動另一個進程,但我無法在同一個 Visual Studio 2022 實例中同時調試這兩個進程。
當子進程命中DebugBreak(true)
時,如下所示:
[Conditional("ATTACH_DEBUGGER")]
public static void DebugBreak(bool condition)
{
if (condition)
{
if (!System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debugger.Launch();
System.Diagnostics.Debugger.Break();
}
}
}
我被提示啟動一個新的 VS2022 實例來調試它:
但是,如果我已經在調試父進程,我想在現有的 VS 實例中調試它。
這可能嗎? 是否有我可能缺少的 VS 配置設置?
當前解決方法:手動附加,同時使用下面的WaitForDebugger()
將子進程置於等待 state 中:
[Conditional("ATTACH_DEBUGGER")]
public static void WaitForDebugger()
{
using var process = Process.GetCurrentProcess();
Console.WriteLine($"Waiting for debugger, process: {process.ProcessName}, id: {process.Id}, Assembly: {Assembly.GetExecutingAssembly().Location}");
while (!System.Diagnostics.Debugger.IsAttached)
{
// hit Esc to continue without debugger
if (Console.KeyAvailable && Console.ReadKey(intercept: true).KeyChar == 27)
{
break;
}
Thread.Sleep(TimeSpan.FromSeconds(1));
Console.Beep(frequency: 1000, duration: 50);
}
}
我有一個非常相似的設置,其中以下步驟實現了這一點。 但是,這是.NET 框架,所以我不能保證它能與 .NET 核心一起使用。 (更新:.NET 核心方法見下文;GitHub上完整代碼示例的鏈接見末尾。)
首先,在您的第一個進程(例如FirstProcess
)中確定一個點,您希望將調試器附加到第二個進程( SecondProcess
)。 顯然, SecondProcess
需要運行(例如SecondProcess.exe
)。
打開 Solution Explorer 並導航到FirstProcess
中相關項目的References
。 右鍵單擊,搜索“env”並添加兩個引用, EnvDTE (v.8.0.0.0)
和EnvDTE80 (v.8.0.0.0)
。
從要附加的位置將以下方法添加到FirstProcess
中的 class:
private static void Attach(DTE2 dte)
{
var processName = "SecondProcess.exe";
var processes = dte.Debugger.LocalProcesses;
// Note: Depending on your setup, consider whether an exact match is required instead of using .IndexOf()
foreach (var proc in processes.Cast<EnvDTE.Process>().Where(proc => proc.Name.IndexOf(processName) != -1))
{
proc.Attach();
}
}
private static DTE2 GetCurrent()
{
// Note: "16.0" is for Visual Studio 2019; you might need to tweak this for VS2022.
var dte2 = (DTE2)Marshal.GetActiveObject("VisualStudio.DTE.16.0");
return dte2;
}
Visual Studio 現在應提示您將以下引用添加到您的 class:
using System.Runtime.InteropServices;
using EnvDTE80;
最后,在FirstProcess
中您希望將調試器附加到SecondProcess
的位置插入以下行:
Attach(GetCurrent());
如果您設法使它正常工作,請隨時編輯此答案,並根據 .NET 核心環境所需的任何更改進行修改。
更新 - 對於 .NET 核心:
對於 .NET 核心有兩個問題需要克服:
envdte
和envdte80
(均由 Microsoft 提供,下載量超過 200 萬)添加到FirstProcess
。Marshal.GetActiveObject()
方法在 .NET Core 中不可用。 要解決此問題,您可以從 Microsoft( 此處)獲取源代碼並手動添加; 這已在下面的代碼示例中完成。 以下是FirstProcess
的完整工作 .NET 核心代碼示例。 這在啟動后以編程方式正確附加到SecondProcess
。
namespace FirstProcess
{
using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Threading;
using EnvDTE80;
class Program
{
private const string FileName = "C:\\Users\\YourUserName\\source\\repos\\TwoProcessesSolution\\SecondProcess\\bin\\Debug\\net5.0\\SecondProcess.exe";
private const string ProcessName = "SecondProcess";
static void Main(string[] args)
{
var childProcess = Process.Start(new ProcessStartInfo(FileName));
Attach(GetCurrent());
while (true)
{
// Your code here.
Thread.Sleep(1000);
}
childProcess.Kill();
}
private static void Attach(DTE2 dte)
{
var processes = dte.Debugger.LocalProcesses;
// Note: Depending on your setup, consider whether an exact match is required instead of using .IndexOf()
foreach (var proc in processes.Cast<EnvDTE.Process>().Where(proc => proc.Name.IndexOf(ProcessName) != -1))
{
proc.Attach();
}
}
private static DTE2 GetCurrent()
{
// Note: "16.0" is for Visual Studio 2019; you might need to tweak this for VS2022.
var dte2 = (DTE2)Marshal2.GetActiveObject("VisualStudio.DTE.16.0");
return dte2;
}
public static class Marshal2
{
internal const String OLEAUT32 = "oleaut32.dll";
internal const String OLE32 = "ole32.dll";
[System.Security.SecurityCritical] // auto-generated_required
public static Object GetActiveObject(String progID)
{
Object obj = null;
Guid clsid;
// Call CLSIDFromProgIDEx first then fall back on CLSIDFromProgID if
// CLSIDFromProgIDEx doesn't exist.
try
{
CLSIDFromProgIDEx(progID, out clsid);
}
// catch
catch (Exception)
{
CLSIDFromProgID(progID, out clsid);
}
GetActiveObject(ref clsid, IntPtr.Zero, out obj);
return obj;
}
//[DllImport(Microsoft.Win32.Win32Native.OLE32, PreserveSig = false)]
[DllImport(OLE32, PreserveSig = false)]
[ResourceExposure(ResourceScope.None)]
[SuppressUnmanagedCodeSecurity]
[System.Security.SecurityCritical] // auto-generated
private static extern void CLSIDFromProgIDEx([MarshalAs(UnmanagedType.LPWStr)] String progId, out Guid clsid);
//[DllImport(Microsoft.Win32.Win32Native.OLE32, PreserveSig = false)]
[DllImport(OLE32, PreserveSig = false)]
[ResourceExposure(ResourceScope.None)]
[SuppressUnmanagedCodeSecurity]
[System.Security.SecurityCritical] // auto-generated
private static extern void CLSIDFromProgID([MarshalAs(UnmanagedType.LPWStr)] String progId, out Guid clsid);
//[DllImport(Microsoft.Win32.Win32Native.OLEAUT32, PreserveSig = false)]
[DllImport(OLEAUT32, PreserveSig = false)]
[ResourceExposure(ResourceScope.None)]
[SuppressUnmanagedCodeSecurity]
[System.Security.SecurityCritical] // auto-generated
private static extern void GetActiveObject(ref Guid rclsid, IntPtr reserved, [MarshalAs(UnmanagedType.Interface)] out Object ppunk);
}
}
}
注 1:這是針對Visual Studio 2019 和 .NET Core 5的。 我希望這適用於 VS2022 和 .NET Core 6,只需對上面注釋的 Visual Studio 版本進行一次更改。
注意 2:您將只需要打開一個 Visual Studio 實例(盡管如果這不可能,代碼可能很容易修復)。
可下載演示
.NET Framework (v4.7.2) 和 .NET Core (v5.0) 的完整工作示例可在 GitHub 此處獲得: https://github.com/NeilTalbott/VisualStudioAutoAttacher
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.