| 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