Last Updated on 2013-07-17.
These exceptions are hardly reproducable if they only appear at the customer’s workstation who cannot explain exactly what they did to get this message – and if it is quite a large project.
Long story short – Don’t forget to dispose controls and other objects if this is not done automatically, e.g. if the controls were not created in the VS Designer.
It you create a control instance in your source code, it might stay there until you close the form (or even longer). So if you remove a control, also make sure you call the Dispose() method of it.
Also make sure that timers really stop after closing a form.
In huge projects, it is not easy to locate the reason for this Win32Exception.
So I will try to explain here how I got rid of these errors.
Task Manager is your friend
In Windows Task Manager details, add the counter colums for handles, threads, user objects and GDI objects. Watch your application if any of these values get very high, e.g. over 1000. They shouldn’t get over 10000 (or near 10000, in most cases), otherwise you get the Win32Exception.
You can test this behaviour with a sample project which includes a loop, e.g. to create new forms which never close etc.
If the exception appears only on other computers in your network, a Remote Task Manager is also available.
Methods via C#
You also get the handle count values in your C# software.
Handle count:
Process.GetCurrentProcess().HandleCount
GDI objects count:
[DllImport("User32")] extern public static int GetGuiResources(IntPtr hProcess, int uiFlags); public static int GetGuiResourcesGDICount() { //Return the count of GDI objects. return GetGuiResources(System.Diagnostics.Process.GetCurrentProcess().Handle, 0); }
User objects count:
[DllImport("User32")] extern public static int GetGuiResources(IntPtr hProcess, int uiFlags); public static int getGuiResourcesUserCount() { return GetGuiResources(System.Diagnostics.Process.GetCurrentProcess().Handle, 1); }
Automated error report
If you cannot debug your software at the workstation where the exception appears, it might be useful to catch all exceptions (e.g. handle Application.ThreadException in Main() method), save a current screenshot e.g. to a temporary folder and write the Exception details to the Windows event log – or mail it to yourself.
Also include PC name, currently open forms count (and their names), process start time (and time running), disk/CPU/RAM usage and all the counter values mentioned above.
With all these values, it could get easier to reproduce such exceptions and then hopefully to solve it.
Thanks for the awesome post, the code snippets to get the handle/object counts in C# were really useful in a project I’m working on.
Caleb