HandyOrg/HandyControl · error
StatusException(status)
Error message
StatusException(status)
What it means
GDI+ returned a non-Ok status from GdipCreateBitmapFromHBITMAP while wrapping the screen-capture HBITMAP into a native Bitmap inside ScreenshotWindow. The library immediately surfaces it as a StatusException. In a screenshot flow this usually means the HBITMAP or its palette handle was invalid at conversion time.
Solutions
- Verify desktopWindowWidth/Height are > 0 and all GDI handles (CreateCompatibleDC/Bitmap, SelectObject) succeeded before this call
- Check GetDC/GetDesktopWindow results and retry capture if BitBlt failed
- Release/Dispose each capture's HBITMAP and DCs to prevent GDI handle leaks over repeated screenshots
- Catch the StatusException around the capture and show a user-facing 'capture failed' fallback
Example fix
// before
var status = InteropMethods.Gdip.GdipCreateBitmapFromHBITMAP(new HandleRef(null, hbitmap), new HandleRef(null, IntPtr.Zero), out var bitmap);
if (status != InteropMethods.Gdip.Ok) throw InteropMethods.Gdip.StatusException(status);
// after
if (desktopWindowWidth <= 0 || desktopWindowHeight <= 0)
throw new InvalidOperationException("Desktop has no drawable area; screenshot aborted.");
var status = InteropMethods.Gdip.GdipCreateBitmapFromHBITMAP(new HandleRef(null, hbitmap), new HandleRef(null, IntPtr.Zero), out var bitmap);
if (status != InteropMethods.Gdip.Ok || bitmap == IntPtr.Zero)
throw InteropMethods.Gdip.StatusException(status); Defensive patterns
Strategy: try-catch
Validate before calling
if (desktopWindowWidth <= 0 || desktopWindowHeight <= 0 || hbitmap == IntPtr.Zero)
throw new InvalidOperationException("Invalid capture state; aborting bitmap conversion."); Type guard
static bool IsCaptureValid(int w, int h, IntPtr hbmp) => w > 0 && h > 0 && hbmp != IntPtr.Zero;
Try / catch
try { status = GdipCreateBitmapFromHBITMAP(...); if (status != Ok) throw StatusException(status); }
catch (ExternalException) { /* retry capture or notify user */ } Prevention
- Check every GDI handle creation result before BitBlt
- Handle secure-desktop / elevated-UAC captures gracefully
- Delete HBITMAPs and release DCs after each capture to avoid handle exhaustion
When it happens
Trigger: Taking a screenshot where the freshly created HBITMAP could not be converted — e.g. the CompatibleBitmap creation failed earlier (bad HDC, zero desktop width/height, secure desktop/UAC elevation differences) — or a null hbitmap reached GdipCreateBitmapFromHBITMAP.
Common situations: Capturing on secure desktops / elevated UAC prompts where BitBlt yields an empty bitmap; RDP sessions with disconnected monitors (zero-size desktop); GDI handle exhaustion after many captures.
Related errors
- GdiplusInvalidSize
- StatusException(InteropMethods.Gdip.OutOfMemory)
- StatusException(status)
- stream null
- NativeHandle0
AI-assisted analysis of HandyOrg/HandyControl@2c0875ebd6 (2026-09-14).
Data as JSON: /api/errors/31dcd8917f1f8139.
Report an issue: GitHub.
Appendix: source
Thrown at src/Shared/HandyControl_Shared/Controls/Screenshot/ScreenshotWindow.cs:569
private BitmapSource GetDesktopSnapshot()
{
_desktopWindowHandle = InteropMethods.GetDesktopWindow();
var hdcSrc = InteropMethods.GetWindowDC(_desktopWindowHandle);
var hdcDest = InteropMethods.CreateCompatibleDC(hdcSrc);
InteropMethods.GetWindowRect(_desktopWindowHandle, out _desktopWindowRect);
var desktopWindowWidth = _desktopWindowRect.Right - _desktopWindowRect.Left;
var desktopWindowHeight = _desktopWindowRect.Bottom - _desktopWindowRect.Top;
var hbitmap = InteropMethods.CreateCompatibleBitmap(hdcSrc, desktopWindowWidth, desktopWindowHeight);
var hOld = InteropMethods.SelectObject(hdcDest, hbitmap);
InteropMethods.BitBlt(hdcDest, 0, 0, desktopWindowWidth, desktopWindowHeight, hdcSrc, 0, 0, InteropValues.SRCCOPY);
InteropMethods.SelectObject(hdcDest, hOld);
InteropMethods.DeleteDC(hdcDest);
InteropMethods.ReleaseDC(_desktopWindowHandle, hdcSrc);
var status = InteropMethods.Gdip.GdipCreateBitmapFromHBITMAP(new HandleRef(null, hbitmap), new HandleRef(null, IntPtr.Zero), out var bitmap);
if (status != InteropMethods.Gdip.Ok) throw InteropMethods.Gdip.StatusException(status);
using var ms = new MemoryStream();
status = InteropMethods.Gdip.GdipGetImageEncodersSize(out var numEncoders, out var size);
if (status != InteropMethods.Gdip.Ok) throw InteropMethods.Gdip.StatusException(status);
var memory = Marshal.AllocHGlobal(size);
try
{
status = InteropMethods.Gdip.GdipGetImageEncoders(numEncoders, size, memory);
if (status != InteropMethods.Gdip.Ok) throw InteropMethods.Gdip.StatusException(status);
var codecInfo = ImageCodecInfo.ConvertFromMemory(memory, numEncoders).FirstOrDefault(item => item.FormatID.Equals(BmpGuid));
if (codecInfo == null) throw new Exception("ImageCodecInfo is null");
var encoderParamsMemory = IntPtr.Zero;
try
{View on GitHub (pinned to 2c0875ebd6)