dotnet/wpf · error · Win32Exception

Win32Exception(errorCode)

Error message

Win32Exception(errorCode)

What it means

Cursor.LoadFromFile throws a bare Win32Exception(errorCode) when the Win32 LoadImage call fails with a Win32 error code other than ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND (e.g. ERROR_ACCESS_DENIED, ERROR_INVALID_PARAMETER). Unlike the not-found case, this exception carries only the native error code, so the message text is whatever Win32Exception maps the code to.

Solutions

  1. Confirm the file is a genuine .cur or .ani cursor file, not a renamed image.
  2. Check the Win32Exception.NativeErrorCode and look up its meaning (e.g. 5 = access denied → fix file ACLs).
  3. Verify the file is not locked by another process and readable by the app identity.
  4. Re-export/re-download the cursor file to rule out corruption.
  5. Wrap construction in try-catch and fall back to a built-in System.Windows.Input.Cursors value.

Example fix

// before
cursor = new Cursor(logoPath); // logoPath points to a .png
// after
if (Path.GetExtension(logoPath).Equals(".cur", StringComparison.OrdinalIgnoreCase))
    cursor = new Cursor(logoPath);
else
    cursor = Cursors.Arrow;
Defensive patterns

Strategy: try-catch

Validate before calling

if (!File.Exists(path)) throw new FileNotFoundException(path);
var ext = Path.GetExtension(path).ToLowerInvariant();
if (ext != ".cur" && ext != ".ani") throw new InvalidOperationException($"Not a cursor file: {ext}");

Type guard

bool LooksLikeCursorFile(string path) => File.Exists(path) && ".cur|.ani".Contains(Path.GetExtension(path).ToLowerInvariant());

Try / catch

try { cursor = new Cursor(path); }
catch (Win32Exception ex)
{ logger.LogError("LoadImage failed, native error {Code}", ex.NativeErrorCode); cursor = Cursors.Arrow; }

Prevention

When it happens

Trigger: new Cursor(fileName) where LoadImage fails with an unexpected native error — file exists but is not a valid cursor file, is corrupt, is locked, or access is denied (shares/permissions).

Common situations: Pointing a Cursor at a .png/.ico/.bmp instead of a real .cur/.ani file; corrupted downloads; file locked by another process; missing read permission; antivirus blocking reads.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/8c044ecb0ecae018. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/Cursor.cs:190

            if (_cursorHandle == null || _cursorHandle.IsInvalid)
            {
                // LoadImage returns a null handle but does not set
                // the error condition when icon file is of an incorrect type (e.g., .bmp)
                //
                // LoadImage has a bug where it doesn't set the correct error code
                // when a file is given that is not an ico file.  Icon load fails
                // but win32 error code is still zero (success).  Thus, we need to
                // special case this scenario.
                //
                if (errorCode != 0)
                {
                    if ((errorCode == NativeMethods.ERROR_FILE_NOT_FOUND) || (errorCode == NativeMethods.ERROR_PATH_NOT_FOUND))
                    {
                        throw new Win32Exception(errorCode, SR.Format(SR.Cursor_LoadImageFailure, fileName));
                    }
                    else
                    {
                        throw new Win32Exception(errorCode);
                    }
                }
                else
                {
                    throw new ArgumentException(SR.Format(SR.Cursor_LoadImageFailure, fileName));
                }
            }
        }

        //**** DEAD CODE - retained only for compat, if user sets quirk flag  ****
        private const int BUFFERSIZE = 4096; // the maximum size of the buffer used for loading from stream

        private void LegacyLoadFromStream(Stream cursorStream)
        {
            //Generate a temporal file based on the memory stream.

            // GetTempFileName requires unrestricted Environment permission
            // FileIOPermission.Write permission.  However, since we don't

View on GitHub (pinned to 81131a70a4)