获取当前EnvDTE或IServiceProvider的时候无需编码一个插件(Getting the

2019-07-29 17:16发布

我编码了一些设计时间码。 我想利用这个片段:(发现这里 )

var dte = (EnvDTE.DTE) GetService(typeof(EnvDTE.DTE));
if (dte != null)
{
    var solution = dte.Solution;
    if (solution != null)
    {
        string baseDir = Path.GetDirectoryName(solution.FullName);
    }
}

问题是,这并不编译。 (GetService的不是已知的方法调用),我尝试添加Microsoft.VisualStudio.Shell(和Microsoft.VisualStudio.Shell.10.0),但它并没有帮助。

在互联网上四处寻找我发现,你需要一个IServiceProvider的调用此。

但是,这表明如何获得的IServiceProvider的所有例子中使用EnvDTE。

因此,为了得到当前EnvDTE我需要的IServiceProvider。 但是为了得到一个IServiceProvider的我需要一个EnvDTE。 (有一个在我的水桶一个洞...)

所以,这里是我的问题:

在一个正常的WPF应用程序,我怎么能得到EnvDTE的当前实例

注:我不是在寻找EnvDTE的任何旧的实例。 我需要一个为我当前的Visual Studio实例(我在同一时间运行Visual Studio的3-4实例。)

Answer 1:

这个问题已经到你要找的答案。

获取在Visual C#2010 DTE2对象的引用

特别

https://stackoverflow.com/a/4724924/858142

下面是代码:

Usings:

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using EnvDTE;
using Process = System.Diagnostics.Process;

方法:

[DllImport("ole32.dll")]
private static extern void CreateBindCtx(int reserved, out IBindCtx ppbc);
[DllImport("ole32.dll")]
private static extern void GetRunningObjectTable(int reserved,
                                                 out IRunningObjectTable prot);
internal static DTE GetCurrent()
{
   //rot entry for visual studio running under current process.
   string rotEntry = String.Format("!VisualStudio.DTE.10.0:{0}",
                                    Process.GetCurrentProcess().Id);
   IRunningObjectTable rot;
   GetRunningObjectTable(0, out rot);
   IEnumMoniker enumMoniker;
   rot.EnumRunning(out enumMoniker);
   enumMoniker.Reset();
   IntPtr fetched = IntPtr.Zero;
   IMoniker[] moniker = new IMoniker[1];
   while (enumMoniker.Next(1, moniker, fetched) == 0)
   {
       IBindCtx bindCtx;
       CreateBindCtx(0, out bindCtx);
       string displayName;
       moniker[0].GetDisplayName(bindCtx, null, out displayName);
       if (displayName == rotEntry)
       {
           object comObject;
           rot.GetObject(moniker[0], out comObject);
           return (DTE)comObject;
       }
   }
   return null;
}

由于对方的回答表明,这是行不通的同时调试。



Answer 2:

你需要一个IServiceProvider的 ,然后你可以调用它的GetService方法。
dte = (DTE)serviceProvider.GetService(typeof(DTE));

所以,问题是怎么去的一个参考IServiceProvider接口。

如果你正在创建一个VSPackage的一个工具窗口(从继承ToolWindowPane ),例如,那么工具窗口类本身实现的IServiceProvider 。 在当你想在你的WPF控件使用的IServiceProvider这种情况下,你对你的工具窗口的构造函数创建的实例,只是通过this作为参数传递给您的控件的构造函数。

[Guid("f716c629-b8e3-4ab2-8dbd-8edd67165609")]
public class MyToolWindow : ToolWindowPane
{
    /// <summary>
    /// Standard constructor for the tool window.
    /// </summary>
    public MyToolWindow() :
        base(null)
    {
        ...
        // This is the user control hosted by the tool window
        base.Content = new MyControl(this);
    }

你的控制对象的构造函数IServiceProvider作为参数:

public MyControl(IServiceProvider _serviceProvider)


Answer 3:

我们已经做到了这一点成功使用此代码:

System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.10.0")

它并不完美,但 - 它需要的Visual Studio正好1个实例在运行(如果有一个以上的,该方法将返回他们中的一个,但你无法控制哪一个)。



Answer 4:

我已经发布了一个答案对这个类似的问题: 获取DTE2对象在Visual C#2010的参考 。

我的做法是与执行的程序集路径比较DTE2.Solution.FullName,这种方式寻找合适的Visual Studio实例,使用相同的ROT枚举在Quickhorns答案来筛选可能的候选人之后。



Answer 5:

有兴趣的人在F#中,一个最完整的转换是在这里做这个(当前设置为在linqpad运行):

open System;
open System.Runtime.InteropServices;
open System.Runtime.InteropServices.ComTypes;
open EnvDTE;
open System.Diagnostics;
//http://stackoverflow.com/questions/10864595/getting-the-current-envdte-or-iserviceprovider-when-not-coding-an-addin

//http://stackoverflow.com/questions/6558789/how-to-convert-out-ref-extern-parameters-to-f
//http://stackoverflow.com/questions/1689460/f-syntax-for-p-invoke-signature-using-marshalas

[<System.Runtime.InteropServices.DllImport("ole32.dll")>] 
extern int CreateBindCtx(System.IntPtr inRef, IBindCtx& outParentRef);
[<System.Runtime.InteropServices.DllImport("ole32.dll")>]
extern int GetRunningObjectTable(System.IntPtr inRef, IRunningObjectTable& outParentRef);
//let dte = System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.12.0") :?> EnvDTE80.DTE2
let comName="VisualStudio.DTE.12.0"
let rotEntry = "!"+comName
//let mutable rot:IRunningObjectTable =null

let rot=
    let mutable result:IRunningObjectTable = null
    GetRunningObjectTable(nativeint 0, &result) |> ignore
    result


let mutable enumMoniker:IEnumMoniker = null
rot.EnumRunning (&enumMoniker) 
enumMoniker.Reset() |> ignore
let mutable fetched = IntPtr.Zero
let mutable moniker:IMoniker[] = Array.zeroCreate 1 //http://msdn.microsoft.com/en-us/library/dd233214.aspx

let matches = seq {
    while enumMoniker.Next(1, moniker, fetched) = 0 do
        "looping" |> Dump
        let mutable bindCtx:IBindCtx = null
        CreateBindCtx(nativeint 0, &bindCtx) |> ignore
        let mutable displayName:string = null
        moniker.[0].GetDisplayName(bindCtx,null, &displayName)
        displayName |> Dump
        if displayName.StartsWith(rotEntry) then
            let mutable comObject = null
            rot.GetObject(moniker.[0], &comObject) |> ignore
            let dte =  comObject:?>EnvDTE80.DTE2
            yield displayName,bindCtx,comObject,dte.FullName, dte
}
matches |> Dump


文章来源: Getting the current EnvDTE or IServiceProvider when NOT coding an Addin