HandyOrg/HandyControl · error · Win32Exception
Win32Exception
Error message
Win32Exception
What it means
WindowHelper.SystemDpi (or the DPI-Y cache slot) calls the Win32 GetDC(NULL) to obtain a device context for the desktop window and read LOGPIXELSY. When GetDC returns IntPtr.Zero the helper throws a parameterless Win32Exception, whose ErrorCode is Marshal.GetLastWin32Error(). It means Windows refused to hand out a screen DC, so the library cannot determine vertical screen DPI.
Solutions
- Ensure the code runs in an interactive user session (WPF apps cannot compute screen DPI in Session 0 — move DPI work into the UI process).
- Check/relieve GDI handle pressure: leak GDI objects elsewhere in the app can make GetDC fail; inspect with Task Manager's GDI Objects column.
- Wrap the first HandyControl window/show call in a try-catch for Win32Exception and fall back to a fixed 96.0 DPI value.
- Reconnect a disconnected RDP session or log in interactively before launching the app.
- Update HandyControl; newer versions cache DPI differently and handle headless environments more gracefully.
Example fix
// before
var dpi = WindowHelper.SystemDPI; // throws Win32Exception headless
// after
double dpi = 96.0;
try { dpi = WindowHelper.SystemDPI; }
catch (Win32Exception) { /* non-interactive session: assume 96 DPI */ } Defensive patterns
Strategy: try-catch
Validate before calling
// not applicable: failure is environmental, cannot be pre-validated safely // optional session check: bool hasDesktop = Environment.UserInteractive;
Try / catch
try { dpi = WindowHelper.SystemDPI; }
catch (Win32Exception ex) { Log.Warn($"DPI detection failed: {ex.NativeErrorCode}"); dpi = 96.0; } Prevention
- Never run WPF/HandyControl UI initialization from services, scheduled tasks, or Session 0.
- Monitor the process GDI object count; fix GetDC/ReleaseDC imbalances.
- Default to 96 DPI when DPI detection fails so rendering still works.
- Test the app headless in CI to catch this early.
When it happens
Trigger: Calling any HandyControl API that reads SystemDpi/DPI-aware window metrics when InteropMethods.GetDC(new HandleRef(null, IntPtr.Zero)) fails and returns IntPtr.Zero, e.g. during WindowHelper initialization in a non-interactive session.
Common situations: App running as a Windows Service or scheduled task without an interactive desktop; Session 0 isolation; remote desktop disconnecting right at startup; heavily locked-down terminal servers or GDI handle exhaustion in the process; WindowsCitrix/virtual sessions where the desktop window is unavailable.
Related errors
- Win32Exception
- Unable to create a device context from the specified device…
- Unable to combine two HRGNs.
- NotSupportedException
- NotSupportedException
AI-assisted analysis of HandyOrg/HandyControl@2c0875ebd6 (2026-09-14).
Data as JSON: /api/errors/20607fa84ed7a8cd.
Report an issue: GitHub.
Appendix: source
Thrown at src/Shared/HandyControl_Shared/Tools/Helper/WindowHelper.cs:58
{
[SecurityCritical, SecuritySafeCritical]
get
{
if (!_dpiInitialized)
{
lock (_dpiLock)
{
if (!_dpiInitialized)
{
var desktopWnd = new HandleRef(null, IntPtr.Zero);
// Win32Exception will get the Win32 error code so we don't have to
var dc = InteropMethods.GetDC(desktopWnd);
// Detecting error case from unmanaged call, required by PREsharp to throw a Win32Exception
if (dc == IntPtr.Zero)
{
throw new Win32Exception();
}
try
{
_dpi = InteropMethods.GetDeviceCaps(new HandleRef(null, dc), InteropValues.LOGPIXELSY);
_dpiInitialized = true;
}
finally
{
InteropMethods.ReleaseDC(desktopWnd, new HandleRef(null, dc));
}
}
}
}
return _dpi;
}
}
View on GitHub (pinned to 2c0875ebd6)