It’s about time: MZ2005003 article (HOWTO: Adding buttons, commandbars and toolbars) revisited and with C# code

A long overdue task I had was to revisit the most popular article of the MZ-Tools Articles Series of my web site and provide the samples in C# code:

HOWTO: Adding buttons, commandbars and toolbars to Visual Studio .NET from an add-in

It happened that many developers didn’t bother to read or try the samples because they were only in VB.NET, so I have added them in C# too. It has taken me quite a few hours because I have been enhancing the code with better sections, comments, constants for names and captions, etc. so hopefully it is now more clear how to:

  • Add a button to a Visual Studio built-in toolbar
  • Add a button to a Visual Studio built-in menu
  • Add a button to a Visual Studio built-in context menu
  • Create a new toolbar with a button
  • Create a new menu in the main menu
  • Create a new submenu under a menu

The new code layout will help to identify what does what, and what to remove if you are not interested, both with the temporary or permanent approaches.

My feeling about the commandbar model of Visual Studio (borrowed from Office) has increased after all these hours: commands, buttons and commandbars are incredibly tricky because of:

  • Two models: permanent or temporary user interface
  • The confusing /resetaddin flag that causes many programmers that they will get a ext_ConnectMode.ext_cm_UISetup phase each time that the add-in is loaded
  • The half-backed /resetaddin flag that only reset buttons, but not commandbars, so you get duplicated UI if you don’t take care.
  • The CommandBarControls, that can be CommandBarButton or CommandBarPopup
  • The confusing connectMode of the OnConnection method, and in general, the IDTExtensibility2 interface.
  • The difficulty distinguising Name/Caption when creating commandbars or toolbars.
  • The lack of helpful message error from Visual Studio when you make a mistake with a parameter of the call that adds a command, button, commandbar, etc. Only enhancing this area would save tons of hours and questions in forums.
  • Etc, etc.

The result is that after several years working with add-ins, I am unable to write code to add commandbars, popups, context menus, main menus, etc. by heart. I have always to go to read the code of the article.

The strange case of 8013150A loading a Visual Studio add-in

Visual Studio add-ins are not very friendly when trying to auto-update them (at least as of Visual Studio 2008), so when deploying an add-in for internal use within an organization, one creative idea is to put the assembly dll in a shared network folder and register the add-in from there in each computer without copying it to the hard disks. You can do this putting the XML .AddIn file in that same folder and adding that folder to the list of locations that VS uses when searching for add-ins (Tools, Options menu, Environment, Add-in/Macros security). During the day you won’t be able to update the add-in assembly because it will be in use by the developers, but chances are that you will be able to do it at night (with some automated mechanism).

There is still a problem, though. As of .NET Framework 3.5 (without SP1) and below, by default assemblies in shared network folders lack FullTrust permission required to run add-ins, because shared folders belong to the LocalIntranet_Zone, which has a LocalIntranet permission set, not a FullTrust permission set. This was an incovenience not only for add-ins, but also for general .NET applications, and since configuring the .NET runtime security policy is not trivial, I guess that Microsoft got tired of support calls and complaints from developers and IT staffs and in SP1 of .NET Framework 3.5 they changed things to allow .NET assemblies to run with FullTrust permission from shared network folders (you can revert back this change if you want the old behavior).

Note: .NET Framework 3.5, 3.0 and 2.0 share the same CLR, so it’s CLR 2.0 what matters for security and add-ins, not the .NET Framework. 

So, the question I was wondering is: can then a .NET 2.0 add-in run from a shared network location without further security configuration changes? I did the test, and I got this nice COM error: 8013150A (not very helpful as usual). If I changed the permissions to FullTrust in that shared network location, it worked, so I have enhanced my article about troubleshooting with a mention to this error:

HOWTO: Troubleshooting Visual Studio and Office add-ins

The only remaining thing to clarify is why the security policy change doesn’t work with add-ins. Well, it happens that this is by “design”, it doesn’t work with ClickOnce applications or applications that are designed to run on a host:

Running Intranet Applications in Full Trust

More on new project type Guids or flavors and how to get them

Some days ago I wrote about testing a Visual Studio add-in against new Visual Studio tools or extensions from Microsoft. I have been testing my MZ-Tools add-in and I have had to make it aware of those new project types, mainly to display correctly the project/file icons in some features. I wrote long time ago how to get the project type Guid from an add-in. I have updated that article with the C# version:

HOWTO: Get the project flavor (subtype) of a Visual Studio project from an add-in

and I have updated too the list of known project type Guids to include XNA Game, Silverlight and SharePoint projects:

INFO: List of known project type Guids

Finally, it can happen, as in my case, that I don’t want to use the services from the SDK to get the project type or flavor (I still support VS.NET 2002/2003), so I use another approach through extenders, as I explained in the article:

HOWTO: Guess the type of a Visual Studio project from an add-in or macro

I have updated it to provide the C# code and to document “creative ways” of getting the project type flavor when the extender is the same for several project flavors, such as “VST” for Visual Studio Tools for Office (Word, Excel, Outlook) or “Microsoft.Xna.GameStudio.CodeProject.ParentProjectExtender” for XNA game projects (Zune, XBox, Windows).

MZ-Tools Articles Series: BUG: Infinite recursion in add-in causes Visual Studio crash

This bug that I commented in a previous blog entry and that I reported to Micorosoft through Microsoft Connect is not going to be fixed in the next version VS 2010:

Add-in causing stack overflow causes “Microsoft Visual Studio has encountered a problem and needs to close”

So, there will be three versions of Visual Studio affected. I have written a MZ-Tools article to document it:

BUG: Infinite recursion in add-in causes Visual Studio crash

MZ-Tools Articles Series: INFO: Testing a Visual Studio add-in against new Visual Studio tools or extensions from Microsoft

When you create your Visual Studio extension, whether an add-in or package, likely you test it most of the time against project types provided by Visual Studio out of the box, such as VB.NET/C# projects, smartdevice projects, database projects, etc.

Long time ago I wrote an article warning that likely add-ins fail throwing exceptions when tested against 3rd party project types, because they tend to be “unmodeled projects” (meaning that they don’t support automation):

PRB: Add-ins fail with 3rd party project kinds in Visual Studio .NET

New project types can introduce new icons for project/project items, new text file types that are searchable, etc. so your add-in can be affected.

While you may argue that it is annoying and time-consuming to test an add-in/package against every single new project type that any 3rd party company feels the need to create, there are new project types from a company that you should test: the new project types from Microsoft itself. This is because they are extensions for Microsoft products and technologies and very likely they will be installed on tons of computers with Visual Studio. My latest article mentions some of the new extensions or tools for Visual Studio that you should test against:

INFO: Testing a Visual Studio add-in against new Visual Studio tools or extensions from Microsoft

Inspecting COM Objects With Reflection

Long time ago I wrote about HOWTO: Know the actual type behind a System.__ComObject type returned by an .Object property since chances are that you are going to find System._ComObject when using Visual Studio automation (because internally it’s all COM).

Last January 2009 Lucian Wischik, the Visual Basic Specification Lead, wrote an article in MSDN Magazine about Inspecting COM Objects With Reflection, which can be useful if you are unable to get the assembly DLL that contains the actual type behind System._ComObject to perform the cast and you need to use Reflection against the _COMObject to get its properties, call its methods, etc.

MZ-Tools Articles Series: HOWTO: Prevent dead CommandBarButtons when Visual Studio or an add-in crashes

This is another problem that was bugging me for quite some time: if an add-in uses a temporary user-interface rather than a permanent one when adding buttons to a built-in toolbar of Visual Studio, the add-in must remove the buttons when unloaded, typically keeping a reference to the CommandBarButton instance and calling the CommandBarButton.Delete method in the OnDisconnection method.

This approach has a problem that was affecting some customers of my MZ-Tools add-in: if Visual Studio or the add-in crashes, the add-in doesn’t have the chance of removing those buttons and they stay there forever, creating duplicates the next one that the add-in is loaded.

A better approach is to delete the command, rather than the button, when the add-in is unloaded (the command should be recreated rather than deleted to keep keyboard bindings). Deleting a command deletes all buttons, even “dead” ones. While this new approach doesn’t prevent duplicated buttons, they only stay there for a session. Using this new approach also solves the sporadic problem of COMException 0x800A01A8 that I already blogged about.

I have just written a new MZ-Tools Series article about this:

HOWTO: Prevent dead CommandBarButtons when Visual Studio or an add-in crashes

FWIW, MZ-Tools (February 1, 2009) uses this new approach, which solves both problems.

The strange case of ProjectItem.Open(EnvDTE.Constants.vsext_vk_Designer) trying to check-out a form file

Today I have solved a problem that was bugging me for months. I was aware of it but I hadn’t paid much attention to it (because I knew it was not a problem of my MZ-Tools add-in) until today, when I decided to take a closer look. The problem was the following: whenever I executed one of the features of MZ-Tools that reviews the designers of forms (such as the TabIndex review, the Access Keys review, etc.), of a solution under source control, the MDI form of the application became checked-out after the review and I had to undo the check-out by hand.

The line of code that caused the check-out was, of course:


and I knew that the problem was not MZ-Tools because opening the designer by hand in the IDE resulted also in a silent check-out. I noticed too that if I disconnected the solution from source control, in this case Visual Studio prompted to edit the read-only file with a dialog with buttons “Edit In-memory”, “Make Writeable” and “Cancel”. So, Visual Studio was really feeling the need of edit a designer file when opening it. But what was causing it?

I have spent the whole morning prunning the project, the form and the code, with several oops-too-much-pruning-that-no-longer-reproduces-the-problem and finally I have a minimal reproducible pattern:

1) Create a new Windows Forms project with Form1.

2) Create a user control UserControl1 with this code:

Private Sub UserControl1_VisibleChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.VisibleChanged

   Me.Size = New Size(100, 100)

End Sub

3) Build the project so the usercontrol appears on the toolbox.

4) Add the usercontrol to the form and set its Dock property to Fill.

5) Build the project again

6) Close all windows

7) Close the solution

8) Using the Windows Explorer, set the read-only attribute of the Form1*.* files

9) Open the solution again

10) Try to open the Form1.vb file in Design view. You get a prompt to edit the read-only file.

I know it’s stupid to set the size of the usercontrol in the VisibleChanged event of a usercontrol that will be docked, but that was what the code was doing in the end …

So, the solutions are:

1) Stop doing stupid things or…

2) Change the code to the following, so it only executes at run-time:

Private Sub UserControl1_VisibleChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.VisibleChanged

   If Not Me.Site.DesignMode Then

      Me.Size = New Size(100, 100)

   End If

End Sub

Is there anything that an add-in can do when it encounters this situation? If VS shows a prompt, there is nothing that an add-in can do. But if VS does a silent check-out, or silently changes the read-only flag of files you can do something: get the read-only value before calling ProjectItem.Open(EnvDTE.Constants.vsext_vk_Designer), get it afterwards, compare them and it they are not the same you can inform the user that there is something wrong in the file or in the controls used in the file, and that the same problem would happen if he opens the designer by hand, so it’s not really add-in’s fault.

Update (March 11, 2009):

If the file is not read-only, then VS edits it behind the scenes and you get an unexpected prompt to save the changes when closing the solution.

Also, I have found other pattern that reproduces the problem without wrong code:

1) Create a Windows Form project in VS 2008

2) Add a ListBox control to Form1 and set its Dock property to Fill

3) Save the changes, close the windows, and close VS

4) Using Windows Explorer, set the read-only attributes of the three Form1*.* files

5) Open VS and load the solution

6) Try to open the Form1.vb file in Design view. You get a prompt to edit the read-only file.

MZ-Tools Articles Series: BUG: ProjectItem.Open(EnvDTE.Constants.vsext_vk_Designer) restores Visual Studio 2005/2008 from minimized state

Suppose that you have an add-in, like my MZ-Tools add-in, that has a feature that needs to open (invisibly) each form of a project to (do some review, modify some properties of controls, etc.). In that case you need to call ProjectItem.Open(EnvDTE.Constants.vsext_vk_Designer) to get the EnvDTE.Window, which remains invisible (you would have to call Window.Visible = True), and then get the Window.Object property to cast it to IDesignerHost. If the operation is very long because the project has many forms, chances are that the user will want to minimize the Visual Studio IDE to do other things meantime. However, due to a bug introduced in VS 2005 (it didn’t happen in VS.NET 2003), the IDE is annoyingly restored from the minimized state each time that a form is processed.

Here you have the article that I have written with the details:

BUG: ProjectItem.Open(EnvDTE.Constants.vsext_vk_Designer) restores the IDE from minimized state

And the bug report sent to Microsoft if you want to vote to fix it or track its resolution (hopefully they fix it because it ruins the user experience):

Announcing the revised MZ-Tools Articles Series with C# samples and more

One of the initiatives that I want to accomplish this year 2009 is to revise and update all the more than 125 articles that I have written all these years since 2004 in the MZ-Tools Articles Series to include the following:

  • Samples in C#.  I have provided all the samples in the articles in VB.NET since it is my preferred development language and I assumed that every C# developer could understand the code. But I have noticed that:
    • To write add-ins in C# is somewhat more difficult due to the lack of optional parameters in C# (version 4.0 will support them, BTW) and other things.
    • Not every C# developer reading the articles bothers to try the VB.NET code to run the sample and then translates it to C#. Instead, they keep inventing code that it is not in the sample.

    So I have decided to make it easy for everybody and provide the samples of add-ins in VB.NET and C#. Macros will remain in VB.NET since C# is not supported as a macro language.

  • Revision of the Visual Studio version(s) that the articles apply to. Many articles were written when VS 2005 and VS 2008 were not released yet. So I am revising if each article still applies to new versions, such as if a bug has been fixed, etc.
  • “Copy” button to copy the code sample to the clipboard. Currently it works only with Internet Explorer. For FireFox it is more complicated and I haven’t found yet a satisfactory solution using the FireFox interfaces or the Flash approach. Security is a major concern in all browsers and operating systems such as Windows Vista and getting access to the clipboard of the client machine is increasingly more difficult. Nonetheless, FireFox is my preferred browser, so I will keep trying in the future.
  • Revision of the nomenclature prefixes used in the sample code. I am now trying to use the Microsoft guidelines, avoiding prefixed for types.
  • Revision of the “Related Articles” section and the end of each article. Some articles will reference now other articles that were not written yet when they were written.
  • Hopefully less spelling and grammar mistakes :-). I am from Spain so I don’t speak English natively, and the editor that I use lacks a spell checker.

I have created a spreadsheet with all the articles that need modification and this happens to be a huge task that will take me months keeping a pace of one article per workable day, but I think it will be worth. This also means that this year will be less new content, but I have still some topics to write about.

Here you have a sample of a revised article:

HOWTO: Add a popup command bar to the context menu of a code window of Visual Studio .NET