我正在编写一些设计时代码。我想使用此代码段:(找到here)
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实例(我一次运行3-4个Visual Studio实例。)
答案 0 :(得分:8)
这个问题有你正在寻找的答案。
Get the reference of the DTE2 object in Visual C# 2010
具体地
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;
}
正如另一个答案所示,调试时这不起作用。
答案 1 :(得分:3)
您需要一个IServiceProvider,然后您可以调用其GetService方法
dte = (DTE)serviceProvider.GetService(typeof(DTE));
所以问题是如何获得对IServiceProvider
界面的引用。
例如,如果要使用工具窗口(继承自VsPackage)创建ToolWindowPane,则ToolWindow类本身implements 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)
答案 2 :(得分:0)
我们已成功使用此代码:
System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.10.0")
虽然它并不完美 - 它要求正好运行一个Visual Studio实例(如果有多个,则该方法将返回其中一个,但您无法控制哪一个)。
答案 3 :(得分:0)
我已在此类似问题上发布了an answer:Get the reference of the DTE2 object in Visual C# 2010。
我的方法是将DTE2.Solution.FullName与正在执行的程序集路径进行比较,这样就可以在使用与Quickhorns相同的ROT枚举后回答过滤可能的候选者。
答案 4 :(得分:0)
对于任何有兴趣使用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