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
- Confirm the file is a genuine .cur or .ani cursor file, not a renamed image.
- Check the Win32Exception.NativeErrorCode and look up its meaning (e.g. 5 = access denied → fix file ACLs).
- Verify the file is not locked by another process and readable by the app identity.
- Re-export/re-download the cursor file to rule out corruption.
- 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
- Only pass genuine .cur/.ani files — never renamed .png/.ico/.bmp files.
- Inspect NativeErrorCode to distinguish access-denied from corrupt-file issues.
- Verify file permissions for the running app identity in restricted environments.
- Fall back to built-in Cursors values for non-critical customization.
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
- SR.Cursor_LoadImageFailure (fileName)
- ArgumentNullException
- InvalidOperationException
- InvalidOperationException
- new System.ComponentModel.Win32Exception(win32Error)
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'tView on GitHub (pinned to 81131a70a4)