Logo
HOWTO: Creating custom pictures for Visual Studio .NET add-ins commands, buttons and toolwindows.

Author: Carlos J. Quintero (Microsoft MVP) Applies to: Microsoft Visual Studio .NET 2002
Date: August 2005   Microsoft Visual Studio .NET 2003
Updated: March 2013   Microsoft Visual Studio 2005
      Microsoft Visual Studio 2008
      Microsoft Visual Studio 2010
      Microsoft Visual Studio 2012
Introduction

This article describes how to create custom pictures for Visual Studio .NET add-ins commands, buttons and toolwindows.

More Information

There are at least three cases in which you will need to create custom, transparent, pictures for your Visual Studio .NET add-in features. This article explains how to do it in each case:

1) Custom pictures for add-in commands

When you call the Commands.AddNamedCommand function to create a command, if you pass the False value in the MSOButton parameter (the 5th), then the command will use a custom picture instead of a picture taken from Microsoft Office. The custom picture is specified through the Bitmap parameter (the 6th) which is an integer, and it indicates the resource ID of the bitmap in a satellite DLL. The satellite DLL can be of two kinds, depending on the type of the add-in (COM add-in, managed XML-based add-in)

  • Visual Studio .NET 2002/2003 can use only COM add-ins whose satellite DLLs must be native, that is, created with a Win32 Visual C++ project.
  • Visual Studio 2005 or higher can use:
    • COM add-ins with native satellite DLLs (for backwards compatibility) created with a Win32 Visual C++ project.
    • XML add-ins with managed (.NET) satellite DLLs created with VB.NET or C# projects.

Note: a COM add-in can't use managed (.NET) satellite DLLs and a XML add-in can't use native (Win32 Visual C++) satellite DLLs.

1.1) Creating a command with a custom picture using a native Win32 (Visual C++) satellite DLL for a COM-based Visual Studio add-in

The steps are the following:

  • Add a new project to the solution selecting Visual C++ projects, Win32 project and give it a name, such as <MyAddinName>UI.vcproj (UI stands for user interface).
  • In the wizard that is shown, select Application Settings, select the DLL radiobutton and click the Finish button. The new project is added to the solution.
  • Right-click the Resources folder node of this new project and select "Add", "Add Resource…". A file named "<MyAddinName>.rc" file is added to the node and an "Add Resource" dialog appears. Select Bitmap from the list and click the "New" button.
  • In the Properties window, change the dimensions of the bitmap setting the Height and Width properties to 16.
  • In the Properties window, change the Colors property of the bitmap to the following value:
    • Visual Studio .NET 2002/2003: 4 bit (that is, 16 colors)
    • Visual Studio 2005/2008: 24 bit (that is, True Color)
  • Doble click the .rc file in the Solution Explorer (under the "Resource Files" folder) to open the Resource Editor window
  • Select the bitmap (under the "Bitmap" folder).
  • In the Properties window, change the ID property of the bitmap to the numeric value 1 (for example).
  • In the Properties window, change the Language property of the bitmap to the value "Neutral"
  • Draw or paste an image for your bitmap.
  • To use transparency you need to use a special color:
    • Select a color that you don't use in the Colors window.
    • Click the "Image", "Adjust Colors…" menu.
    • Enter the values Red=0, Green=254 (not 255!) and Blue=0 (almost pure green). You can use now this color to fill the transparent areas.
  • Once you have finished your bitmap, you need to change the call to the Commands.AddNamedCommand function: pass the False value in the MSOButton parameter (the 5th) and pass the ID of the bitmap (1, in our example) in the Bitmap parameter (the 6th).
  • Build the Dll and put it in a subfolder of your add-in folder naming the subfolder with the locale of Visual Studio. For the English version, the locale is 1033.
  • At this point you only need to inform Visual Studio .NET that your COM add-in uses a satellite DLL. In the registry entry where the add-in is registered for Visual Studio:

    HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\<version>\Addins\<MyAddinName>.Connect

    or

    HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\<m.n>\Addins\<MyAddinName>.Connect

    where <version> is:

    • 7.0 for Visual Studio .NET 2002
    • 7.1 for Visual Studio .NET 2003
    • 8.0 for Visual Studio 2005
    • 9.0 for Visual Studio 2008
    • 10.0 for Visual Studio 2010
    • 11.0 for Visual Studio 2012

    add two alphanumeric values:

"SatelliteDLLName": the name of your satellite dll, such as <MyAddinName>UI.dll
"SatelliteDLLPath": the path your satellite dll, excluding the locale (so it is really the path to the add-in, not to the satellite Dll).

After all this, your commands will be created with a custom, transparent picture.

If you need to reset your commands so they are created again, see HOWTO: Reset a Visual Studio add-in.


1.2) Creating a command with a custom picture using a managed (VB.NET / C#) satellite DLL for a XML-based Visual Studio add-in (Visual Studio 2005 or higher)

See the article HOWTO: Create a command with a custom picture using a managed satellite DLL for a XML-based Visual Studio add-in.

1.3) Creating a command with a custom picture without using a managed (VB.NET / C#) satellite DLL for a XML-based Visual Studio add-in (Visual Studio 2008 or higher)

See the article HOWTO: Create a command with a custom picture without using a managed satellite DLL for a XML-based Visual Studio add-in.

2) Custom pictures for add-in buttons without a command

In the previous case we have seen how to create a command with a custom picture. CommandBarButtons created from this command (using the Command.AddControl method) will show that custom picture too, but sometimes you may need to create buttons that don't have a command behind, using the CommandBar.Controls.Add method instead. In this case, to set a custom, transparent, picture for the CommandBarControl created, you need to cast it to CommandBarButton and then set its Picture and Mask properties (in this order):

  • The Picture property is used to specify an Stdole.IPictureDisp object (an unmanaged COM picture) with your bitmap.
  • The Mask property is used to specify an Stdole.IPictureDisp object with a 16-color bitmap (not a 2-color bitmap) which uses the white color to set the transparent areas of the picture, and the black color to set the non-transparent areas.

You can get an Stdole.IPictureDisp object from a managed System.Drawing.Image object using this class:

Public Class ImageToPictureDispConverter
   Inherits System.Windows.Forms.AxHost
   
   Public Sub New()
      MyBase.New("{63109182-966B-4e3c-A8B2-8BC4A88D221C}")
   End Sub
   
   Public Function GetIPictureDispFromImage(ByVal objImage As System.Drawing.Image) _
      As stdole.IPictureDisp
   
      Dim objPicture As stdole.IPictureDisp
   
      objPicture = CType(MyBase.GetIPictureDispFromPicture(objImage), _
         stdole.IPictureDisp)
 
      Return objPicture
    
   End Function
 
End Class 

You use this class as follows:

Dim objImageToPictureDispConverter As ImageToPictureDispConverter
Dim objImage As System.Drawing.Image
Dim objIPictureDisp As stdole.IPictureDisp
 
objImage = (get the managed image from somewhere)
objImageToPictureDispConverter = New ImageToPictureDispConverter()
objIPictureDisp=objImageToPictureDispConverter.GetIPictureDispFromImage(objImage)
objImageToPictureDispConverter.Dispose()

Other ways of creating an Stdole.IPictureDisp instead of using a managed image is using a file on disk or a bitmap resource from a satellite DLL. In the former case you would use this function exported by oleaut32.dll:

<DllImport("oleaut32.dll", =CharSet.Unicode, =True, ="OleLoadPictureFile")> _
Public Shared Sub OleLoadPictureFile(ByVal varFileName As Object,_
  <MarshalAs(UnmanagedType.IDispatch)> ByRef lpIPictureDisp As Object)
End Sub 

As you can see, the function receives a file name as first parameter, and it returns an IPictureDisp in the second parameter.

In the latter case you can get a bitmap handle from a resource DLL handle using this function:

<DllImport("user32.dll", ="LoadBitmapA")> _
Public Shared Function LoadBitmap(ByVal hDLLInstance As IntPtr, _
   ByVal iBitmapIndex As Integer) As Integer
End Function 

and then you would use the OleCreatePictureIndirect function to get an IPictureDisp object from the bitmap handle:

Public Structure PICTDESC
   Friend SizeOfStruct As Integer
   Friend PicType As Integer
   Friend Hbitmap As IntPtr
   Friend Hpal As IntPtr
   Friend Padding As Integer
   Friend Sub New(ByVal hBmp As IntPtr)
      Me.SizeOfStruct = Marshal.SizeOf(Me.GetType)
      Me.PicType = 1
      Me.Hbitmap = hBmp
      Me.Hpal = IntPtr.Zero
      Me.Padding = 0
   End Sub
End Structure
 
<DllImport("olepro32.dll", ="OleCreatePictureIndirect")> _
Public Shared Function OleCreatePictureIndirect(ByRef pPictDesc As PICTDESC, _
   ByRef riid As Guid, ByVal fOwn As Integer, _
   <MarshalAs(UnmanagedType.IDispatch)> ByRef ppvObj As Object) As Integer
End Function

That function is used as follows:

Public Function GetIPictureDispFromBitmapHandle(ByVal hBitmapHandle As IntPtr) _
   As stdole.IPictureDisp
 
   Dim objPicture As Object
   Dim objGuid As New Guid("00020400-0000-0000-C000-000000000046")
   Dim iResult As Integer
   Dim tPICTDESC As New PICTDESC(hBitmapHandle)
 
   iResult = OleCreatePictureIndirect(tPICTDESC, objGuid, 1, objPicture)
 
   Return CType(objPicture, stdole.IPictureDisp)
 
End Function 

3) Custom pictures for toolwindows

When you create a toolwindow using the Windows.CreateToolWindow method and the window is linked (docked) together with other toolwindows, its tab shows a picture. If you have not specified a picture, by default a Visual Studio picture logo is shown. You can specify a custom picture using the Window.SetTabPicture method, which must be called before setting the Visible property of the toolwindow to true.

3.1) Custom toolwindow picture for Visual Studio .NET 2002/2003

  • The object passed to the Window.SetTabPicture method must be of the type StdOle.IPictureDisp, which you can get with any method explained above.
  • The bitmap must be 4-bit (16 colors)
  • The transparent color must be RGB=0,254,0 (almost pure green) as explained before in this article.

3.2) Custom toolwindow picture for Visual Studio 2005

  • The object passed to the Window.SetTabPicture method can be of the type:
    • StdOle.IPictureDisp, which you can get with any method explained above.
    • The IntPtr handle of a System.Drawing.Bitmap (.NET), that is, calling EnvDTE.Window.SetTabPicture(Bitmap.GetHbitmap())
  • The bitmap can be either:
    • 32-bit bitmap with transparency in the alpha channel (recommended).
    • 24-bit bitmap with transparent color RGB=255,0,255 (magenta)

3.2) Custom toolwindow picture for Visual Studio 2008 or higher

  • The object passed to the Window.SetTabPicture method can be of the type:
    • StdOle.IPictureDisp, which you can get with any method explained above.
    • The 32-bit handle of a System.Drawing.Bitmap (.NET), that is, calling EnvDTE.Window.SetTabPicture(Bitmap.GetHbitmap().ToInt32())
  • The bitmap can be either:
    • 32-bit bitmap with transparency in the alpha channel (recommended).
    • If the color depth of the screen is:
      • 32-bit: a 24-bit bitmap made transparent calling System.Bitmap.MakeTransparent(color used for background)
      • 16-bit: a 24-bit bitmap with one of the following colors as transparent color:
        • RGB=255,0,255 (magenta)
        • RGB=0,254,0 (almost pure green)


Go to the 'Visual Studio Extensibility (VSX)' web site for more articles like this (Articles section)


Top