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

  1. Verify desktopWindowWidth/Height are > 0 and all GDI handles (CreateCompatibleDC/Bitmap, SelectObject) succeeded before this call
  2. Check GetDC/GetDesktopWindow results and retry capture if BitBlt failed
  3. Release/Dispose each capture's HBITMAP and DCs to prevent GDI handle leaks over repeated screenshots
  4. 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

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


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)