dotnet/wpf · error · ObjectDisposedException

SR.Penservice_Disposed

Error message

SR.Penservice_Disposed

What it means

PenThreadWorker.AddPenContext (WorkerAddPenContext) throws ObjectDisposedException (SR.Penservice_Disposed) when the pen thread worker has already been disposed but a new pen context is added to it. Once the stylus worker thread is shutting down, no further pen contexts may be registered.

Solutions

  1. Guard the worker's lifetime: do not add pen contexts after disposal; recreate a new PenThreadWorker if needed
  2. Ensure windows' stylus support is disabled before the worker disposes
  3. Check for races in window close/dispose ordering when multiple HwndSources share the pen service
  4. Catch ObjectDisposedException around context registration during teardown

Example fix

// before
worker.WorkerAddPenContext(penContext); // may already be disposed during shutdown
// after
if (!worker.IsDisposed)
    worker.WorkerAddPenContext(penContext);
Defensive patterns

Strategy: try-catch

Validate before calling

if (!worker.IsDisposed)
    worker.WorkerAddPenContext(penContext);

Try / catch

try { worker.WorkerAddPenContext(penContext); }
catch (ObjectDisposedException) { /* worker shutting down; skip registration */ }

Prevention

When it happens

Trigger: Adding a PenContext to the worker after the PenService/worker thread was disposed — e.g. a window/tablet is torn down while another stylus device still attempts registration, or re-enabling a HwndSource's stylus support after shutdown.

Common situations: Closing one window while pen events are still in flight; rapid open/close of windows with stylus input; disposing the PenService and then re-attaching a tablet device; shutdown races during application exit.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/1ba96c6afadceb0d. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/Stylus/Wisp/PenThreadWorker.cs:511

        {
            if(!__disposed)
            {
                __disposed = true;
                
                // Kick thread to wake up and see we are disposed.
                MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle);
                // Let it destroy the reset event.
            }
            GC.KeepAlive(this);
        }

        /////////////////////////////////////////////////////////////////////

        internal bool WorkerAddPenContext(PenContext penContext)
        {
            if (__disposed)
            {
                throw new ObjectDisposedException(null, SR.Penservice_Disposed);
            }

            Debug.Assert(penContext != null);
            
            WorkerOperationAddContext addContextOperation = new WorkerOperationAddContext(penContext, this);

            lock(_workerOperationLock)
            {
                _workerOperation.Add(addContextOperation);
            }

            // Kick thread to do this work.
            MS.Win32.Penimc.UnsafeNativeMethods.RaiseResetEvent(_pimcResetHandle);

            // Wait for this work to be completed.
            addContextOperation.DoneEvent.WaitOne();
            addContextOperation.DoneEvent.Close();

View on GitHub (pinned to 81131a70a4)