Issue #817: Set "Embed Interop Types" to False for EnvDTE in NugGet.VisualStudio.dll

Mar 11, 2011 at 10:02 PM
Embedding the types only makes the assembly bigger for no benefit.
And it does screw up debugging for anyone doing VS extensibility, where you start getting errors like this:


soln.Projects.OfType<EnvDTE.Project>()
Embedded interop type 'EnvDTE.Project' is defined in both 'EnvDTE.dll' and 'NuGet.VisualStudio.dll'. Some operations on objects of this type are not supported while debugging. Consider casting this object to type 'dynamic' when debugging or building with the 'Embed Interop Types' property set to false.


(here I was trying to inspect the current solution in a quick watch window)


/kzu

--
Daniel Cazzulino | Developer Lead | MS MVP | Clarius Consulting | +1 425.329.3471
Developer
Mar 11, 2011 at 10:14 PM

Why would we want to do this? What were you trying to do that you got those errors?

Mar 11, 2011 at 10:47 PM

It's generally advisable when doing VSX development (which my company and myself do a lot) NOT to use Embed Interop Types, which is a feature intended mostly for office PIA scenarios where the PIA assemblies are HUGE and had to be shipped with your app.

This is NEVER the case with VSX authoring. All interop assemblies you reference (EnvDTE, VS.Shell, etc.) are ALWAYS already there in the users' machine, and you NEVER need to distribute them. So embedding those types only increases your assembly size without a single benefit to you (the NuGet developer/author).

But on the other hand, it confuses the VS debugger the hell out, as I explained in the comment above.

Repro is very straight forward: just attach VS to a running instance of VS with NuGet installed, set a breakpoint in any kind of VS automation (i.e. a VS command Execute, a package Initialize method, whatever), and try to inspect the solution being debugged from either the inmediate window or quickwatch. You can't reference ANY type in EnvDTE because the debugger doesn't know WHICH EnvDTE you are referring two, because there are TWO in the AppDomain, one in the VS built-in EnvDTE.dll assembly, and one in your NuGet.VisualStudio.dll assembly (which is of course also loaded in the appdomain and which contains EnvDTE types as they are embedded!!!)

 

So, it makes it painful for everybody doing VS extensibility work, for no gain whatesoever. 

It's probably just the result of adding the reference and leaving the default behavior kick in and embed the types, and not checking whether that was needed or not. It's not, and it's well-known to cause issues in the VSX community.

 

HTH

Developer
Mar 11, 2011 at 10:55 PM

You gonna submit a patch :)?

Mar 11, 2011 at 11:07 PM

Should have saved keystrokes http://kzu.to/fINDmD

Mar 11, 2011 at 11:44 PM
for setting a property on an assembly reference? kinda overkill to fork and all that ;)

Mar 11, 2011 at 11:53 PM

no worry, I'll fix it.

Mar 12, 2011 at 2:50 AM

So I gave it a try, setting the property Embeded Interop Types to false for those two assemblies. It results in lots of compile errors :) I'm not sure if I'm doing anything wrong but maybe you can give it a try?

Mar 12, 2011 at 12:24 PM

Jeje, ok, I will

/kzu from galaxy tab

On Mar 11, 2011 11:50 PM, "dotnetjunky" <notifications@codeplex.com> wrote:
> From: dotnetjunky
>
> So I gave it a try, setting the property Embeded Interop Types to false for those two assemblies. It results in lots of compile errors :) I'm not sure if I'm doing anything wrong but maybe you can give it a try?
>
>
Developer
Mar 12, 2011 at 5:17 PM

It's not just flipping a bit. Code needs to be changed. Setting Embed Interop Types to true doesn't just make the assembly bigger, it also changes the all of the properties that return object to return dynamic instead.

Mar 12, 2011 at 5:41 PM
didn't know that. interesting!

makes sense as it's mostly for COM stuff, and the EnvDTE and friends have been around too long to have dynamic in the signatures...
Mar 12, 2011 at 6:06 PM
dfowler wrote:

It's not just flipping a bit. Code needs to be changed. Setting Embed Interop Types to true doesn't just make the assembly bigger, it also changes the all of the properties that return object to return dynamic instead.


Why didn't you say this earlier?

Mar 13, 2011 at 6:56 PM

I never saw this because flipping the bit is the very first thing we do when developing VSX extensions :(

Developer
Mar 14, 2011 at 1:15 AM

@dotnetjunky

I thought you knew :).

Mar 14, 2011 at 1:17 AM
me2 :(
Apr 20, 2011 at 2:04 PM

Just sent a pull request that fixes this issue. 

It's blocking me on the generic script to add MSBuild targets automatically on install/uninstall :(. I'm getting invalid cast exceptions from _ComObject to _ComObject :(  (this is also another symptom)

Developer
Apr 20, 2011 at 4:33 PM

Are you 100% sure it's blocking you from doing that feature? We haven't really had any problems with this feature so far so I find that weird. I also don't like the fact that we have to make our code uglier (with all the casts). Can you show me what you did that caused it to be horribly broken?

Apr 20, 2011 at 4:46 PM
Edited Apr 20, 2011 at 4:48 PM

My changes were in < 10 places.

Not embedding VS core interop assemblies is the right thing to do (would you agree?).

So, I think the justification has to go the other way: why do you want to embed the interop types which screws up everyone's ability to debug VS while doing VSX work? (i.e., just break VS, try to do anything from the Immediate window using EnvDTE types and see what I mean, i.e. use ServiceProvider.GlobalServiceProvider.GetService(typeof(EnvDTE.DTE)) and enjoy). Are you saying a few casts here and there are worth the pain of VSX authors?

BTW, MonoDroid authoring has the same issue and I'll send them a similar patch.

Developer
Apr 20, 2011 at 5:06 PM

Thats just the immediate window right. Debugging is a bit messed up, but that's the only thing right? The actual code works, you made it sound like it was blocking the change altogether...

Developer
Apr 20, 2011 at 5:08 PM

I prefer to have to code be readable instead of injecting casts everywhere. You changed 10 places but of course we'll write more code in the future and we'll have to keep adding more casts. I haven't had a huge issue with it as yet but maybe we just have different development habits. Still I'm not convinced this change needs to be made.

Apr 20, 2011 at 7:10 PM

Immediate, Quick Watch, Watch windows, etc. It's a huge PITA and there's no workaround for it other than disabling the extension with the "embed interop types" flag set. So it has a big impact, believe me.  And that PITA is totally unrelated to whichever other feature I might be spiking at the moment ;).

> Debugging is a bit messed up

Could you elaborate? Messed up by who? ;)

 

Coincidentally, because of the way I'm trying to implement the MSBuild stuff, I'm also getting the invalid cast which is a consequence of the above, although by no means the only reason why this change should be accepted.

In the package manager console (which is the way I incrementally develop my nuget scripts), I can write this code and get the invalid cast exception:

$project = Get-Project "Foo"
Add-Type -AssemblyName "Microsoft.VisualStudio.ComponentModelHost, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
Add-Type -AssemblyName "Microsoft.VisualStudio.Shell.10.0, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
Add-Type -AssemblyName NuGet.VisualStudio

  $components = [Microsoft.VisualStudio.Shell.ServiceProvider]::GlobalProvider.GetService([Microsoft.VisualStudio.ComponentModelHost.SComponentModel]);
$factory = [Microsoft.VisualStudio.ComponentModelHost.IComponentModel].GetMethod("GetService").MakeGenericMethod([NuGet.VisualStudio.IVsPackageManagerFactory]).Invoke($components, $null)
$packageManager = $factory.CreatePackageManager()
$projectManager = $packageManager.GetProjectManager($project)

That last line blows with the exception I mentioned. It wouldn't with the proposed fix. It may be that there's other ways of doing what I show there. I don't think that's relevant. It only shows ONE case where the embed interop types causes code to fail (in addition to the general reason about breaking debugging for every vsx author).

 

> I prefer to have to code be readable instead of injecting casts everywhere

That point is moot since you're already building your own abstraction on top of the DTE (IProjectSystem) and you have strong-types there. I'm confident you'll be building that further over time, rather than doing most coding against that 10+ years old API that sucks anyway you look at it and which is there mostly for backwards compatibility reasons since VB4 days (more historical background at http://blogs.msdn.com/b/oscar_calvo/archive/2007/12/26/the-evil-envdte-namespace.aspx).

So, a cast on your adapters here and there against the crappy DTE&friends API doesn't seem like a big price to pay (hardly "casts everywhere", as evidenced by the very little code I had to modify) to keep the VSX development environment happy.

Developer
Apr 20, 2011 at 7:29 PM

Ok I'll tentatively agree with you :). Let me run our functional tests with your change to see if everything works.

Apr 20, 2011 at 7:33 PM

yay! :)

Developer
Apr 20, 2011 at 7:42 PM

Can you see if you can get rid of all the build warnings? When I run build.cmd I get 12 warnings now.

Apr 20, 2011 at 7:44 PM

btw, r u dfowler or david.fowler at MS?

Here's what I got from the VSX list, if you need more convincing that nobody should be embedding interop types:

 

Sent: Wednesday, April 20, 2011 3:36 PM
To: Daniel Cazzulino (Clarius Consulting); Visual Studio Extensibility Discussions
Subject: RE: Best practice around "Embed Interop Types" flag for VS core interop assemblies

The guidance is not to embed in Dev10. If you notice, all projects generated from VS Package wizard template, we add COM+ reference to these PIA and set embedding to false.

--

Regards,

Developer
Apr 20, 2011 at 7:46 PM

Why yes I am :). Thanks for checking.

Apr 20, 2011 at 7:55 PM

I wanted to FW but didn't know which one to :P

I'll check the warnings.

Developer
Apr 20, 2011 at 8:03 PM

Ok so I get 5 failing tests. 4 of them are the same issue (haven't looked into how to fix it as yet). The other 1 is an issue we kinda knew about (powershell not being able to convert com objects):

You can run them on your side by just spinning up a new instance of the exp hive and executing Run-Test from the console.

Apr 24, 2011 at 4:28 AM

Here's another very easy way to get the invalid cast exception (blocking another approach to the framework-aware msbuild imports via .ps1):

param($installPath, $toolsPath, $package, $project)
   Add-Type -AssemblyName NuGet.Core
   Add-Type -AssemblyName NuGet.VisualStudio
   $projectSystem = [NuGet.VisualStudio.VsProjectSystemFactory]::CreateProjectSystem($project)

 

Fails with:

Install-Package : Cannot convert argument "0", with value: "System.__ComObject", for "CreateProjectSystem" to type "EnvDTE.Project": "Cannot convert the "System.__ComObject" value of type "System.__ComObject#{866311e6-c887-4143-9833-645f5b93f6f1}" to type "EnvDTE.Project"."

 

;)

Developer
Apr 24, 2011 at 4:49 AM

I think we've seen that already I'm just waiting on you to fix the warnings :)

Developer
Apr 24, 2011 at 5:28 AM

I still see that exception when running the end to end test with your change:

Failed RemovingAmbiguousProjectAllowsSimpleNameToBeUsed Cannot convert argument "0", with value: "System.__ComObject", for "Remove" to type "EnvDTE.Project": "Cannot convert the "System.__ComObject" value of type "System.__ComObject#{866311e6-c887-4143-9833-645f5b93f6f1}" to type "EnvDTE.Project"."
May 11, 2011 at 3:58 PM

@dfowler: was this issue ever resolved? I was trying to run the following End To End test: RemovingAmbiguousProjectAllowsSimpleNameToBeUsed and I got this error:
Remove Failed: Cannot convert argument "0", with value: "System.__ComObject", for "Remove" to type "EnvDTE.Project": "Cannot convert the "System.__ComObject" value of type "System.__ComObject#{866311e6-c887-4143-9833-645f5b93f6f1}" to type "EnvDTE.Project"."

and have no clue as to what I need to do to fix it.

Developer
May 11, 2011 at 7:20 PM

Ignore that error for now. Even with these changes I still see the error on certain machines. If you see other types of errors let me know.

Jan 25, 2015 at 10:35 PM
Was this resolved?
I am working on a VSPackage project and I get the error:

"Embedded interop type 'EnvDTE.Project' is defined in both 'EnvDTE.dll' and 'NuGet.Tools.dll'.
Some operations on objects of this type are not supported while debugging. Consider casting this object to type 'dynamic' when debugging or building with the 'Embed Interop Types' property set to false.  "