【问题标题】:Getting running Visual Studio 2010 instances and programmatically attaching to a process?正在运行 Visual Studio 2010 实例并以编程方式附加到进程?
【发布时间】:2010-07-16 20:06:07
【问题描述】:

我有一个显示进程列表的 WinForms 应用程序 (.net 3.5)。

我希望能够附加到其中一个进程。我有多个 Visual Studio 2010 实例正在运行,我想创建一个列表/下拉列表,在其中选择其中一个实例,然后将调试器附加到它。

获取 VS2010 实例应该不会太难,但我不知道如何调用“附加到进程”命令。我想避免 SendKeys-Type 解决方案,所以我想知道是否有办法做到这一点?

编辑:澄清一下:我想使用特定的运行 VS2010 来调试外部应用程序。

【问题讨论】:

  • 您想将附加到 VS2010 实例还是使用其中的1 个作为调试器?
  • 我不太确定这是否会有所帮助,因此我不会将其作为完整的解决方案发布,但我将从 Visual Studio SDK microsoft.com/downloads/… 中的 Microsoft.VisualStudio.Debugger.Interop 开始
  • @Henk 我想用VS附加到一个单独的应用程序

标签: .net visual-studio-2010 debugging remoting


【解决方案1】:

一种方法是使用 EnvDTE,它是 Visual Studio 的 COM 自动化接口:

http://msdn.microsoft.com/en-us/library/envdte(VS.100).aspx

您可以通过在运行对象表 (ROT) 中查找来获取用于运行 Visual Studio 实例的自动化接口。一旦你有了接口的实例,你就可以自动化选定的 Visual Studio 实例以附加到你想要的进程。

以下是如何执行此操作的基本示例。您需要将项目的引用添加到 EnvDTE。该程序集位于我机器上的以下位置:

C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies\EnvDTE.dll

更新

更新为通过进程 ID 获取 Visual Studio 实例自动化接口的示例。

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using EnvDTE;

namespace VS2010EnvDte
{
internal class Program
{
    [DllImport("ole32.dll")]
    public static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);

    [DllImport("ole32.dll")]
    public static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);

    private static void Main()
    {
        //ProcessId of the VS instance - hard-coded here.
        int visualStudioProcessId = 5520;

        _DTE visualStudioInstance;

        if (TryGetVSInstance(visualStudioProcessId, out visualStudioInstance))
        {
            Process processToAttachTo = null;

            //Find the process you want the VS instance to attach to...
            foreach (Process process in visualStudioInstance.Debugger.LocalProcesses)
            {
                if (process.Name == @"C:\Users\chibacity\AppData\Local\Google\Chrome\Application\chrome.exe")
                {
                    processToAttachTo = process;
                    break;
                }
            }

            //Attach to the process.
            if (processToAttachTo != null)
            {
                processToAttachTo.Attach();
            }
        }
    }

    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;
    }
}
}

【讨论】:

  • @Michael 自 VS2005 以来我就没有使用过这种技术,虽然我在 2010 年对此进行了编码并对其进行了测试,但您是否尝试过并遇到可能有用的问题?我将在不久的将来在我的应用程序中引入一个依赖这种方法的功能,并想知道您是否遇到过任何 2010 年的问题。谢谢。
  • 注意:如果调用脚本是从具有提升权限的进程调用的,TryGetVsInstance 将不会返回未以管理员身份启动的 Visual Studio 实例的 DTE 对象。
【解决方案2】:

Tim Lloyd 的回答效果很好。这是一个小的修改,它使控制台程序将调试器附加到在命令行上指定为不区分大小写的正则表达式的程序。这非常简单,因此假设只有一个 Visual Studio 实例正在运行,并且只有一个您要附加到的进程实例。

using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text.RegularExpressions;
using EnvDTE;

namespace VstAttach {
    internal static class Program {
        [DllImport("ole32.dll")]
        static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);

        [DllImport("ole32.dll")]
        static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);

        private static void Main(string[] args) {
            if (args.Length == 0)
                throw new Exception("Syntax: VstAttach ProcessName (case  insensitive regex)");
            var vst = System.Diagnostics.Process.GetProcessesByName("devenv").FirstOrDefault();
            if (vst == null)
                throw new Exception("Visual Studio not found.");
            var visualStudioProcessId = vst.Id;

            _DTE visualStudioInstance;

            if (TryGetVsInstance(visualStudioProcessId, out visualStudioInstance)) {
                var processToAttachTo = visualStudioInstance.Debugger.LocalProcesses
                    .Cast<Process>()
                    .FirstOrDefault(process => Regex.IsMatch(process.Name, args[0], RegexOptions.IgnoreCase));

                if (processToAttachTo != null) {
                    processToAttachTo.Attach();
                }
            }
        }

        private static bool TryGetVsInstance(int processId, out _DTE instance) {
            var numFetched = IntPtr.Zero;
            IRunningObjectTable runningObjectTable;
            IEnumMoniker monikerEnumerator;
            var 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;
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-31
    • 2012-01-11
    • 2018-08-04
    • 2013-02-24
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    • 2017-08-07
    相关资源
    最近更新 更多