stride3d/stride · error · ArgumentNullException

uiControl

Error message

uiControl

What it means

InputSourceWinforms' constructor requires a WinForms Control used as the message pump target for mouse/keyboard/gamepad events. Passing null throws ArgumentNullException immediately. Without a control handle, Windows messages driving Stride input cannot be received.

Solutions

  1. Create the Form/Control first and pass the live instance to the constructor.
  2. Assert the control is non-null and its handle exists before constructing the input source.
  3. Delay input-source initialization until the UI control is available.

Example fix

// before
var source = new InputSourceWinforms(controlField);
// after
if (controlField == null)
    throw new InvalidOperationException("InputSourceWinforms requires an initialized Control.");
var source = new InputSourceWinforms(controlField);
Defensive patterns

Strategy: validation

Validate before calling

if (uiControl == null || uiControl.IsDisposed)
    throw new InvalidOperationException("InputSourceWinforms requires a live Control.");
var source = new InputSourceWinforms(uiControl);

Type guard

bool HasValidControl(Control c) => c != null && !c.IsDisposed;

Try / catch

try
{
    var source = new InputSourceWinforms(uiControl);
}
catch (ArgumentNullException)
{
    // Defer input initialization until the form/control is created.
}

Prevention

When it happens

Trigger: Calling new InputSourceWinforms(null) or passing a form/control reference that is still null at construction time.

Common situations: Constructing the input source before Application.Run / form creation; unit-testing the input pipeline without a real control; refactoring where the control field is initialized after the input source.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/ff6195b6bfdd772b. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Input/Windows/InputSourceWinforms.cs:44

        private KeyboardWinforms keyboard;
        private MouseWinforms mouse;
        private PointerWinforms pointer;

        private IntPtr defaultWndProc;
        private Win32Native.WndProc inputWndProc;

        // My input devices
        private readonly Control uiControl;
        private InputManager input;

        /// <summary>
        /// Gets the value indicating if the mouse position is currently locked or not.
        /// </summary>
        public bool IsMousePositionLocked { get; protected set; }

        public InputSourceWinforms(Control uiControl)
        {
            this.uiControl = uiControl ?? throw new ArgumentNullException(nameof(uiControl));
        }

        public override void Initialize(InputManager inputManager)
        {
            input = inputManager;

            // Hook window proc
            defaultWndProc = Win32Native.GetWindowLong(uiControl.Handle, Win32Native.WindowLongType.WndProc);
            // This is needed to prevent garbage collection of the delegate.
            inputWndProc = WndProc;
            var inputWndProcPtr = Marshal.GetFunctionPointerForDelegate(inputWndProc);
            Win32Native.SetWindowLong(uiControl.Handle, Win32Native.WindowLongType.WndProc, inputWndProcPtr);

            // Do not register keyboard devices when using raw input instead
            keyboard = new KeyboardWinforms(this, uiControl);
            RegisterDevice(keyboard);

            mouse = new MouseWinforms(this, uiControl);

View on GitHub (pinned to 96fad776d2)