11

我正在編寫一些設計時間代碼。我想用這個片段:(找到here在不對外部地址進行編碼時獲取當前的EnvDTE或IServiceProvider

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實例。)

+0

就是這裏你WPF代碼一個單獨的進程完全,或WPF代碼還在裏面視覺運行工作室通過其他機制? –

+0

@jason - 只是一個正常的WPF應用程序。我計劃在設計時運行它。但是我會很滿意一個可以在運行時工作的例子(例如在一個OnClick事件中)。 (創建一個新的WPF應用程序,在窗口上拖動一個按鈕,然後雙擊它。) – Vaccano

+1

您需要使用正確的名稱來調用GetActiveObject以獲得所需的VS實例。這是您需要的信息:http://msdn.microsoft.com/en-us/library/ms228755.aspx? –

回答

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; 
} 

至於對方的回答表明,這並不在調試工作。

+0

嗨Vaccano,我只是讀了你的評論我的帖子,我很高興我的回答確實幫助你! – Dennis

0

我們已經做到了這一點成功使用此代碼:

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

它並不完美,但 - - 它需要正好運行1個Visual Studio實例(如果有多個,該方法將返回其中的一個,但無法控制哪一個)。

+0

拍攝 - 只需重新閱讀你的帖子,看到最後一部分關於多個實例,並需要一個特定的。對不起 - 我什麼都沒有。 – JMarsch

3

你需要一個IServiceProvider然後你可以調用它的GetService方法。
dte = (DTE)serviceProvider.GetService(typeof(DTE));

所以現在的問題是如何獲取到IServiceProvider接口的引用。

如果創建了一個工具窗口VsPackage(從ToolWindowPane繼承),例如,那麼工具窗口類本身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) 
+0

唉,正如我所說,這是一個「正常的WPF應用程序」。沒有實現工具或軟件包。 – Vaccano

+0

@Vaccano如果您正在運行獨立的WPF應用程序,**基於您想要選擇EnvDTE實例的什麼?**什麼是_「EnvDTE的舊/新實例」_適合您?它是EnvDTE的舊版本還是新版本?還是您指的是按時間順序調用的最後一個Visual Studio實例? –

+0

我可以看到我困惑的地方。我這樣做是因爲我想將一些設計時間元素添加到WPF應用程序(普通的WPF應用程序)。但我沒有模板或加載項。只是一個正常的WPF應用程序。來自Quickhorn的答案最終爲我工作。 – Vaccano

0

我已經在此類似的問題上發佈了an answerGet the reference of the DTE2 object in Visual C# 2010

我的方法是將DTE2.Solution.FullName與正在執行的程序集路徑進行比較,以這種方式在使用與Quickhorns中相同的ROT枚舉答案來篩選可能的候選項後,找到正確的Visual Studio實例。

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 
相關問題