MZ-Tools articles series: HOWTO: Removing commands and UI elements during Visual Studio .NET add-in uninstallation (updated)

I have updated a quite old but useful article (Feb 2005) to document the new /ResetAddin command-line flag of Visual Studio 2005/2008 and how to do it correctly:

HOWTO: Removing commands and UI elements during Visual Studio .NET add-in uninstallation

It is important to note that the /ResetAddin command-line flag will remove permanent controls but not permanent commandbars (another reason to not use them). 

devenv.exe /SafeMode and add-ins in Visual Studio 2005 / 2008

Just a curious difference in behavior between Visual Studio 2005 and Visual Studio 2008 that the MSDN documentation doesn’t cover very well:

According to the MSDN documentation of VS 2005, “This switch prevents all third-party VSPackages from loading when Visual Studio starts, thus ensuring stable execution.” One would expect that if third-party VSPackages are not loaded, add-ins would be also excluded from loading, but they aren’t, they are loaded.

Visual Studio 2008 works as expected and the whole Add-in Manager is disabled.

Unknown error (error number 80131522) loading add-ins

I am writing an article about creating setups for Visual Studio add-ins and testing I have found that if the namespace/class specified in the <FullClassName> tag of the .AddIn XML file does not match the actual namespace and connect class name in the source code, you get an obscure <Unknown error> (error number 80131522) loading the add-in. Searching the web I found in the forums that I was not the first developer with this problem, so I have updated my article to reflect this:

HOWTO: Troubleshooting Visual Studio and Office add-ins

It would be great if Microsoft could provide more helpful message errors when things are not set up as expected…

MZ-Tools Articles Series: HOWTO: Get the text editor font and colors information in a Visual Studio add-in

Although I wrote long time ago an article about EnvDTE.DTE.Properties, it was not until this week that I needed to retrieve font and color information of the text editor of Visual Studio. Basically I am changing the code template editor of my MZ-Tools add-in from black and white to colorized text using a RichTextBox, resembling as much as possible the code editor of VS without using more complex 3rd party products (such as Activepro Syntaxt Editor, which seems excellent) or trying to host the Visual Studio code editor inside a Windows Form.

Here is a new article about this subject and some things that I have encountered.

HOWTO: Get the text editor font and colors information in a Visual Studio add-in

BTW, notice that VS 2005 has a bug (fixed in VS 2008) and the “Comment” foreground color is not returned correctly (although the VS code editor colorizes perfectly). You may want to use the XML Comment or CSS Comment foreground color in this case.

New book on Visual Studio extensibility

As you may have noticed, there aren’t many books on Visual Studio Extensibility, so any new book is great news. This is the case of a new book with the title “Professional Visual Studio Extensibility” by Keyvan Nayyeri:

It is already available from Wiley and Wrox (where you can read the TOC, index, and first chapter) and will be available from Amazon shortly. I haven’t read it yet (I am awaiting a complimentary copy in a few days or weeks) but I am excited because this book covers more than add-ins or macros, so you have chapters about VS SDK packages, DSL tools, Visual Studio Shell, extending the debugger or even MSBuild. While there is lot of information about those subjects in MSDN and blogs, I personally prefer a good book to learn new technologies.

How do I get a System.Type from a type name?

This is another question that appears from time to time in the forums, and it is one extremely complicated to have a 100% satisfaction with the result :-). I haven’t written a MZ-Tools Series article for this since I don’t have a comprehensive answer with a sample code, but I will elaborate a bit about this in this post.

The question is, suppose I have a string like “Car” that I know it’s a type. How can I get the System.Type that represents that type? Before that question there is a previous one: how did I get that string? There are several ways:

  • Using the code model (EnvDTE.Project.CodeModel or EnvDTE.ProjectItem.FileCodeModel), you have a CodeVariable, CodeParameter, etc. which has a CodeTypeRef property that returns the type of the code element.
  • Parsing a procedure code (by hand, since the code model doesn’t cover that), you get statements like “Dim objCar as Car” (VB.NET) or “Car mycar” (C#), so somehow you get the “Car” string and you guess that it is a type.

There are a couple of complications to note here:

  • Types have a short name, such as “Car”, and a fully qualified name, such as “Vehicles.Motorized.Car”. Since you can have “Imports” statements at file or project level in VB.NET and “using” statements at file level in C#, it is not required that the fully qualified name to appear in the variable or parameter declaration. Note: even if the declaration contains a dot (.) you can’t assure that it is a fully qualified name because it can be a partially-qualified name, such as if you import the “Vehicles” namespace at file level and you declare the variable as Dim objCar As Motorized.Car.
  • Types can reside in compiled assemblies references, or, alas, in the project’s source code or in a project (not compiled) reference. In the last two cases, you can’t have a System.Type, since maybe the project is not compiled yet (first time) or maybe the last compilation was days ago and it is not up-to-date. In these cases, for most accuracy you don’t really want a System.Type but an EnvDTE.CodeElement such as an EnvDTE.CodeClass, EnvDTE.CodeStruct, EnvDTE.CodeInterface, etc. So, your add-in has to deal with two kind of types: compiled types (represented by a System.Type) and source code types (represented by a CodeElement).

So, let’s try to solve them:

  • To get the fully qualified name of a type name, assumming that it comes from a EnvDTE.CodeTypeRef, you can try the CodeTypeRef.AsFullName property (in contrast to its CodeTypeRef.AsString property). I don’t know how reliable is this in each version of Visual Studio and for each language (VB.NET, C#) but my experience is that you can’t fully trust the code model. As a workaround, you should compose a list of fully qualified candidate type names combining the imported namespaces and then try to resolve which of them is the true one. This is what the compiler does after all when building the project, although it doesn’t expose that information to add-ins or packages (AFAIK).
  • Given the fully qualified name, or a list of candidates, you need to “resolve” them to a System.Type or EnvDTE.CodeElement. To do this, I would start with compiled references since is faster than using the code model. You would have to get the references of the project which are compiled assemblies (see HOWTO: Getting information specific to VB.NET and C# projects from an add-in or macro). For each compiled reference you get the name of the assembly and using Reflection you can use Assembly.Load or Assembly.LoadFrom to load it and then call Assembly.GetExportedTypes to get the public types and then iterate them until you find the one that matches the fully qualified type name. If you don’t find it, then chances are that it is a type declared in the source code of the project, or in one of the project (not compiled) references. In these cases you have to navigate the code model of each project (see HOWTO: Navigate the files of a solution from a Visual Studio .NET macro or add-in and HOWTO: Navigate the code elements of a file from a Visual Studio .NET macro or add-in). Needless to say, this can be slow.

All that said, you may have heard of the ITypeResolutionService service of Visual Studio, which sounds promising to avoid all that. I haven’t tried it personally because it was not clear for me how to get an instance of it (most documentation refers to component designers) but today I found two posts of MVP fellow Daniel Cazzulino that can be helpful:

Retrieving available types in current project and its references (without locking)


How to get a System.Type from an EnvDTE.CodeTypeRef or EnvDTE.CodeClass

So, he explains how to get the all the types declared in a project and references using the ITypeDiscoveryService, and how to get a System.Type from a type name using the ITypeResolutionService, retrieving both services from an EnvDTE.Project. These is great news, but notice the caveat that for types declared in source code, it will retrieve a System.Type from the last successful compilation (if any) and not an EnvDTE.CodeElement. Assuming that you don’t mind the issue of the out-of-date compilation, getting a System.Type can be enough for some scenarios, but not for others, such as when you want to go to the source code file of the type (think the Go To Definition command of Visual Studio), where you really want an EnvDTE.CodeElement (which contains the ProjectItem and location, etc.) and not a System.Type.

TechDays 2008

This week I attended the TechDays 2008 here at Madrid, a two-days event to launch Visual Studio 2008, Windows Server 2008 and SQL Server 2008 (this product actually is not released yet but…). I don’t know if it was that Microsoft Iberica (the subsidiary for Spain and Portugal) celebrated its 20 anniversary or that the new products deserved it, but this has been the greatest Microsoft event that I ever attended (except the Microsoft TechEd at Barcelona that I attend every some years). It was like a mini-TechEd, with lots of parallel sessions, hands-on labs, ask the expert, partners expo, etc. and even hot dogs ;-). Lots of known people (many speakers were fellow MVPs) and very good content in most sessions. Apart from the new exciting technologies such as WCF, WFF, WPF or SilverLight I was mostly interested in Team Foundation Server 2008, a great tool for collaboration and team work that hopefully I will install and use this year, and which furthermore provides extensibility, so who knows if I enter that area some day…