| Author: |
Carlos J. Quintero (Microsoft MVP) |
Applies to: |
Microsoft Visual Studio 2012 |
| Date: |
October 2012 |
|
|
| |
|
|
|
Introduction
When using the Dark theme, Visual Studio 2012 automatically inverts the colors
of bitmaps of commands on toolbars, commandbars, etc. However, an add-in may
require to invert the colors of some bitmap on some other user interface
element.
More information
The following sample shows an add-in that inverts the bitmap shown on a form,
using the
ThemeDIBits method of the Microsoft.VisualStudio.Shell.Interop.IVsUIShell5
interface. To get that interface from an add-in, see the article HOWTO: Get the Microsoft.VisualStudio.Shell.Interop.IVsUIShell5 interface to theme a Visual Studio 2012 add-in.
The sample uses the LockBits method of the Bitmap class, as explained in this
sample from the
MSDN documentation.
To show the sample:
- Select the Dark theme in Visual Studio 2012.
- Create a 24-bit bitmap using the value RGB=0,254,0 as transparent color. The
sample uses this color, but you can change it to other color.
- Create an add-in for Visual Studio 2012 with a form Form1 with two PictureBox
controls on it (PictureBox1 and PictureBox2).
- Add references to the Microsoft.VisualStudio.OLE.Interop.dll,
Microsoft.VisualStudio.Shell.Interop.dll and
Microsoft.VisualStudio.Shell.Interop.11.0 assemblies as explained in the article HOWTO: Get the Microsoft.VisualStudio.Shell.Interop.IVsUIShell5 interface to theme a Visual Studio 2012 add-in.
- Set the image of the PictureBox1 control to the bitmap created before.
- Use this code in the Connect class, that shows the form modally with the
inverted bitmap in the PictureBox2 control:
| Language: VB.NET | Copy Code (IE only) |
Imports System
Imports Microsoft.VisualStudio.CommandBars
Imports Extensibility
Imports EnvDTE
Imports EnvDTE80
Imports System.Runtime.InteropServices
Imports System.Drawing
Public Class Connect
Implements IDTExtensibility2
Private _applicationObject As DTE2
Private _addInInstance As AddIn
Public Sub OnConnection(ByVal application As Object, ByVal connectMode As ext_ConnectMode, ByVal addInInst As Object, _
ByRef custom As Array) Implements IDTExtensibility2.OnConnection
_applicationObject = CType(application, DTE2)
_addInInstance = CType(addInInst, AddIn)
Select Case connectMode
Case ext_ConnectMode.ext_cm_AfterStartup
InitializeAddIn()
Case ext_ConnectMode.ext_cm_Startup
' OnStartupComplete will be called
End Select
End Sub
Public Sub OnStartupComplete(ByRef custom As Array) Implements IDTExtensibility2.OnStartupComplete
InitializeAddIn()
End Sub
Private Function GetIVsUIShell5() As Microsoft.VisualStudio.Shell.Interop.IVsUIShell5
Dim sp As Microsoft.VisualStudio.OLE.Interop.IServiceProvider
Dim SVsUIShellType As Type
Dim hr As Integer
Dim serviceIntPtr As IntPtr
Dim shell5 As Microsoft.VisualStudio.Shell.Interop.IVsUIShell5 = Nothing
Dim serviceObject As Object
sp = DirectCast(_applicationObject, Microsoft.VisualStudio.OLE.Interop.IServiceProvider)
SVsUIShellType = GetType(Microsoft.VisualStudio.Shell.Interop.SVsUIShell)
hr = sp.QueryService(SVsUIShellType.GUID, SVsUIShellType.GUID, serviceIntPtr)
If hr <> 0 Then
System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(hr)
ElseIf Not serviceIntPtr.Equals(IntPtr.Zero) Then
serviceObject = System.Runtime.InteropServices.Marshal.GetObjectForIUnknown(serviceIntPtr)
shell5 = CType(serviceObject, Microsoft.VisualStudio.Shell.Interop.IVsUIShell5)
System.Runtime.InteropServices.Marshal.Release(serviceIntPtr)
End If
Return shell5
End Function
Private Function GetInvertedBitmap(ByVal shell5 As Microsoft.VisualStudio.Shell.Interop.IVsUIShell5, _
ByVal inputBitmap As Bitmap, ByVal transparentColor As Color, ByVal backgroundColor As UInteger) As Bitmap
Dim outputBitmap As Bitmap = Nothing
Dim outputBytes() As Byte
Dim rect As Rectangle
Dim bitmapData As Imaging.BitmapData
Dim sourcePointer As IntPtr
Dim length As Integer
Try
outputBitmap = New Bitmap(inputBitmap)
outputBitmap.MakeTransparent(transparentColor)
rect = New Rectangle(0, 0, outputBitmap.Width, outputBitmap.Height)
bitmapData = outputBitmap.LockBits(rect, Imaging.ImageLockMode.ReadWrite, outputBitmap.PixelFormat)
sourcePointer = bitmapData.Scan0
length = (Math.Abs(bitmapData.Stride) * outputBitmap.Height)
outputBytes = New Byte(length - 1) {}
Marshal.Copy(sourcePointer, outputBytes, 0, length)
shell5.ThemeDIBits(CType(outputBytes.Length, UInt32), outputBytes, CType(outputBitmap.Width, UInt32), _
CType(outputBitmap.Height, UInt32), True, backgroundColor)
Marshal.Copy(outputBytes, 0, sourcePointer, length)
outputBitmap.UnlockBits(bitmapData)
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
Return outputBitmap
End Function
Private Sub InitializeAddIn()
Const COLOR_NAME As String = "ToolWindowBackground"
Const GUID_COLOR_TABLE_ENVIRONMENT_CATEGORY As String = "624ed9c3-bdfd-41fa-96c3-7c824ea32e3d"
Dim backgroundColor As UInteger
Dim frm1 As Form1
Dim inputBitmap As Bitmap
Dim outputBitmap As Bitmap
Dim almostGreenColor As Color
Dim shell5 As Microsoft.VisualStudio.Shell.Interop.IVsUIShell5
Try
shell5 = GetIVsUIShell5()
' Get the background color of toolwindows
backgroundColor = shell5.GetThemedColor(New System.Guid(GUID_COLOR_TABLE_ENVIRONMENT_CATEGORY), COLOR_NAME, 0)
frm1 = New Form1()
' Apply the background color to the form
frm1.BackColor = ColorTranslator.FromWin32(CType(backgroundColor And &HFFFFFF, Integer))
' Get the unthemed input bitmap
inputBitmap = New Bitmap(frm1.PictureBox1.Image)
' Assume that the transparent color is almost green. It can be any color
almostGreenColor = Color.FromArgb(0, 254, 0)
' Get the themed output bitmap
outputBitmap = GetInvertedBitmap(shell5, inputBitmap, almostGreenColor, backgroundColor)
inputBitmap.Dispose()
frm1.PictureBox2.Image = outputBitmap
frm1.ShowDialog()
frm1.Dispose()
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
End Sub
Public Sub OnDisconnection(ByVal disconnectMode As ext_DisconnectMode, ByRef custom As Array) _
Implements IDTExtensibility2.OnDisconnection
End Sub
Public Sub OnAddInsUpdate(ByRef custom As Array) Implements IDTExtensibility2.OnAddInsUpdate
End Sub
Public Sub OnBeginShutdown(ByRef custom As Array) Implements IDTExtensibility2.OnBeginShutdown
End Sub
End Class
| Language: C# | Copy Code (IE only) |
using System;
using Extensibility;
using EnvDTE;
using EnvDTE80;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Windows.Forms;
namespace MyAddIn
{
public class Connect : IDTExtensibility2
{
private DTE2 _applicationObject;
private AddIn _addInInstance;
public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
_applicationObject = (DTE2)application;
_addInInstance = (AddIn)addInInst;
switch (connectMode)
{
case ext_ConnectMode.ext_cm_AfterStartup:
InitializeAddIn();
break;
case ext_ConnectMode.ext_cm_Startup:
// OnStartupComplete will be called
break;
}
}
public void OnStartupComplete(ref Array custom)
{
InitializeAddIn();
}
private Microsoft.VisualStudio.Shell.Interop.IVsUIShell5 GetIVsUIShell5()
{
Microsoft.VisualStudio.OLE.Interop.IServiceProvider sp = null;
Type SVsUIShellType = null;
int hr = 0;
IntPtr serviceIntPtr;
Microsoft.VisualStudio.Shell.Interop.IVsUIShell5 shell5 = null;
object serviceObject = null;
sp = (Microsoft.VisualStudio.OLE.Interop.IServiceProvider)_applicationObject;
SVsUIShellType = typeof(Microsoft.VisualStudio.Shell.Interop.SVsUIShell);
hr = sp.QueryService(SVsUIShellType.GUID, SVsUIShellType.GUID, out serviceIntPtr);
if (hr != 0)
{
System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(hr);
}
else if (!serviceIntPtr.Equals(IntPtr.Zero))
{
serviceObject = System.Runtime.InteropServices.Marshal.GetObjectForIUnknown(serviceIntPtr);
shell5 = (Microsoft.VisualStudio.Shell.Interop.IVsUIShell5)serviceObject;
System.Runtime.InteropServices.Marshal.Release(serviceIntPtr);
}
return shell5;
}
private Bitmap GetInvertedBitmap(Microsoft.VisualStudio.Shell.Interop.IVsUIShell5 shell5, Bitmap inputBitmap,
Color transparentColor, uint backgroundColor)
{
Bitmap outputBitmap = null;
byte[] outputBytes = null;
Rectangle rect;
System.Drawing.Imaging.BitmapData bitmapData = null;
IntPtr sourcePointer;
int length = 0;
try
{
outputBitmap = new Bitmap(inputBitmap);
outputBitmap.MakeTransparent(transparentColor);
rect = new Rectangle(0, 0, outputBitmap.Width, outputBitmap.Height);
bitmapData = outputBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, outputBitmap.PixelFormat);
sourcePointer = bitmapData.Scan0;
length = (Math.Abs(bitmapData.Stride) * outputBitmap.Height);
outputBytes = new byte[length];
Marshal.Copy(sourcePointer, outputBytes, 0, length);
shell5.ThemeDIBits((UInt32)outputBytes.Length, outputBytes, (UInt32)outputBitmap.Width,
(UInt32)outputBitmap.Height, true, backgroundColor);
Marshal.Copy(outputBytes, 0, sourcePointer, length);
outputBitmap.UnlockBits(bitmapData);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
return outputBitmap;
}
private void InitializeAddIn()
{
const string COLOR_NAME = "ToolWindowBackground";
const string GUID_COLOR_TABLE_ENVIRONMENT_CATEGORY = "624ed9c3-bdfd-41fa-96c3-7c824ea32e3d";
uint backgroundColor = 0;
Form1 frm1 = null;
Bitmap inputBitmap = null;
Bitmap outputBitmap = null;
Color almostGreenColor;
Microsoft.VisualStudio.Shell.Interop.IVsUIShell5 shell5 = null;
try
{
shell5 = GetIVsUIShell5();
// Get the background color of toolwindows
backgroundColor = shell5.GetThemedColor(new System.Guid(GUID_COLOR_TABLE_ENVIRONMENT_CATEGORY), COLOR_NAME, 0);
frm1 = new Form1();
// Apply the background color to the form
frm1.BackColor = ColorTranslator.FromWin32(Convert.ToInt32(backgroundColor & 0xffffff));
// Get the unthemed input bitmap.
// Note: Change the modifer from private to public
inputBitmap = new Bitmap(frm1.pictureBox1.Image);
// Assume that the transparent color is almost green. It can be any color
almostGreenColor = Color.FromArgb(0, 254, 0);
// Get the themed output bitmap
outputBitmap = GetInvertedBitmap(shell5, inputBitmap, almostGreenColor, backgroundColor);
inputBitmap.Dispose();
// Note: Change the modifer from private to public
frm1.pictureBox2.Image = outputBitmap;
frm1.ShowDialog();
frm1.Dispose();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
{
}
public void OnAddInsUpdate(ref Array custom)
{
}
public void OnBeginShutdown(ref Array custom)
{
}
}
}
Related articles
Go back to the 'Resources for Visual Studio .NET extensibility' section for more articles like this