Вопрос по visual-studio, visual-studio-2010, .net – Получение текущего EnvDTE или IServiceProvider, когда НЕ кодируется надстройка

11

Я кодирую некоторый код времени проектирования. Я хочу использовать этот фрагмент :( НайденоВот)

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. (В моем ведре дыра ...)

Вот мой вопрос:

In a normal WPF Application, how can I get the current instance of EnvDTE?

ПРИМЕЧАНИЕ. Я не ищу какой-либо старый экземпляр EnvDTE. Мне нужен один для моего текущего экземпляра Visual Studio (я запускаю 3-4 экземпляра Visual Studio одновременно.)

Является ли ваш код WPF здесь отдельным процессом, или код WPF все еще выполняется внутри Visual Studio через какой-то другой механизм? Jason Malinowski
@jason - просто нормальное приложение wpf. Я планирую запустить его во время разработки. Но я был бы счастлив с примером, который будет работать во время выполнения (например, в событии OnClick). (Создайте новое приложение wpf, перетащите кнопку в окно и дважды щелкните по нему.) Vaccano
Я нашел решение, см .:stackoverflow.com/questions/4724381/… Dennis
Вам нужно вызвать GetActiveObject с правильным именем для экземпляра VS, который вы хотите. Это та информация, которая вам нужна:msdn.microsoft.com/en-us/library/ms228755.aspx ? Simon Mourier

Ваш Ответ

5   ответов
0

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

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

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

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

На этот вопрос есть ответ, на который вы ищете.

Получить ссылку на объект DTE2 в Visual C # 2010

конкретно

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

Here is the code:

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

Как показывает другой ответ, это не работает во время отладки.

Error: User Rate Limit Exceeded
0

Я отправилответ на этот похожий вопрос:Получить ссылку на объект DTE2 в 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
3

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

So the question is how to get a reference to the IServiceProvider interface.

Если вы создаетеVSPackage с окном инструмента (который наследует отToolWindowPane), например, сам класс ToolWindowреализует IServiceProvider. In such case when you want to use IServiceProvider in your WPF control, you create its instance on your tool window constructor and simply pass 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)
Error: User Rate Limit Exceededbased on what do you want to select the EnvDTE instance?Error: User Rate Limit Exceeded"old/new instance of EnvDTE" для тебя? Это старая / новая версия EnvDTE или вы ссылаетесь на последний экземпляр Visual Studio, который был вызван в хронологическом порядке?
Error: User Rate Limit Exceeded Vaccano
Error: User Rate Limit Exceeded Vaccano

Похожие вопросы