11

Я кодирую некоторый код времени разработки. Я хочу использовать этот фрагмент кода: (Найдено here)Получение текущего EnvDTE или IServiceProvider, когда НЕ кодируется Addin

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

Ваш 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

Привет Ваккано, я просто прочитал ваш комментарий к моему сообщению, и я рад, что мой ответ действительно помог вам !!! – Dennis

0

Мы сделали это успешно, используя этот код:

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

Это не идеально, хотя - - для этого требуется, чтобы выполнялся ровно один экземпляр Visual Studio (если их несколько, метод вернет один из них, но вы не сможете контролировать, какой из них).

+0

стрелять - просто перечитайте ваш пост и увидел, что последняя часть о нескольких экземплярах и нужна конкретная. Извините - у меня нет ничего для этого. – JMarsch

3

Вам нужен IServiceProvider, а затем вы можете вызвать его метод GetService.
dte = (DTE)serviceProvider.GetService(typeof(DTE));

Таким образом, вопрос, как получить ссылку на интерфейс IServiceProvider.

Если вы создаете VsPackage с окном инструмента (который наследует от ToolWindowPane), например, то сам implements IServiceProvider ToolWindow класс. В таком случае, когда вы хотите использовать IServiceProvider в своем элементе управления WPF, вы создаете его экземпляр в своем конструкторе окна инструмента и просто передаете 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 answer по этому вопросу: Get the reference of the DTE2 object in Visual C# 2010.

Мой подход заключается в сравнении DTE2.Solution.FullName с исполняемым контуром сборки, в этом случае поиск нужного экземпляра Visual Studio после использования того же перечисления ROT, что и в ответ Quickhorns для фильтрации возможных кандидатов.

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 
Смежные вопросы