BCUninstaller/Bulk-Crap-Uninstaller · error · ArgumentException

Icon handle must not be zero

Error message

Icon handle must not be zero

What it means

Thrown by DrawingTools.CreateOwnedIconFromHandle(IntPtr handle) when handle == IntPtr.Zero. The method clones the native icon into a managed Icon and then always calls DestroyIcon on the handle in a finally block, so passing zero would both be meaningless and would leak/destroy an invalid handle; it fails fast with ArgumentException(nameof(handle)).

Source

Thrown at source/KlocTools/Tools/DrawingTools.cs:65

                var iconPath = new StringBuilder(260);
                iconPath.Append(filePath);
                
                var index = 0;
                var handle = SafeNativeMethods.ExtractAssociatedIcon(new HandleRef(null, IntPtr.Zero), iconPath, ref index);
                if (handle != IntPtr.Zero)
                    return CreateOwnedIconFromHandle(handle);
            }
            return null;
        }

        /// <summary>
        /// Clone an icon handle into a managed icon instance and release the original native handle.
        /// </summary>
        public static Icon CreateOwnedIconFromHandle(IntPtr handle)
        {
            if (handle == IntPtr.Zero)
                throw new ArgumentException("Icon handle must not be zero", nameof(handle));

            try
            {
                using (var temporaryIcon = Icon.FromHandle(handle))
                {
                    return (Icon)temporaryIcon.Clone();
                }
            }
            finally
            {
                SafeNativeMethods.DestroyIcon(handle);
            }
        }


        /// <summary>
        /// This class suppresses stack walks for unmanaged code permission. 
        /// (System.Security.SuppressUnmanagedCodeSecurityAttribute is applied to this class.) 

View on GitHub (pinned to 608321de98)

Solutions

  1. Check for IntPtr.Zero before calling and skip/null-return instead.
  2. Use the calling code's own guard (the snippet already shows the caller does `if (handle != IntPtr.Zero) return CreateOwnedIconFromHandle(handle);`).
  3. Log why the source extraction returned zero (bad file path, missing resource) and handle upstream.

Example fix

// before
var icon = DrawingTools.CreateOwnedIconFromHandle(h); // h may be Zero

// after
Icon icon = h == IntPtr.Zero ? null : DrawingTools.CreateOwnedIconFromHandle(h);
Defensive patterns

Strategy: validation

Validate before calling

Icon icon = handle == IntPtr.Zero ? null : DrawingTools.CreateOwnedIconFromHandle(handle);

Type guard

static bool IsValidIconHandle(IntPtr h) => h != IntPtr.Zero;

Prevention

When it happens

Trigger: Passing IntPtr.Zero (a sentinel for 'no icon') into CreateOwnedIconFromHandle instead of checking first. Common after ExtractIcon/LoadImage return zero on failure.

Common situations: Calling the API after a native icon-extraction call that returned zero (file has no associated icon, missing resource, wrong type), or forwarding an uninitialised IntPtr.

Related errors


AI-assisted analysis of BCUninstaller/Bulk-Crap-Uninstaller@608321de98 (2026-08-13). Data as JSON: /api/errors/ac03366ea8a4f930. Report an issue: GitHub.