Einar Egilsson

Easy way to have custom icons in Visual Studio AddIn

Posted: Last updated:

I've recently been developing a Visual Studio AddIn and I wanted to use custom icons for a command I had. Looking for a solution I found the offical MSDN article on the subject, that might possibly be the most misleading and useless article ever. Add the resource file in Visual Studio, then exclude from project, rename your images to numbers, edit with Notepad and then build satellite assemblies on the commandline? Really? That is a horrible way to do it and not at all necessary. I've found a very simple and easy way to add these icons without all that hassle.

There are a couple of other articles out there that approach the problem in a different way. Roy Osherove has an article where he shows how you can add icons without having satellite assemblies for them, but that has > 350 lines of code for loading the images yourself including P/Invokes and all sorts of stuff, and I didn't really need such a heavyweight solution. To be fair, his solution does give you the ability to use .ico files as well, and offers transparency, but transparency can be achieved in an easier way.

I also found another article that shows how you can get transparency by using a special color that, as far as I know, is not documented anywhere officially. It also shows you how you can build a satellite assembly from Visual Studio without resorting to Notepad and the command line tools, but this approach uses a special project for the satellite assembly, which is completely unneccessary.

So, finally, my approach, which is really a refinement of the last article I mentioned. If your add-in is meant for only VS2008 then you can get away with having no satellite assembly, VS2008 falls back to looking in your main assembly for the resources if it doesn't find a satellite assembly. If you want to support VS2005 you must have a satellite assembly for it to work.

So, assume we have a project named MyProject which will compile to an assembly called MyProject.dll. Here's what you do:

  1. Add a new "resources" item to the project and give it the name "MyProject.en.resx".
  2. Go the properties for the item and set the "Custom Tool" field to nothing. This will remove the auto-generated code for the .resx file
  3. Double click on the .resx file, this opens up the resource editor. There you can add an existing image (Add Resource->Add existing file). The image should be a 16x16 pixel bitmap image. It must be in True Color format. True Color is the same as a 24-bit bitmap.
  4. If you want transparency in your image then use the special color: Red:0 , Green:254, Blue:0 . Note that it really is 254, NOT 255.
  5. In the resource editor, give your image a name that is a number, e.g. 1. Note that you did not have to change the filename of your image file, just its name in the resource file.
  6. Now add your command in your add-in file like so: commands.AddNamedCommand2(_addInInstance, "MyProject", "MyProject", "Executes the command for MyProject", false, 1, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton); There you must send in false and then the number you gave the icon in your .resx file, e.g. 1.

Now when you compile your solution, a satellite assembly with the name MyProject.resources.dll will automatically be created and put in a "en" subfolder of your output folder. If you only want to support VS2008 and don't want satellite assemblies then you can name the .resx file just MyProject.resx instead, then no satellite assemblies will be created and the resources will be embedded in the main assembly.

And that's it. Add more resources in Visual Studio, have things compile automatically and don't touch command line tools, notepad, hundreds of lines of custom code or anything like that. I *think* it is enough to just have the "en" resources dll even if you use another locale, I'm pretty sure Visual Studio falls back to that if it doesn't find a satellite assembly in your current culture. At least I have my Windows set up for Danish, but my "en" satellite assembly works just fine for me. Although, there doesn't exist a Danish version of Visual Studio, maybe this works differently for localized Visual Studio, e.g. the German version. If someone has one of those and can test I'd love to know whether it falls back to "en" if nothing else is available. If it doesn't then just create a few more MyProject.de.resx, MyProject.es.resx etc. to get more satellite assemblies. But like I said before, VS2008 and later doesn't need this, so for that case just have the one MyProject.resx file.

I've made the small MyProject example and it can be downloaded here. Let me know if this works (or doesn't) for you. Enjoy!

If you read this far you should probably follow me on Twitter or check out my other blog posts. I no longer have comments on this blog, but you can send me an email if you have some comments about this page.