Closed jaelys closed 11 months ago
Please provide a repro project having the issue.
@jaelys Sorry, I run your demo but I do not repro it.
@lindexi Thank you for your help. I updated the Demo and annotated some code that may prevent exceptions. These codes are valid, but not 100%. Now we should be able to simply reproduce the exception. Just press the Pen Button several times, switch another button, and repeat it several times
感謝林德熙大神
@jaelys Sorry, I run the PC-Test-develop-2
, but I do not repro it.
@jaelys Thank you. And I know why. This is the thread-safe issues in WPF.
The DynamicRenderer call the OnRemoved
before the TransitionComplete
. And the OnRemoved
will set the _applicationDispatcher
to null but the TransitionComplete
will use the _applicationDispatcher
which will throw the NullReferenceException.
I add the break point output in the OnRemoved
and NotifyAppOfDRThreadRenderComplete
and TransitionComplete
mehtod. And then I find the output is:
14:12:08:043 NotifyAppOfDRThreadRenderComplete
14:12:08:043 OnRemoved
14:12:08:043 TransitionComplete
It means this is a thread-safe issue.
The NotifyAppOfDRThreadRenderComplete
call stack:
> PresentationCore.dll!System.Windows.Input.StylusPlugIns.DynamicRenderer.NotifyAppOfDRThreadRenderComplete(System.Windows.Input.StylusPlugIns.DynamicRenderer.StrokeInfo si)
PresentationCore.dll!System.Windows.Input.StylusPlugIns.DynamicRenderer.OnDRThreadRenderComplete(object sender, System.EventArgs e)
PresentationCore.dll!System.Windows.Media.MediaContext.CommitChannel()
PresentationCore.dll!System.Windows.Media.MediaContext.Render(System.Windows.Media.ICompositionTarget resizedCompositionTarget)
PresentationCore.dll!System.Windows.Media.MediaContext.RenderMessageHandlerCore(object resizedCompositionTarget)
PresentationCore.dll!System.Windows.Media.MediaContext.RenderMessageHandler(object resizedCompositionTarget)
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs)
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler)
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeImpl()
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(object state)
WindowsBase.dll!MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(object obj)
System.Private.CoreLib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state)
System.Private.CoreLib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state)
WindowsBase.dll!MS.Internal.CulturePreservingExecutionContext.Run(MS.Internal.CulturePreservingExecutionContext executionContext, System.Threading.ContextCallback callback, object state)
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.Invoke()
WindowsBase.dll!System.Windows.Threading.Dispatcher.ProcessQueue()
WindowsBase.dll!System.Windows.Threading.Dispatcher.WndProcHook(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled)
WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled)
WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object o)
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs)
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler)
WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, int numArgs)
WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam)
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame)
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame frame)
WindowsBase.dll!System.Windows.Threading.Dispatcher.Run()
PresentationCore.dll!System.Windows.Input.StylusPlugIns.DynamicRendererThreadManager.DynamicRendererThreadManagerWorker.InkingThreadProc()
System.Private.CoreLib.dll!System.Threading.Thread.StartHelper.Callback(object state)
System.Private.CoreLib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state)
System.Private.CoreLib.dll!System.Threading.Thread.StartCallback()
This thread is DynamicRenderer thread.
The OnRemoved
call stack:
> PresentationCore.dll!System.Windows.Input.StylusPlugIns.DynamicRenderer.OnRemoved()
InkTest.dll!InkTest.DrawPen.OnRemoved()
PresentationCore.dll!System.Windows.Input.StylusPlugIns.StylusPlugIn.Removed()
PresentationCore.dll!System.Windows.Input.StylusPlugIns.StylusPlugInCollection.RemoveItem.AnonymousMethod__1()
PresentationCore.dll!System.Windows.Input.StylusPlugIns.StylusPlugInCollection.ExecuteWithPotentialLock(System.Action action)
PresentationCore.dll!System.Windows.Input.StylusPlugIns.StylusPlugInCollection.RemoveItem.AnonymousMethod__0()
PresentationCore.dll!System.Windows.Input.StylusPlugIns.StylusPlugInCollection.ExecuteWithPotentialDispatcherDisable(System.Action action)
PresentationCore.dll!System.Windows.Input.StylusPlugIns.StylusPlugInCollection.RemoveItem(int index)
System.Private.CoreLib.dll!System.Collections.ObjectModel.Collection<System.Windows.Input.StylusPlugIns.StylusPlugIn>.RemoveAt(int index)
PresentationFramework.dll!System.Windows.Controls.InkCanvas.DynamicRenderer.set(System.Windows.Input.StylusPlugIns.DynamicRenderer value)
InkTest.dll!InkTest.InkCanvasEx.SetInkBrush(string name)
InkTest.dll!InkTest.PenButton.Button_Click(object sender, System.Windows.RoutedEventArgs e)
This thread is main UI thread.
Why can’t it be reproduced in mouse? Because it is a thread-safe issue, and the touch will enter the logic code which runs in Stylus Input
thread, but the mouse will run in main UI thread.
@jaelys Thank you. And I know why. This is the thread-safe issues in WPF.
The DynamicRenderer call the
OnRemoved
before theTransitionComplete
. And theOnRemoved
will set the_applicationDispatcher
to null but theTransitionComplete
will use the_applicationDispatcher
which will throw the NullReferenceException.
I use the physical touch whiteboard, which is easy to reproduce, Abnormality cannot be reproduced in mouse or analog touch
Thank you again for your help
@jaelys Thanks for your feedback, and I am trying to fix this issues.
Description
When using the touch screen, errors will occur, but not when using the mouse
On the touch screen, the two buttons switch and click multiple times to set a custom Dynamic Renderer for InkCanvas.DynamicRenderer. The crash always occurs after DrawPen OnRemoved
Button(DrawPen)、Button(DrawArrow)
`var dr = name switch {
"GeneralPen" => new DrawPen(this),
"ArrowPen" => new DrawArrow(this),
_ => new DrawPen(this), };
DynamicRenderer = dr; `
If set different custom DynamicRenderer multiple times, throw an exception
App_DispatcherUnhandledException--Object reference not set to an instance of an object. at System.Windows.Input.StylusPlugIns.DynamicRenderer.TransitionComplete(StrokeInfo si) at System.Windows.Input.StylusPlugIns.DynamicRenderer.<>c__DisplayClass19_0.<NotifyAppOfDRThreadRenderComplete>b__0(Object unused) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
PC-Test-develop-2.zip
Reproduction Steps
Ditto description
Expected behavior
No exception will be thrown
Actual behavior
Throw thread exception
Regression?
No response
Known Workarounds
No response
Impact
No response
Configuration
.NET Core Version: .NET 7.0.103 SDK Windows version: Version 22H2 (OS Build 19045.2546)
Other information
No response