我编码了一些设计时间码。 我想利用这个片段:(发现这里 )
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