Getting a GDI+ Bitmap from an HICON with proper transparency
February 29, 2008
The GDI+ Bitmap class has a nice constructor that takes in a HICON. The problem is that it doesn’t preserve alpha values– icons such as the Firefox icon that have semi-transparent shadows show up with completely black shadows. This code will get you the icon with proper transparency:
Gdiplus::Bitmap *WindowsSystem::GetIconPixelData(HICON hIcon)
{
ICONINFO iconInfo;
GetIconInfo(hIcon, &iconInfo);
BITMAP iconBmp;
GetObject(iconInfo.hbmColor, sizeof(BITMAP),&iconBmp);
Gdiplus::Bitmap* bitmap = new Gdiplus::Bitmap(iconBmp.bmWidth,iconBmp.bmHeight,PixelFormat32bppARGB);
bool hasAlpha = false;
{
// We have to read the raw pixels of the bitmap to get proper transparency information
// (not sure why, all we're doing is copying one bitmap into another)
Gdiplus::Bitmap colorBitmap(iconInfo.hbmColor, NULL);
Gdiplus::BitmapData bmpData;
Gdiplus::Rect bmBounds(0, 0, colorBitmap.GetWidth(), colorBitmap.GetHeight());
colorBitmap.LockBits(&bmBounds, Gdiplus::ImageLockModeRead, colorBitmap.GetPixelFormat(), &bmpData);
for (int y = 0; y < colorBitmap.GetHeight(); y++)
{
byte *pixelBytes = (byte*)bmpData.Scan0 + y*bmpData.Stride;
for (int x = 0; x SetPixel(x, y, Gdiplus::Color(*pixel));
hasAlpha = hasAlpha || (pixelBytes[3] > 0 && pixelBytes[3] < 255);
}
}
colorBitmap.UnlockBits(&bmpData);
}
if (!hasAlpha)
{
// If there's no alpha transparency information, we need to use the mask
// to turn back on visible pixels
Gdiplus::Bitmap maskBitmap(iconInfo.hbmMask,NULL);
Gdiplus::Color cMask, cBitmap;
for (int y = 0; y < maskBitmap.GetHeight(); y++)
{
for (int x = 0; x GetPixel(x, y, &cBitmap);
cBitmap.SetValue(cBitmap.GetValue() | 0xFF000000); // turn alpha to opaque (i.e. 0xFF)
bitmap->SetPixel(x, y, cBitmap);
}
}
}
}
return bitmap ;
}
Getting events on WPF Canvas background
October 30, 2007
I recently encountered an error where I was not getting MouseMove events for a Canvas that was within a StackPanel.
The first problem is that, if the background is not set to anything, there will be no events transmitted. A simple solution is just to set the background to transparent or white (or whatever color you want).
The second problem, which took me forever to figure out, stems from the fact that the Canvas width was 1 pixel (or was it 0?) once I put it into my StackPanel. However, this does not keep elements in the Canvas from appearing outside this 1-pixel wide region, so it appears as if the width of the Canvas is greater. So the important thing to realize is that the Canvas will only respond to events that are within the area covered by its width/height.
Windows XP using 100% CPU in Boot Camp
October 18, 2007
I’ve had this problem several times where my Windows XP installed on a Boot Camp partition on my Macbook will suddenly freak out and start using 100% CPU and generally being very unresponsive. Thanks a tip from a friend I found a very easy fix: reboot into MacOS, and then boot into Windows XP again.
It seems that other people have the same problem as well.
Modifying your Child’s transform in WPF without changing its RenderTransform or LayoutTransform
October 6, 2007
Sometimes in WPF you might want to create a class that has a Child and that somehow changes the presentation of the Child, perhaps by scaling it or translating it. And example is the Viewbox class, which scales your content to fit the window. You could do this just by modifying the RenderTransform or LayoutTransform of the Child. However, if you want this be a general, reusable class, you probably shouldn’t touching those properties of your Child, in case someone else might want to.
The solution is to add another node in the hierarchy, so you have:
(your custom class) –> (a private container class) –> Child
Then, you could just modify the container class’s transforms, and it would affect the presentation of the Child. I coded up a trivial example which scales everything 2x:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace Model
{
class ZoomAndPan : Decorator
{
Decorator _container;
public ZoomAndPan()
{
_container = new Decorator();
AddVisualChild(_container);
AddLogicalChild(_container);
_container.RenderTransform = new RotateTransform(45);
}
public override UIElement Child
{
get { return _container.Child; }
set { _container.Child = value; }
}
protected override int VisualChildrenCount
{
get { return _container != null ? 1 : 0; }
}
protected override Visual GetVisualChild(int index)
{
if (index > 0 || _container == null)
throw new ArgumentOutOfRangeException("index");
return _container;
}
protected override Size MeasureOverride(Size sizeAvailable)
{
_container.Measure(sizeAvailable);
return _container.DesiredSize;
}
protected override Size ArrangeOverride(Size sizeArrange)
{
_container.Arrange(new Rect(new Point(0, 0), sizeArrange));
return sizeArrange;
}
[STAThread]
static void Main(string[] args)
{
Rectangle r = new Rectangle();
r.Fill = Brushes.Bisque;
r.Width = 200;
r.Height = 200;
Canvas canv = new Canvas();
canv.Children.Add(r);
ZoomAndPan zp = new ZoomAndPan();
zp.Child = canv;
Window w = new Window();
w.Content = zp;
new Application().Run(w);
}
}
}
Global keyboard and mouse hooks without the lag
September 20, 2007
Note (10/6/2007): I found a much better (and simpler) way of doing this. Details below.
For the purposes of a project I was working on, I needed to detect when the user was pressing a key or moving the mouse. Because my project is all done in C#, I found this piece of code from Code Project very helpful. It’s just a drop-in class that notifies you whenever you receive a keystroke or mouse activity. All was great except for one thing: when you click on the minimize, maximize, or close buttons of your application, the whole application starts stuttering. Other applications running at the time are not affected, but this little problem plagues every implementation of global mouse hooks that I could find, whether written in managed or unmanaged code. Instead, I’m going to use a more roundabout method. I’ll have a very small Win32 app print basic information about events to the console, and then read this information in from my C# application. I found this great little C++ global hooking app after a lot of looking.
Addendum (10/6/2007):
It turns out a much simpler way is to set up the hook in a new thread. You simply create a new thread and call SetWindowsHookEx from that thread. However, if that is all you do you will not be receiving any events. You need to create a message loop in the thread that reads messages coming to it and processes them. Fortunately, this is very easy. Using WPF, all you need to do is call Dispatcher.Run() after you initialize the hook. Using Windows Forms, I think all you need to do is call Application.Run().
“Unrecoverable build error” when building Setup project in Microsoft Visual Studio 2005
August 8, 2007
I was having this problem and tried everything in this Microsoft knowledge base article. It was no help. Finally I tried the suggestion at the end of this forum and it worked! What an intuitive piece of software Visual Studio is….