Search code examples
c#winformsmemorystreamimagelist

ImageList throws "Out of memory" exception when adding images from SQL database


I have a few SQL databases which has a table that store images using varbinary datatype.

On button click, it will remove all existing images except the first three images from the ImageList control and add all new images to the ImageList on my form.

There is a TreeView that uses this ImageList.

I've been getting:

Out of memory exception

...if I click the button many times on the same database.

Simplified code:

if(imageList1.Images.Count > 3)
{
    for (int i = imageList1.Images.Count - 1; i > 2; i--)
    {
       imageList1.Images.RemoveAt(i);      
    }
}
int counter = 0;
foreach (DataRow dr in dataset.Tables[0].Rows)
{
    if (dr["ImageField"] != DBNull.Value)
    {
        byte[] imageData = (byte[])dr["ImageField"];
        MemoryStream ms = new MemoryStream(imageData, 0, imageData.Length);
        Bitmap img = new Bitmap(ms);
        imageList1.Images.Add("Image" + counter, img);
        img.Dispose();
        ms.Dispose();
        counter++;
    }
}

StackTrace:

at System.Drawing.Graphics.FromHdcInternal(IntPtr hdc)
   at System.Drawing.Font.ToLogFont(Object logFont)
   at System.Drawing.Font.ToHfont()
   at System.Windows.Forms.Control.FontHandleWrapper..ctor(Font font)
   at System.Windows.Forms.OwnerDrawPropertyBag.get_FontHandle()
   at System.Windows.Forms.TreeView.CustomDraw(Message& m)
   at System.Windows.Forms.TreeView.WmNotify(Message& m)
   at System.Windows.Forms.TreeView.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at System.Windows.Forms.Control.SendMessage(Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.Control.ReflectMessageInternal(IntPtr hWnd, Message& m)
   at System.Windows.Forms.Control.WmNotify(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
   at System.Windows.Forms.Control.DefWndProc(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.TreeView.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd, Int32 msg, Int32 wParam, Int32 lParam)
   at System.Windows.Forms.Control.EndUpdateInternal(Boolean invalidate)
   at System.Windows.Forms.TreeView.ImageListChangedHandle(Object sender, EventArgs e)
   at System.EventHandler.Invoke(Object sender, EventArgs e)
   at System.Windows.Forms.ImageList.OnChangeHandle(EventArgs eventargs)
   at System.Windows.Forms.ImageList.ImageCollection.Add(Original original, ImageInfo imageInfo)
   at System.Windows.Forms.ImageList.ImageCollection.Add(String key, Image image)
   at Test.MyClass.LoadLibraryImageList()

Why does it throw that exception when the memory usage is very low?


Solution

  • Looks like ImageList is just the tip of the iceberg, the real problem lays in my extended MultiSelectTreeView control. After reading this question, I added GC.Collect() to my code whenever I change the TreeNode font and voila, problem solved.

    From the suggestions, I also dispose unwanted images from my ImageList before loading a new batch which seems to help lower my GDI counts too. Thanks everyone.