11

Estoy codificando algún código de tiempo de diseño. Quiero utilizar este fragmento: (Encontrado here)Obtener el actual EnvDTE o IServiceProvider cuando NO está codificando un 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); 
    } 
} 

El problema es que esto no se compila. (GetService no es una llamada de método conocida) Intenté agregar Microsoft.VisualStudio.Shell (y Microsoft.VisualStudio.Shell.10.0) pero no me ayudó.

Al buscar en Internet encontré que necesita un IServiceProvider para llamar a esto.

Pero todos los ejemplos que muestran cómo obtener un IServiceProvider usan un EnvDTE.

Entonces, para obtener el EnvDTE actual necesito IServiceProvider. Pero para obtener un IServiceProvider necesito un EnvDTE. (Hay un agujero en mi cubo ...)

lo tanto, aquí está mi pregunta:

en una aplicación WPF normal, ¿cómo puedo obtener la instancia actual de EnvDTE?

NOTA: No estoy buscando ninguna instancia anterior de EnvDTE. Necesito el uno para mi instancia actual de Visual Studio (corro 3-4 instancias de Visual Studio a la vez.)

+0

es su código de WPF aquí un proceso separado por completo, o código de WPF aún en marcha dentro de Visual Estudio a través de algún otro mecanismo? –

+0

@jason - Simplemente una aplicación wpf normal. Planeo ejecutarlo en tiempo de diseño. Pero estaría contento con un ejemplo que funcionaría en tiempo de ejecución (en un evento OnClick, por ejemplo). (Cree una nueva aplicación wpf, arrastre un botón en la ventana y haga doble clic en él). – Vaccano

+1

Debe llamar a GetActiveObject con un apodo apropiado para la instancia de VS que desee. ¿Es este el tipo de información que necesita: http://msdn.microsoft.com/en-us/library/ms228755.aspx? –

Respuesta

8

Esta pregunta tiene la respuesta a la que usted está buscando.

Get the reference of the DTE2 object in Visual C# 2010

Específicamente

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

Aquí está el código:

usings:

using System; 
using System.Runtime.InteropServices; 
using System.Runtime.InteropServices.ComTypes; 
using EnvDTE; 
using Process = System.Diagnostics.Process; 

Método:

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

Como indica la otra respuesta, esto no funciona durante la depuración.

+0

Hola Vaccano, acabo de leer tu comentario en mi publicación, ¡y me alegra que mi respuesta te haya ayudado! – Dennis

0

Hemos hecho esto con éxito utilizando este código:

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

No es perfecto, aunque - - requiere que se ejecute exactamente 1 instancia de Visual Studio (si hay más de uno, el método devolverá uno de ellos, pero no puede controlar cuál).

+0

disparar - solo volver a leer su publicación y vio esa última parte sobre varias instancias y necesita una específica. Lo siento, no tengo nada para eso. – JMarsch

3

Necesita un IServiceProvider y luego puede llamar a su método GetService.
dte = (DTE)serviceProvider.GetService(typeof(DTE));

Así que la pregunta es cómo obtener una referencia a la interfaz IServiceProvider.

Si va a crear un VsPackage con una ventana de herramientas (que hereda de ToolWindowPane), por ejemplo, entonces la propia clase implements IServiceProvider ToolWindow. En tal caso, cuando desee utilizar IServiceProvider en su control WPF, cree su instancia en el constructor de la ventana de la herramienta y simplemente pase this como un argumento para el constructor de su control. constructor

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

Su obtiene el control de IServiceProvider como argumento:

public MyControl(IServiceProvider _serviceProvider) 
+0

Desgraciadamente, como dije, esto es para una "aplicación WPF normal". Nada que implemente una herramienta o paquete. – Vaccano

+0

@Vaccano Si está ejecutando una aplicación WPF independiente, ** en función de qué desea seleccionar la instancia EnvDTE? ** ¿Qué es una "vieja/nueva instancia de EnvDTE" _ para usted? ¿Es una versión vieja/nueva de EnvDTE o se refiere a la última instancia de Visual Studio invocada cronológicamente? –

+0

Puedo ver dónde estaba confundiendo. Estoy haciendo esto porque quiero agregar algunos elementos de tiempo de diseño a una aplicación WPF (aplicación WPF normal). Pero no tengo una plantilla o complemento. Solo una aplicación normal de WPF. La respuesta de Quickhorn terminó trabajando para mí. – Vaccano

0

He publicado an answer sobre esta misma pregunta: Get the reference of the DTE2 object in Visual C# 2010.

Mi enfoque es comparar DTE2.Solution.FullName con la ruta del ensamblaje de ejecución, de esa manera encontrar la instancia de Visual Studio correcta, después de usar la misma enumeración ROT que en la respuesta de Quickhorns para filtrar los posibles candidatos.

0

para cualquier persona interesada en hacer esto con F # una conversión casi completa está aquí (actualmente configurado para ejecutarse en 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 
Cuestiones relacionadas