【问题标题】:How to attach a debugger dynamically to a specific process如何将调试器动态附加到特定进程
【发布时间】:2009-10-26 18:22:22
【问题描述】:

我正在构建一个内部开发工具来管理我们开发环境中常用的不同流程。该工具显示被监视进程的列表,指示它们的运行状态并允许启动或停止每个进程。

我想从我的工具中添加将调试器附加到受监视进程的功能,而不是进入 Visual Studio 中的 Debug -> 附加到进程 和找到过程。

我的目标是拥有类似Debugger.Launch() 的东西,它会显示可用 Visual Studio 的列表。我不能使用Debugger.Launch(),因为它会在进行调用的进程上启动调试器。我需要像Debugger.Launch(processId) 这样的东西。

如何实现此功能?

一种解决方案可以是在每个被监控进程中实现一个命令,以便在从监控工具收到命令时调用Debugger.Launch(),但我更喜欢不需要修改被监控进程代码的东西。

附加问题:

使用Debugger.Launch() 时,未列出已附加调试器的 Visual Studio 实例。 Visual Studio 不限于一个附加的调试器,您可以在使用 Debug附加到进程时附加多个进程。

在使用Debugger.Launch() 或替代方法时如何绕过此限制?

【问题讨论】:

    标签: visual-studio debugging


    【解决方案1】:

    一位同事最终找到了使用 DTE 的解决方案,我将代码发布在 PasteBin 上。

    感兴趣的方法是AttachVisualStudioToProcessTryGetVsInstance

    Source Code

    public static void AttachVisualStudioToProcess(Process visualStudioProcess, Process applicationProcess)
    {
        _DTE visualStudioInstance;
    
        if (TryGetVsInstance(visualStudioProcess.Id, out visualStudioInstance))
        {
            //Find the process you want the Visual Studio instance to attach to...
            DTEProcess processToAttachTo = visualStudioInstance.Debugger.LocalProcesses.Cast<DTEProcess>().FirstOrDefault(process => process.ProcessID == applicationProcess.Id);
    
            // Attach to the process.
            if (processToAttachTo != null)
            {
                processToAttachTo.Attach();
    
                ShowWindow((int)visualStudioProcess.MainWindowHandle, 3);
                SetForegroundWindow(visualStudioProcess.MainWindowHandle);
            }
            else
            {
                throw new InvalidOperationException("Visual Studio process cannot find specified application '" + applicationProcess.Id + "'");
            }
        }
    }
    
    private static bool TryGetVsInstance(int processId, out _DTE instance)
    {
        IntPtr numFetched = IntPtr.Zero;
        IRunningObjectTable runningObjectTable;
        IEnumMoniker monikerEnumerator;
        IMoniker[] monikers = new IMoniker[1];
    
        GetRunningObjectTable(0, out runningObjectTable);
        runningObjectTable.EnumRunning(out monikerEnumerator);
        monikerEnumerator.Reset();
    
        while (monikerEnumerator.Next(1, monikers, numFetched) == 0)
        {
            IBindCtx ctx;
            CreateBindCtx(0, out ctx);
    
            string runningObjectName;
            monikers[0].GetDisplayName(ctx, null, out runningObjectName);
    
            object runningObjectVal;
            runningObjectTable.GetObject(monikers[0], out runningObjectVal);
    
            if (runningObjectVal is _DTE && runningObjectName.StartsWith("!VisualStudio"))
            {
                int currentProcessId = int.Parse(runningObjectName.Split(':')[1]);
    
                if (currentProcessId == processId)
                {
                    instance = (_DTE)runningObjectVal;
                    return true;
                }
            }
        }
    
        instance = null;
        return false;
    }
    

    【讨论】:

    • 您是否为此制作了自定义 VS 插件?或者你是如何“连接起来”的?我也有类似的需求。我在这里盯着你的代码,但在寻找你如何在你的最终解决方案中连接它。谢谢。
    • 我们没有制作 VS 插件,我们在监控产品流程的自定义工具中使用了该代码。
    • 我正在使用此代码,但我不知道如何告诉 VS 附加到托管代码。附加到进程对话框询问“附加到:”,您可以在其中选择托管代码而不是自动检测。调试 IISExpress 进程时需要设置此项。知道如何在代码中选择它吗?
    • 自动检测应该适用于IISExpress进程,但如果你真的需要指定引擎,你可以使用Process2.Attach2,msdn.microsoft.com/en-us/library/…
    • 注意:如果调用脚本是从具有提升权限的进程调用的,TryGetVsInstance 将不会返回未以管理员身份启动的 Visual Studio 实例的 DTE 对象。
    【解决方案2】:

    WinDbg 默认对原生代码进行链式调试。如果要启动另一个 Visual Studio 实例,请查看 MSDN 上的Launch the Debugger Automatically

    要自动化现有的调试器,请使用 Marshal.GetActiveObject 获取当前的 EnvDTE.Debugger,然后让它附加到您刚刚创建的进程。

    有时,您可能需要调试由另一个进程启动的应用程序的启动代码。示例包括服务和自定义设置操作。在这些情况下,您可以启动调试器并在应用程序启动时自动附加。

    设置应用程序以自动启动调试器

    1. 启动注册表编辑器 (regedit)。

    2. 在注册表编辑器中,打开 HKEY_LOCAL_MACHINE 文件夹。

    3. 导航到 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\currentversion\image 文件执行选项。

    4. Image File Execution Options 文件夹中,找到您要调试的应用程序的名称,例如 myapp.exe。如果找不到要调试的应用程序:

      一个。右击Image File Execution Options文件夹,在快捷菜单上点击New Key

      b.右键单击新键,然后在快捷菜单上单击重命名

      c。将键名编辑为您的应用程序的名称; myapp.exe,在本例中。

    5. 右击myapp.exe文件夹,在快捷菜单上点击New String Value

    6. 右键单击新字符串值,然后在快捷菜单上单击重命名

    7. 把名字改成debugger

    8. 右键单击新字符串值,然后在快捷菜单上单击修改编辑字符串对话框出现。

    9. 数值数据框中,输入vsjitdebugger.exe

    10. 点击确定

    11. 注册表菜单中,点击退出

    12. 包含 vsjitdebugger.exe 的目录必须在您的系统路径中。要将其添加到系统路径,请按照下列步骤操作:

      一个。在经典视图中打开控制面板,然后双击系统

      b.点击高级系统设置

      c。在系统属性中,点击高级标签。

      d。在高级标签上,点击环境变量

      e。在环境变量对话框的系统变量下,选择路径,然后点击编辑按钮。

      f。在 Edit System Variable 对话框中,将目录添加到 Variable value 框中。使用分号将其与列表中的其他条目分开。

      g.单击确定关闭编辑系统变量对话框。

      h。单击确定关闭环境变量对话框。

      我。单击确定关闭系统属性对话框。

    现在,使用任何方法启动您的应用程序。 Visual Studio 将启动并加载应用程序。

    【讨论】:

    • 您提供的链接指示如何在附加调试器的情况下启动进程。我想在已经运行的进程上附加调试器。阅读文章后,我检查了有关 vsjitdebugger 的文档以及我所需要的:vsjitdebugger -p ProcessId。感谢您为我指明方向。知道如何附加到处于调试模式的视觉工作室吗? “Visual Studio Just-in-time debugger”中显示的Visual Studio列表不显示。
    • 什么意思?将调试器附加到正在调试其他内容的 Visual Studio?这有什么好处?
    • 我的意思是只使用一个 Visual Studio 实例来调试多个进程。可以从“调试 -> 附加到进程”中执行此操作,但 JIT 调试器对话框不会显示处于调试模式的 Visual Studio 实例。
    • 就我而言,这将很有用,因为受监控的进程共享一个通用的 Visual Studio 解决方案。这个方案比较大,也很耗内存,所以只用一个实例去调试多个进程可以节省很多内存。
    • 那么你可能需要一个 Visual Studio 扩展来自动化它。
    【解决方案3】:

    以下是有关如何以编程方式将调试器附加到多个进程的一些信息:

    【讨论】:

    • 虽然这在理论上可以回答问题,it would be preferable 在这里包含答案的基本部分,并提供链接以供参考。
    猜你喜欢
    • 1970-01-01
    • 2010-10-07
    • 2012-03-21
    • 1970-01-01
    • 2012-02-11
    • 2023-03-07
    • 2019-01-31
    • 2019-08-12
    • 2018-10-15
    相关资源
    最近更新 更多