如何获取正在运行的Visual Studio实例的DTE?

14

如何获取所有正在运行的 Visual Studio 实例,以便进行自动化?

(添加此问题是因为 这个问题 被关闭了)

2个回答

22

使用运行对象表获取所有实例,然后选择您想要的实例。

我认为您无法做得比这更好了。这类似于将调试器附加到 VS 实例的方式。您必须从列表中选择一个。

IEnumerable<DTE> GetInstances()
{
    IRunningObjectTable rot;
    IEnumMoniker enumMoniker;
    int retVal = GetRunningObjectTable(0, out rot);

    if (retVal == 0)
    {
        rot.EnumRunning(out enumMoniker);

        uint fetched = uint.MinValue;
        IMoniker[] moniker = new IMoniker[1];
        while (enumMoniker.Next(1, moniker, out fetched) == 0)
        {
            IBindCtx bindCtx;
            CreateBindCtx(0, out bindCtx);
            string displayName;
            moniker[0].GetDisplayName(bindCtx, null, out displayName);
            Console.WriteLine("Display Name: {0}", displayName);
            bool isVisualStudio = displayName.StartsWith("!VisualStudio");
            if (isVisualStudio)
            {
               object obj;
               rot.GetObject(moniker[0], out obj);
               var dte = obj as DTE;
               yield return dte;
            }
        }
    }
}

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

[DllImport("ole32.dll")]
private static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);

要使此功能在Visual Studio 2022中工作,您需要envdte nuget软件包: https://www.nuget.org/packages/envdte/17.2.32505.113


1
@Matt Ferguson 我使用这里的代码:https://code.google.com/p/tray-service-control/source/browse/TrayServiceControl/Debugging/RunningObjectTable.cs - Dave Hillier
3
请注意:如果从具有提升权限的进程中调用脚本,则此功能不会返回未以管理员身份启动的 Visual Studio 实例的 DTE 对象。 - Erwin Mayer
你的代码缺乏任何注释/文档来帮助理解它的功能和实现方式,需要进行大量的MSDN研究以了解这些WinAPI函数。不过,+1是给你写下并分享解决方案的,这对于通过评估返回的DTE对象的解决方案名称来获取当前VS实例非常有帮助(例如)。 - ElektroStudios
@ErwinMayer,你找到了一个查询所有正在运行实例的解决方案吗?而不是获取当前正在运行程序权限的所有实例? - Tobi De
很抱歉,@DarkStaR,不行。 - Erwin Mayer
显示剩余3条评论

-2
以下是VB.Net获取当前Visual Studio实例的解决方案。
我的做法是将正在调试的进程与当前程序集名称进行简单的字符串比较。当多个VS实例打开时,它似乎按预期工作。我在Visual Studio 2013的调试和发布模式下尝试过。
导入:
Imports System
Imports System.Diagnostics.CodeAnalysis
Imports System.Runtime.InteropServices
Imports System.Runtime.InteropServices.ComTypes
Imports EnvDTE80

P/Invokes:

(NativeMethods.dll)

''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Returns a pointer to an implementation of <see cref="IBindCtx"/> (a bind context object).
''' <para></para>
''' This object stores information about a particular moniker-binding operation.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <remarks>
''' <see href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms678542%28v=vs.85%29.aspx"/>
''' </remarks>
''' ----------------------------------------------------------------------------------------------------
''' <param name="reserved">
''' This parameter is reserved and must be 0.
''' </param>
''' 
''' <param name="ppbc">
''' Address of an <see cref="IBindCtx"/> pointer variable that receives the 
''' interface pointer to the new bind context object.
''' <para></para>
''' When the function is successful, the caller is responsible for calling Release on the bind context.
''' <para></para>
''' A value of <see langword="Nothing"/> for the <paramref name="ppbc"/> value indicates that an error occurred.
''' </param>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' This function can return the standard return values <c>E_OUTOFMEMORY</c> and <c>S_OK</c>.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
<SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible", justification:="Assembly Reference")>
<DllImport("ole32.dll")>
Public Shared Function CreateBindCtx(ByVal reserved As Integer,
                                     ByRef ppbc As IBindCtx
) As Integer
End Function

''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Returns a pointer to the <see cref="IRunningObjectTable"/> interface on the local running object table (ROT).
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <remarks>
''' <see href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms684004%28v=vs.85%29.aspx"/>
''' </remarks>
''' ----------------------------------------------------------------------------------------------------
''' <param name="reserved">
''' This parameter is reserved and must be 0.
''' </param>
''' 
''' <param name="pprot">
''' The address of an <see cref="IRunningObjectTable"/> pointer variable that receives the 
''' interface pointer to the local ROT.
''' <para></para>
''' When the function is successful, the caller is responsible for calling Release on the interface pointer.
''' <para></para>
''' A value of <see langword="Nothing"/> for the <paramref name="pprot"/> value indicates that an error occurred.
''' </param>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' This function can return the standard return values <c>E_UNEXPECTED</c> and <c>S_OK</c>.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
<SuppressMessage("Microsoft.Interoperability", "CA1401:PInvokesShouldNotBeVisible", justification:="Assembly Reference")>
<DllImport("ole32.dll")>
Public Shared Function GetRunningObjectTable(ByVal reserved As Integer,
                                             ByRef pprot As IRunningObjectTable
) As Integer
End Function

代码的其余部分:

''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Gets a collection of the Visual Studio instances that are running on this PC.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' An <see cref="IEnumerable(Of DTE2)"/> that contains the running Visual Studio instances, if any.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
Public Shared Iterator Function GetVisualStudioInstances() As IEnumerable(Of DTE2)

    Dim rot As IRunningObjectTable = Nothing
    Dim enumMoniker As IEnumMoniker = Nothing
    Dim retVal As Integer = NativeMethods.GetRunningObjectTable(0, rot)

    If (retVal = 0) Then

        rot.EnumRunning(enumMoniker)

        Dim fetched As IntPtr = IntPtr.Zero
        Dim moniker As IMoniker() = New IMoniker(0) {}

        While (enumMoniker.Next(1, moniker, fetched) = 0)

            Dim bindCtx As IBindCtx = Nothing
            NativeMethods.CreateBindCtx(0, bindCtx)

            Dim displayName As String = ""
            moniker(0).GetDisplayName(bindCtx, Nothing, displayName)

            If (displayName.StartsWith("!VisualStudio")) Then
                Dim obj As New Object
                rot.GetObject(moniker(0), obj)
                Yield DirectCast(obj, DTE2)
            End If

        End While

    End If

End Function

''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Gets a <see cref="DTE2"/> object that represents the current Visual Studio instance that is running this project.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' A <see cref="DTE2"/> object that represents the current Visual Studio instance that is running this project.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
Public Shared Function GetCurrentVisualStudioInstance() As DTE2

    Dim currentInstance As DTE2 = Nothing
    Dim processName As String = Process.GetCurrentProcess.MainModule.FileName
    Dim instances As IEnumerable(Of DTE2) = GetVisualStudioInstances

    For Each instance As DTE2 In instances

        For Each p As EnvDTE.Process In instance.Debugger.DebuggedProcesses

            If (p.Name = processName) Then
                currentInstance = instance
                Exit For
            End If

        Next p

    Next instance

    Return currentInstance

End Function

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接