torsdag 10. februar 2011

Memory leaks while converting from bitmap to bitmapsource

One project I'm working on is using TwainDotNet. It has been some work to get to work "exactly" like we want it to, but it's overall been a nice library to play with.
But today, I've been working on a memory leak... These bugs are really annoying to work on, but anyhow here is what I found out:
The problem is that the sample code and samples I've found on the internet for converting Bitmap to BitmapSource. The code usually looks something like this:
    image1.Source = Imaging.CreateBitmapSourceFromHBitmap(
        new System.Drawing.Bitmap(args.Image).GetHbitmap(),
        IntPtr.Zero,
        Int32Rect.Empty,
        BitmapSizeOptions.FromEmptyOptions());

This works fine, but it also creates a HBitmap in unmanaged memory that it doesn't free.
A better way to solve this is to store the HBitmap in a variable and call DeleteObject on it. DeleteObject is a function from gdi32.dll:
    [System.Runtime.InteropServices.DllImport("gdi32.dll")]
    public static extern bool DeleteObject(IntPtr hObject);

Here is the code I ended up with in our production code:
    private void TwainOnTransferImage(Object sender, TransferImageEventArgs e) {
        if (e.Image != null) {
            var bmp = new System.Drawing.Bitmap(e.Image);
            IntPtr hBitmap = bmp.GetHbitmap();
            image1.BeginInit();
            image1.Source = Imaging.CreateBitmapSourceFromHBitmap(
                hBitmap,
                IntPtr.Zero,
                Int32Rect.Empty,
                BitmapSizeOptions.FromEmptyOptions());
            image1.EndInit();
            image1.Source.Freeze();
            DeleteObject(hBitmap);
            bmp.Dispose();
            e.Image.Dispose();
        }
    }