How to get at EnvDTE from a plugin?

I need to access EnvDTE from my R#6/VS2010 plugin.  I see some messages from a few years ago on how to reference EnvDTE in order to do this, but the technique doesn't seem to apply to the current APIs.  Can someone outline what needs to be done here?

Thanks,
Jeremy

20 comments
Comment actions Permalink

It's not pretty, but you can get a reference to DTE2 directly through com. See http://stackoverflow.com/questions/4724381/get-the-reference-of-the-dte2-object-in-visual-c-sharp-2010 for how to accomplish this.

0
Comment actions Permalink

Have you tried simply injecting

EnvDTE
by putting it as a constructor parameter in the component where you need it?
0
Comment actions Permalink

Injecting didn't work for me:

[ActionHandler("ReplaceWithAutocomplete")]     public class ReplaceWithAutoComplete : IActionHandler     {         private readonly DTE _dte;         public ReplaceWithAutoComplete(DTE dte)         {             _dte = dte;         }         public bool Update(IDataContext context, ActionPresentation presentation, DelegateUpdate nextUpdate)         {             var textControl = context.GetData(JetBrains.TextControl.DataContext.DataConstants.TEXT_CONTROL);             return textControl != null;         }         public void Execute(IDataContext context, DelegateExecute nextExecute)         {             var textControl = context.GetData(JetBrains.TextControl.DataContext.DataConstants.TEXT_CONTROL);             if (textControl != null)             {                 _dte.ExecuteCommand("Edit.SelectCurrentWord");                 _dte.ExecuteCommand("Edit.ListMembers");             }         }     }



ReplaceWithAutoComplete constuctor is never called. Is there other ways to get DTE? I need to execute commands. Is there other way to do this?
0
Comment actions Permalink

As of ReSharper 6.1 + 7.0, Action handlers cannot have dependencies injected. They require either a parameterless constructor, or a constructor with a single argument, which can be either the string action id that the handler is for, or an instance of ActionManager.

You can get various information such as solution, project and text control from the IDataContext parameter to the Update and Execute method (look for classes called DataConstants that contain readonly instances of a DataConstant that acts as a key). But unfortunately, DTE isn't available that way.

Instead, you need to call Shell.Instance.GetComponent<DTE>(). This can be called from your action handler's constructor, and should work fine (just checked on a quick plugin, and it gets a value correctly)

Thanks
Matt

0
Comment actions Permalink

I tried to get DTE in Action constructor, but even parametless constructor is never called by Resharper. So, I am getting DTE in Execute method. Unfortunetly I am getting an exception:

Could not find the component DTE in the chain of component containers.

Here is my code:

[ActionHandler("ReplaceWithAutocomplete")]        public class ReplaceWithAutoComplete : IActionHandler     {         private DTE _dte;         private DTE Dte         {             get { return _dte ?? (_dte = Shell.Instance.GetComponent<DTE>()); }         }         public bool Update(IDataContext context, ActionPresentation presentation, DelegateUpdate nextUpdate)         {             var textControl = context.GetData(JetBrains.TextControl.DataContext.DataConstants.TEXT_CONTROL);             return textControl != null;         }         public void Execute(IDataContext context, DelegateExecute nextExecute)         {                         var textControl = context.GetData(JetBrains.TextControl.DataContext.DataConstants.TEXT_CONTROL);             if (textControl != null)             {                                                 Dte.ExecuteCommand("Edit.SelectCurrentWord");                 Dte.ExecuteCommand("Edit.ListMembers");             }         }     }



I feel like I am really close to solving this problem. Please help.
0
Comment actions Permalink

What versions of ReSharper and Visual Studio are you using? I successfully retrieved the DTE object in an action handler constructor with ReSharper 7 + VS2012.

The parameterless constructor must be called by ReSharper if Execute gets called. The only reason it isn't being called is if you have another constructor.

0
Comment actions Permalink

I am using VS2010 SP1 + ReSharper 7.0.1.1098.2760.

I referenced EnvDTE from:

c:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies\EnvDTE.dll

Runtime version: v1.0.3705
Version: 8.0.0.0

0
Comment actions Permalink

Also Execute gets called only if I remove parameterless constructor.

0
Comment actions Permalink

Hmm. I can't reproduce this. It looks like I'm using the same version of ReSharper, VS and EnvDTE.dll as you, and it all seems to work. Could you post a simple repro? You can email it to me at resharper-plugins@jetbrains.com

Matt

0
Comment actions Permalink

I created new plugin project from scratch for demo purposes. I can get DTE in new project and parameterless constructor is also called during initialization. I guess there is something wrong with my project, so problem is on my side. Thank you for your help.

0
Comment actions Permalink

It was a .NET framework version. I used 4.0. I switched to 3.5 and it fixed an issue.

0
Comment actions Permalink

Sorry for the late reply. This does (kinda) make sense. ReSharper plugins should really be .net 3.5 dlls, as ReSharper is still a .net 3.5 product. That is, it runs on the 2.0 CLR, to still support older versions of Visual Studio. I guess by having the plugin as a .net 4 assembly, it's resolving the wrong reference for envdte (perhaps it's looking in the v4 GAC rather than the v2 GAC) and it can't find the component.

Anyway, glad you got it sorted.
Matt

0
Comment actions Permalink

Matt,

Shell was removed in Resharper 9, so I can't get DTE using Shell.Instance.TryGetComponent<DTE>().

Do you know how I can get DTE in Resharper 9?

Viktar

0
Comment actions Permalink

Nevermind, I found it at JetBrains.ReSharper.Resources.Shell namespace.

Viktar

0
Comment actions Permalink

Where you able to get the DTE Viktar? I tried that code in R#9.2 with no luck.

JetBrains.ReSharper.Resources.Shell.Shell.Instance.TryGetComponent<DTE>() returns null for me.

0
Comment actions Permalink

I didn't upgraded to 9.2 yet. Shell.Instance.TryGetComponent<DTE>()  works for me with Resharper 9.1.3.

What framework version your project targeting? I am using .NET 4.0. Previosly I used some other version and had a problem. Try to switch .NET Framework version, maybe now it has to be 4.5.

Viktar

0
Comment actions Permalink

No luck. I tried 4.0, 4.5, 4.5.1 and 4.6. I am using Visual Studio 2015 and testing in the VS hive.

0
Comment actions Permalink

Another issue might be that since DTE is a COM interface, and if it's referenced with Embed COM Interop Types set to true, the System.Type used to identify the DTE object is different to the System.Type used to register it in the first place. Try rebuilding with Embed COM Interop Types set to false.

Out of curiosity, what do you want to use DTE for? There might be a more ReSharper-y way of doing what you need.

0
Comment actions Permalink

Thanks Matt, it works now!

I'm using it to do code cleanup on TFS check in files. Not sure if this would be the best way to do this but these are my steps:

  1. On TFS check in I have a check in policy thats saves the list of check in file names in a global variable in DTE
  2. the policy then fires my R# "TFSCheckInAction"
  3. in the action, I get the list from the variable in DTE, run silent cleanup code on each check in file
  4. Done!


This was a solution I came up in R#8.2, it works most of the time and hangs up VS sometimes but I couldn't find any other way to get the list of check ins from  R#

Not sure if in R#9.2 if there is a way to directly get the list of TFS check in files?

NOTE: sorry to piggy back on someone elses post.

0
Comment actions Permalink

I'm afraid I don't know anything about TFS check in. If there's a Visual Studio interface that can get the data you need, ReSharper should be able to get the interface.

0

Please sign in to leave a comment.