When I bump my mousewheel, my WPF application crashes sometimes, with an OverflowException. Here's the start of the stack trace:
at System.Windows.Shell.WindowChromeWorker._HandleNCHitTest(WM uMsg, IntPtr wParam, IntPtr lParam, Boolean& handled)
From that, I've traced it down to the WindowChrome - I can even reproduce it with just the WindowChrome. But it seems like it has to be fullscreen. What's going on here? Is there a workaround?
This is actually an issue in the class the stack trace points to. Microsoft has a bug in the WindowChromeWorker
that manifests in an OverflowException
.
I've only observed this with Logitech mice, but from what I've seen elsewhere, it may happen with other mice.
The only workarounds available are disallowing full-screen, and preventing the user from sending a message containing side-scroll information.
What I think is going on is this:
//Overflow gets inlined to here. (In System.Windows.Shell.WindowChromeWorker.cs)
var mousePosScreen = new Point(Utility.GET_X_LPARAM(lParam), Utility.GET_Y_LPARAM(lParam));
//Which calls this (In Standard.Utility)
public static int GET_X_LPARAM(IntPtr lParam)
{
return LOWORD(lParam.ToInt32());
}
//Unsafe cast and overflow happens here (In System.IntPtr)
public unsafe int ToInt32() {
#if WIN32
return (int)m_value;
#else
long l = (long)m_value;
return checked((int)l); //Overflow actually occurs and is thrown from here.
#endif
}
It seems like a bad assumption is made in Standard.Utility
that lParam
s always fit in 32 bits, and some mouse drivers violate that on 64-bit systems by writing there.
The reference source for WindowChromeWorker
is here.
The workaround that Ivan Golović included in a comment above needs to be in an answer so it can be spotted easily and in case the link goes dead.
Preprocess the message in a HookProc and mark it as handled if the conversion from lParam to int32 overflows.
protected override void OnSourceInitialized( EventArgs e )
{
base.OnSourceInitialized( e );
( (HwndSource)PresentationSource.FromVisual( this ) ).AddHook( HookProc );
}
private IntPtr HookProc( IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled )
{
if ( msg == 0x0084 /*WM_NCHITTEST*/ )
{
// This prevents a crash in WindowChromeWorker._HandleNCHitTest
try
{
lParam.ToInt32();
}
catch ( OverflowException )
{
handled = true;
}
}
return IntPtr.Zero;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With