Ver versión en español    
 
Home
10 Reasons to use MZ-Tools
MZ-Tools 6.0 for VS.NET
Editions
Features
Online Documentation
MZ-Tools SDK
Download
Purchase
Version History (RSS)  
FAQ & Support
MZ-Tools 3.0 for VB6 & VBA
Features
Online Documentation
Download (freeware)
Donations (Paypal)
Version History (RSS)  
FAQ & Support
User Reviews
Community Place
Contact  
For Add-In Developers
About
   
User Testimonials

I'm an avid supporter of MZ-Tools. It's a product I couldn't do without and your level of support is outstanding.

Jan Hyde (Visual Basic MVP)

You will soon wonder how you ever lived without it.

Andy Maggs

More user reviews
 
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: June 2009   Microsoft Visual Studio 2005
      Microsoft Visual Studio 2008
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 satellite DLL with a Win32 Visual C++ project for a COM 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

    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 managed satellite DLL with a VB.NET/C# project for a XML add-in (Visual Studio 2005 or higher)

The steps are the following:

  • Add a new VB.NET/C# Class Library project to the solution.
  • Remove the Class1 file.
  • Open the Resources.resx file:
    • For a VB.NET Class Library project, click the "Show All Files" button on the Solution Explorer toolbar, open the "My Project" folder and open the Resources.resx file.
    • For a C# Class Library project, double click the "Properties" folder, go to the "Resources" tab, and click the link "The project does not contain a default resources file. Click here to create one".
  • Click the "Add Resource", "New Image", "BMP Image..." button on the toolbar of the Resources.resx window.
  • Enter a numeric value such as 1 as the name of the resource.
  • 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 to 24 bit
  • 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.
  • To remove the "The resource name 'n' is not a valid identifier" warnings in the Error List window, select the Resources.resx file in the Solution Explorer window, and in the Properties window clear the "Custom Tool " and "Custom Tool Namespace" properties. Save all changes, close the windows and rebuild the solution.
  • In the AssemblyInfo file, set the AssemblyVersion attribute to the same value than the one of the add-in assembly. Notice that assembly versions (which is a .NET concept) should not be changed on each build, only the AssemblyFileVersion attribute (which is a Windows concept) should change.
  • In the AssemblyInfo file, set or add the AssemblyCulture attribute with the value "en-US".
  • If the add-in assembly is signed with a strong name, sign also the resource dll using the same .snk file.
  • In the properties window of the project:
    • Go to the Application tab and change the Assembly Name to <MyAddInName>.resources, that is, the name of the add-in assembly with the .resources suffix so that the assembly file will be named <MyAddInName>.resources.dll when built.
    • Go to the Build tab (C# projects) or "Compile" tab (VB.NET projects) and change the output path to a subfolder named "en-US" in the output folder of the add-in assembly.
  • Build the resource dll.
  • Once you have built the resource dll, 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).
  • If after running the add-in the custom bitmap doesn't appear in the button of the add-in, it means that the resource dll is not being located or that its assembly name, version, culture or public key token values don't match the ones of the add-in assembly. You can use the Assembly Binding Log Viewer tool of the .NET Framework SDK to diagnose such problems.

If you need to reset your commands so they are created again, see HOWTO: Reset a 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

  • 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 back to the 'Resources for Visual Studio .NET extensibility' section for more articles like this


   Top