babalae/better-genshin-impact · error · ArgumentOutOfRangeException

鼠标限制区域必须具有有效宽度和高度。

Error message

鼠标限制区域必须具有有效宽度和高度。

What it means

LocalCursorCapture.Capture clamps the OS cursor to a desktop region (the game's 'desktop clone' control). A region with zero or negative width/height is unusable as a clip rectangle and would leave the cursor trapped or unbounded, so the method throws ArgumentOutOfRangeException before touching ClipCursor. The check runs after the ObjectDisposedException guard, so it also implies the instance is still live.

Source

Thrown at BetterGenshinImpact/Core/Monitor/LocalCursorCapture.cs:34

    private const int SmXVirtualScreen = 76;
    private const int SmYVirtualScreen = 77;
    private const int SmCxVirtualScreen = 78;
    private const int SmCyVirtualScreen = 79;

    private NativeRect _previousClipRect;
    private Rectangle _appliedBounds;
    private bool _hasPreviousClipRect;
    private bool _isCaptureSessionActive;
    private bool _isRestrictionApplied;
    private bool _isDisposed;
    private int _cursorHideCallCount;

    internal void Capture(Rectangle bounds)
    {
        ObjectDisposedException.ThrowIf(_isDisposed, this);
        if (bounds.Width <= 0 || bounds.Height <= 0)
        {
            throw new ArgumentOutOfRangeException(
                nameof(bounds),
                bounds,
                "鼠标限制区域必须具有有效宽度和高度。");
        }

        if (!_isCaptureSessionActive)
        {
            var clipRectRead = NativeMethods.GetClipCursor(out _previousClipRect);
            if (!clipRectRead)
            {
                logger.LogWarning(
                    "读取现有鼠标限制区域失败,Win32Error: {Win32Error}",
                    Marshal.GetLastWin32Error());
            }

            _hasPreviousClipRect =
                clipRectRead && !IsVirtualDesktopBounds(_previousClipRect);
            _isCaptureSessionActive = true;

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Ensure the source window/control has non-zero size before invoking Capture.
  2. Guard the caller: if (bounds.Width <= 0 || bounds.Height <= 0) return/skip.
  3. Recompute bounds from the live capture region right before calling Capture.

Example fix

// before
_cursorCapture.Capture(rect);

// after
if (rect.Width <= 0 || rect.Height <= 0) return;
_cursorCapture.Capture(rect);
Defensive patterns

Strategy: validation

Validate before calling

if (bounds.Width <= 0 || bounds.Height <= 0) return; // skip invalid region
_cursorCapture.Capture(bounds);

Type guard

static bool IsValidClipRect(Rectangle r) => r.Width > 0 && r.Height > 0;

Prevention

When it happens

Trigger: Passing a Rectangle.Empty or default(Rectangle); a capture rect computed from a zero-size window; bounds derived from a monitor region that returned 0 before the window was laid out.

Common situations: Starting capture before the game window has a valid client rect; multi-monitor setups where the source window reports 0 size momentarily; DPI/scale math producing 0 dimensions.

Related errors


AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13). Data as JSON: /api/errors/37dc7f5d8817a428. Report an issue: GitHub.