“Creative” solutions from developers to avoid the satellite dll in Visual Studio add-ins

It always fascinates me how “creative” we the developers can be solving problems that shouldn’t exist in the first place. For example, Microsoft has been too much creative in the last decade providing multiple tricky ways to solve the lack of transparency support in the original bitmap format. And now I am seeing in several places an approach that developers of add-ins are using to avoid the satellite DLLs to provide custom pictures. The first place where I saw it was in the very MSDN documentation about displaying a custom icon on the add-in button, in the Community Content section by Miguel Ferreira.

The basic idea is to give up the picture of the command, and to modify the picture of the CommandBarButton created from the command through its Picture and Mask properties. The implementation gets more complicated because those properties have the COM IPictureDisp type and therefore conversions from managed System.Drawing.Bitmap are required, and another creative technique is used to get the mask from a picture pixel by pixel rather than providing it directly (which would force to create two bitmaps per button).

I flagged that community content as “bug” because it doesn’t solve the fundamental problem, that is, providing a picture for the command, not just for its buttons. The picture of a command is something totally visible to the user when she clicks the “Tools”, “Customize” menu, “Commands” tab, “Add-Ins” section. While it may seem not very important a lacking command picture there, it happens that with that window open VS enters in a special mode that allows the user to drag the command on a toolbar to create a button, and the button would get the picture of the command.

I saw this approach too yesterday in this post of Roy Osherove.

Fortunately these hacks won’t be necessary in VS 2010, which will get rid of satellite DLLs for add-ins “officially”.

Issues with the grayscale image generated by Visual Studio for disabled commandbar buttons

I am now investigating why the grayscale image that Visual Studio 2005 / 2008 generates for a disabled button is so horrible/blurry for pictures of add-in commands and so crisp and precise for pictures of VS commands. VS 2005 introduced True Color bitmaps (VS.NET 2003 used 16-color bitmaps) so it should be able to generate good-looking grayscale images as it does with its own pictures (if I am correct that the disabled image is autogenerated and not provided separately through some way not available to add-ins). There are two scenarios where disabled buttons look bad:

  • CommandBarButtons created from a command (via Command.AddControl). In this case the image of the button is actually the image of the command which in turn is supplied in a satellite dll in True Color (24 bit) bitmap format, so there is no much room to play…
  • CommandBarButtons created on a CommandBar created by the add-in to be used as context menu somewhere, for example in the context menu of a list (New, Remove, etc.). The add-in creates a VS commandbar rather than a .NET context menu to provide the same look and feel. In this scenario, there is no command, the CommandBarButton is created via CommandBar.Controls.Add. When you cast the returned CommandBarControl to CommandBarButton you can use the Picture and Mask properties (COM IPictureDisp type) to set the image and the transparency mask, so there is much more room to play with the bitmap format, the color depth (32-bit, 24-bit, 8-bit), and how you get a COM IPictureDisp from a managed System.Drawing.Bitmap.

So far I have been unable to solve this, I will post again if I find a resolution for this issue. If someone know the solution, let me know.

Button custom picture transparency issues in Office extensibility too

I have found today three links on the web about issues with transparency in custom pictures of buttons that Office add-ins have suffered too:

Alpha channels, masks, color keys, oh my! (By Eric Faller about the Office Ribbon)
http://blogs.msdn.com/jensenh/archive/2006/11/27/ribbonx-image-faq.aspx

How To Create a Transparent Picture For Office CommandBar Buttons (MSDN KB Article)
http://support.microsoft.com/kb/288771

How To Set the Mask and Picture Properties for Office XP CommandBars (MSDN KB Article)
http://support.microsoft.com/kb/286460

Given that Visual Studio borrowed its commandbars from Office, it’s no wonder it has suffered the same problems.

More on devenv.exe /resetaddin not removing permanent commandbars

I think I forgot to blog about the resolution of this bug:

devenv.exe /resetaddin doesn’t fully reset the add-in
http://www.visualstudioextensibility.com/2009/06/23/devenv-exe-resetaddin-doesn-t-fully-reset-the-add-in

whose Microsoft Connect bug report is:

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=469322

The problem is, you see, that devenv.exe /resetaddin doesn’t remove permanent commandbars, only commands and buttons on commandbars. That means that if you are using permanent commandbars and not temporary ones, at the very least your uninstaller needs to take care of removing permanent commandbars explicitly because devenv.exe /resetaddin won’t do it. This can be done creating an instance of EnvDTE.DTE, locating the commandbar and calling EnvDTE.DTE.Commands.RemoveCommandBar (see HOWTO: Removing commands and UI elements during Visual Studio .NET add-in uninstallation). And not only the uninstaller: when debugging you may need to remove the commandbar too because VS 2005 and higher fire a new UISetup phase each time that you debug, so you get duplicated commandbars.

The temporary vs permanent approaches for commandbars is a nightmare for two reasons:

  • First, their own existence. A single approach would be much better. And the temporary one would be preferable. The reason for the permanent one is that for add-ins with a large number of commandbars and buttons, it takes less time to persist the UI on disk and retrieve it from there when launching VS than recreating the UI. I think that there aren’t many add-ins with lots of commandbars and buttons (certainly my MZ-Tools add-in is one with such large number of buttons, but I keep using the temporary approach). But if performance is a problem, then it is better to fix that rather than inventing a new approach. Some ideas for Microsoft to increase the performance of add-ins using the temporary approach are:

    • Provide a EnvDTE.Commands.Exist(commandName) method to test if a command exists or not (to create it only if it doesn’t exist). Currently you have to call the Item method which causes an (expensive) exception if the command doesn’t exist.
    • Provide a EnvDTE.AddInCommands collection that returns only the commands of add-ins, not the hundreds of commands of Visual Studio.
    • Make EnvDTE.Command.AddControl to behave as follows: if you are adding a button to a menu, set the CommandBarButton.Style to msoButtonIconAndCaption (VS already does this), but if you are adding it to a toolbar, set the CommandBarButton.Style to msoButtonIcon since it is more likely that style (without caption) on a toolbar. Currently VS defaults to msoButtonIconAndCaption also in this case, which means that after getting the CommandBarControl, you have to cast it to CommandBarButton and then change the Style property, which means that the button needs to be redrawn (a performance hit). I already reported this two years ago to no avail: Wrong default vsCommandStyle for CommandBarButtons created from add-ins. Even more, Visual Studio doesn’t work as supposed to do: Problems with ContextUIGUIDs and vsCommandDisabledFlagsValue in EnvDTE.Commands.AddNamedCommand (a bug yet to be acknowledged and fixed).
    • Simplify the way of getting transparent pictures for commands. The transparent color has been RGB=0,254,0 for long time which means that a color remapping must be performed. Hopefully this has been addressed in VS 2010 with support for 32-bit bitmaps with transparency in the alpha channel.
  • Second, the APIs are not consistent, which creates a lot of confusion. If both approaches need to exist, at least they would have to use the same methods with just one boolean parameter indicating if a commandbar is permanent or temporary. Currently you have:

    • CommandBars.Add to add temporary commandbars
    • CommandBar.Delete to remove temporary commandbars
    • Commands.AddCommandBar to add permanent commandbars (even if the CommandBars.Add method above has a Temporary parameter!)
    • Commands.RemoveCommandBar to remove permanent commandbars

Anyone can see that that mix of methods to add commandbars is bound to cause problems (why is there a AddCommandBar method in the Commands collection?) and certainly it is: the bug of devenv.exe /resetaddin can’t be fixed because the Commands.AddCommandBar method lacks a fundamental piece of information: the AddIn instance that is adding the commandbar. Without that information the IDE doesn’t know which add-in is the owner of a permanent commandbar and therefore can’t remove it.

More (good news) on Visual Studio 2010 getting rid of satellite DLLs for add-ins

In my last post Visual Studio 2010 getting rid of satellite DLLs for add-ins I mentioned that VS 2010 will provide two approaches to avoid satellite DLLs for command pictures of add-ins:

The first one was clear: command pictures will be able to be embedded in the own DLL of the add-in.

The second one was not so clear:

“Commands.AddNamedCommand2 will now support an IPicture”.

After that post I exchanged e-mails with Suzanne Hansen (Program Manager of Visual Studio Platform Shell Team) and Jeff Robison (the developer implementing the changes). While I thought that a new EnvDTE100.Commands3.AddNamedCommand3 would be added supporting managed System.Drawing.Bitmap or System.Drawing.Icon types, they explained me that the Bitmap parameter of the current EnvDTE80.Commands2.AddNamedCommand2 method is actually a Variant/Object, not an integer (as it happens with the old EnvDTE.Commands.AddNamedCommand method) and therefore it allows you to pass other types apart from an integer (denoting a numeric bitmap id). Jeff took advantage of this to accept an IPicture type without introducing a new AddNamedCommand method with a different signature.

The bad news was that, alas, IPicture is a native COM type, not a managed type, so developers of managed add-ins would have to use hacks such as OleCreatePictureIndirect or System.Windows.Forms.AxHost.GetIPictureDispFromPicture to convert a managed System.Drawing.Bitmap to a native COM IPicture or IPictureDisp. I was familiar with those techniques (see my article HOWTO: Creating custom pictures for Visual Studio .NET add-ins commands, buttons and toolwindows) and they were ugly to me, and prone to problems with transparency as happened in the past.

So, I suggested to make EnvDTE80.Commands2.AddNamedCommand2 to accept an IntPtr type that would denote the handle of a managed bitmap (System.Drawing.Bitmap.GetHBitmap). The EnvDTE.Window.SetTabPicture already accepts that happily to set the picture of a toolwindow.

They devoted some days to think about all that and a couple of days ago Suzanne informed me that Jeff was able to make EnvDTE80.Commands2.AddNamedCommand2 accept managed System.Drawing.Bitmap or System.Drawing.Icon apart from the native IPicture type added previously. This couldn’t be greater news. Not only you will be able to get rid of embedded bitmaps, so can also use icons if you are not comfortable with 32-bit bitmaps with alpha channel for transparency.

FWIW if you are developing a package and not an add-in:

“Jeff has also made a similar change for package authors – a new API, AddNamedCommand3, will be available that will also accept Bitmaps, Icons and IPictures.”

While these changes won’t be available in the next VS 2010 Beta 2, they will be in subsequent builds. It is also great that they did these changes so late in the VS 2010 development cycle. Usually when Beta 2 is reached it is “feature completed” and no changes such as those are allowed, just bug and performance fixes.

I am looking forward to test these new changes. At last Visual Studio will allow you to decide:

  • The way to provide custom pictures for add-ins:
    • Embedded bitmaps in satellite Dll
    • Embedded bitmaps in add-in Dll
    • Directly in the EnvDTE80.Commands2.AddNamedCommand2 method
  • The type of image to use:
    • 32-bit System.Drawing.Bitmap with alpha channel for transparency
    • System.Drawing.Icon (built-in transparency)

That plethora of choices together with the absence of COM stuff is what makes a good EnvDTE API for add-in developers.

Jeff and Suzanne, very good job!!

Microsoft fixing bug “Standard user unable to load/unload COM-based add-ins registered for all users with the VS Add-in Manager on Windows Vista”

Two years after I reported it, it seems that MS finally understood that this was a bug and I have been notified today that it is no longer closed as “By design” but as “Fixed”:

Standard user unable to load/unload COM-based add-ins registered for all users with the VS 2008 Add-in Manager on Windows Vista
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=365846

This bug has plagued all of us developing add-ins with COM-registration (rather than .AddIn XML registration) for all users (not for current user) for backwards compatibility with VS.NET 2002 and/or 2003. Too bad that the fix comes so late that I doubt there will be a fix for VS 2008, only for VS 2010…but anyway, it will make VS 2010 a better product.