How to automatically attach process to a specific instance of VS?

我与影子孤独终老i 提交于 2020-01-05 12:56:58

问题


I am trying to attach a process to VS by using this code:

DTE dte = (DTE)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.11.0");
EnvDTE.Processes pro = dte.Debugger.LocalProcesses;

foreach (EnvDTE.Process p in pro)
{
   if (p.ProcessID == num)
   {
      p.Attach();
      return;
   }
   else
   {
      continue;
   }
}

My problem is that I can't control to which instance of VS it gets attach to. usually its the first VS window that I opened.

How can I get a list of all the open VS instances? Thank you very much in advance!


回答1:


The only way to distinguish between running VS instances is by selecting them by the solution they have loaded. As luck would have it (wasn't luck), VS also exposes the EnvDTE.Solution object in the running object table. You can use Roman's RotView-Win32.exe utility to see what that looks like.

Some sample code that iterates the ROT and returns all active solutions:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

public class VSSolution {
    public string Name { get; set; }
    public EnvDTE.Solution Solution { get; set; }
}

public static class VSAutomation {
    public static List<VSSolution> GetRunningSolutions() {
        var instances = new List<VSSolution>();
        // Get running object table reference iterator
        IRunningObjectTable Rot;
        int hr = GetRunningObjectTable(0, out Rot);
        if (hr < 0) throw new COMException("No rot?", hr);
        IEnumMoniker monikerEnumerator;
        Rot.EnumRunning(out monikerEnumerator);

        // And iterate
        IntPtr pNumFetched = new IntPtr();
        IMoniker[] monikers = new IMoniker[1];
        while (monikerEnumerator.Next(1, monikers, pNumFetched) == 0) {
            IBindCtx bindCtx;
            int hr2 = CreateBindCtx(0, out bindCtx);
            if (hr < 0) continue;
            // Check if display ends with ".sln"
            string displayName;
            monikers[0].GetDisplayName(bindCtx, null, out displayName);
            if (displayName.EndsWith(".sln", StringComparison.CurrentCultureIgnoreCase)) {
                object obj;
                Rot.GetObject(monikers[0], out obj);
                if (obj is EnvDTE.Solution) {
                    instances.Add(new VSSolution { Name = displayName, Solution = (EnvDTE.Solution)obj });
                }
                else Marshal.ReleaseComObject(obj);
            }
        }
        return instances;
    }
    [DllImport("ole32.dll")]
    private static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);
    [DllImport("ole32.dll")]
    private static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);
}

Sample usage as tested:

    foreach (var sln in GetRunningSolutions()) {
        if (sln.Name.EndsWith("ConsoleApplication1.sln")) {
            var dte = sln.Solution.DTE;
            // etc...
        }
    }


来源:https://stackoverflow.com/questions/33756928/how-to-automatically-attach-process-to-a-specific-instance-of-vs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!