Austin Salonen
Austin Salonen

Reputation: 50235

C#, WinForms: ListBox.Items.Add generates an OutOfMemoryException, why?

First off, I found the solution to the exception. I'm more curious why it generated the specific exception it did.

In my scenario I'm adding a POCO to a ListBox like so:

myListBox.Items.Add(myPOCO);

This was generating an OutOfMemoryException. The problem was that ToString off the POCO was returning null. I added a string.IsNullOrEmpty check to return a "safe" value when null and the exception went away.

Why does this generate an OutOfMemoryException and not something else (say a NullReferenceException)?

EDIT: Items are added in a for loop.

Full call stack (company-specific references removed) is below. One thing to note -- the list box is empty when this is called.

System.OutOfMemoryException was unhandled
  Message="List box contains too many items."
  Source="System.Windows.Forms"
  StackTrace:
       at System.Windows.Forms.ListBox.NativeAdd(Object item)
       at System.Windows.Forms.ListBox.ObjectCollection.AddInternal(Object item)
       at System.Windows.Forms.ListBox.ObjectCollection.Add(Object item)
       at <FORM>_Load(Object sender, EventArgs e) in <PATH>\<FORM>.cs:line 52
       at System.Windows.Forms.Form.OnLoad(EventArgs e)
       at System.Windows.Forms.Form.OnCreateControl()
       at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
       at System.Windows.Forms.Control.CreateControl()
       at System.Windows.Forms.Control.WmShowWindow(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
       at System.Windows.Forms.ContainerControl.WndProc(Message& m)
       at System.Windows.Forms.Form.WmShowWindow(Message& m)
       at System.Windows.Forms.Form.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.SafeNativeMethods.ShowWindow(HandleRef hWnd, Int32 nCmdShow)
       at System.Windows.Forms.Control.SetVisibleCore(Boolean value)
       at System.Windows.Forms.Form.SetVisibleCore(Boolean value)
       at System.Windows.Forms.Control.set_Visible(Boolean value)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.RunDialog(Form form)
       at System.Windows.Forms.Form.ShowDialog(IWin32Window owner)
       at System.Windows.Forms.Form.ShowDialog()
       at <APP>.Program.Main() in <PATH>\Program.cs:line 25
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
       at System.Runtime.Hosting.ManifestRunner.Run(Boolean checkAptModel)
       at System.Runtime.Hosting.ManifestRunner.ExecuteAsAssembly()
       at System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext, String[] activationCustomData)
       at System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext)
       at System.Activator.CreateInstance(ActivationContext activationContext)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssemblyDebugInZone()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()

Upvotes: 10

Views: 7631

Answers (3)

ZappySys
ZappySys

Reputation: 11

If you get such error then carefully check your code where you are calling listbox.Items.Add or listbox.DataSource = xxxxx. Whatever Object Type is added or bound to list box must return non Null in ToString() method. By default .net returns Type name if you do not override ToString() method.

If you have implemented your own version of ToString() (with override keyword) then make sure method has fail safe to returns non NULL string. See example below how you can add extra 2 lines to avoid such odd error which many people will find totally misleading.

//listbox.Items.Add(new MyItem());
//--or--
//listbox.DataSource= new List<MyItem>(){ new MyItem() };

public class MyItem
{
    public string Name { get; set; }
    public string Label { get; set; }

    public override string ToString()
    {
        //Not adding below 2 lines might throw OutOfMemoryException in listbox.Items.Add or listbox.DataSOurce = somelist
        if (string.IsNullOrEmpty(Label)) //Added this check to avoid 
            return this.GetType().Name; //Return string.Empty or something other than null else you will get OutOfMemoryException error when you add or bind this object to listbox

        return Label;
    }
}

Upvotes: 1

Darin Dimitrov
Darin Dimitrov

Reputation: 1039080

This is because of the way System.Windows.Forms.ListBox.NativeAdd method is implemented:

private int NativeAdd(object item)
{
    int num = (int) base.SendMessage(0x180, 0, base.GetItemText(item));
    switch (num)
    {
        case -2:
            throw new OutOfMemoryException();

        case -1:
            throw new OutOfMemoryException(SR.GetString("ListBoxItemOverflow"));
    }
    return num;
}

The GetItemText method uses ToString() on the object which returns null and so a message is sent with null parameter, which in turn returns an invalid pointer and you enter the second case which throws the exception.

Upvotes: 23

Justin Grant
Justin Grant

Reputation: 46713

When the underlying LB_ADDSTRING Windows API call fails, WinForms always returns an OutOfMemoryException. A comment in the .NET Framework Reference Source explains why:

// On some platforms (e.g. Win98), the ListBox control
// appears to return LB_ERR if there are a large number (>32000)
// of items. It doesn't appear to set error codes appropriately,
// so we'll have to assume that LB_ERR corresponds to item 
// overflow.
// 
throw new OutOfMemoryException(SR.GetString(SR.ListBoxItemOverflow)); 

Upvotes: 12

Related Questions