在 WPF 获取鼠标当前坐标的时候,可能会得到一个异常:System.ComponentModel.Win32Exception:“无效的窗口句柄。”
。
本文解释此异常的原因和解决方法。
异常
获取鼠标当前相对于元素 element
的坐标的代码:
1
var point = Mouse.GetPosition(element);
或者,还有其他的代码:
1
2
var point1 = e.PointFromScreen(new Point());
var point2 = e.PointToScreen(new Point());
如果在按下窗口关闭按钮的时候调用以上代码,则会引发异常:
1
2
3
System.ComponentModel.Win32Exception (0x80004005): 无效的窗口句柄。
at Point MS.Internal.PointUtil.ClientToScreen(Point pointClient, PresentationSource presentationSource)
at Point System.Windows.Input.MouseDevice.GetScreenPositionFromSystem()
原因
将窗口上的点转换到控件上的点的方法是这样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/// <summary>
/// Convert a point from "client" coordinate space of a window into
/// the coordinate space of the screen.
/// </summary>
/// <SecurityNote>
/// SecurityCritical: This code causes eleveation to unmanaged code via call to GetWindowLong
/// SecurityTreatAsSafe: This data is ok to give out
/// validate all code paths that lead to this.
/// </SecurityNote>
[SecurityCritical, SecurityTreatAsSafe]
public static Point ClientToScreen(Point pointClient, PresentationSource presentationSource)
{
// For now we only know how to use HwndSource.
HwndSource inputSource = presentationSource as HwndSource;
if(inputSource == null)
{
return pointClient;
}
HandleRef handleRef = new HandleRef(inputSource, inputSource.CriticalHandle);
NativeMethods.POINT ptClient = FromPoint(pointClient);
NativeMethods.POINT ptClientRTLAdjusted = AdjustForRightToLeft(ptClient, handleRef);
UnsafeNativeMethods.ClientToScreen(handleRef, ptClientRTLAdjusted);
return ToPoint(ptClientRTLAdjusted);
}
最关键的是 UnsafeNativeMethods.ClientToScreen
,此方法要求窗口句柄依然有效,然而此时窗口已经关闭,句柄已经销毁。
解决
本文会经常更新,请阅读原文: https://blog.walterlv.com/post/win32exception.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected]) 。