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
- Guard the worker's lifetime: do not add pen contexts after disposal; recreate a new PenThreadWorker if needed
- Ensure windows' stylus support is disabled before the worker disposes
- Check for races in window close/dispose ordering when multiple HwndSources share the pen service
- 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
- Track worker lifetime explicitly and null it after dispose
- Never re-register pen contexts during shutdown
- Sequence window close before pen service disposal
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
- SR.Format(SR.Invalid_IInputElement, oldCapture.GetType())
- SR.Format(SR.Invalid_IInputElement, oldOver.GetType())
- SR.Format(SR.Invalid_IInputElement…
- SR.PenService_InvalidPacketData
- SR.Stylus_PenContextFailure
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)