gpt4 book ai didi

c# - 无法解释的 OverflowException 将表示屏幕坐标的 IntPtr 转换为 Int32

转载 作者:太空狗 更新时间:2023-10-29 23:51:47 25 4
gpt4 key购买 nike

我们有一个 WinForms AnyCPU 应用程序,其中供应商库控件偶尔会在运行多个监视器的 64 位用户机器上抛出以下异常:

System.OverflowException: Arithmetic operation resulted in an overflow.
at VendorLibraryName.VendorControl.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

我查看了供应商库控件的 WndProc 处理程序,唯一看起来可能会产生溢出的代码是这个(我的评论 - 这是反编译的):

switch (msg)
{
case 132: // NCHITTEST
case 672: // NCMOUSEHOVER

// Technically dangerous: convert IntPtr to Int32 in a 64-bit process.
// However, note that for these message codes,
// LParam represents a "packed" x and y screen-coordinate.
// Given my understanding of how this packing occurs, I can't think
// of how to construct an LParam such that it would overflow an Int32.
SomeMethod(x: (int)m.LParam & 65535, y: (int)m.LParam >> 16);

// More code...

这是转换和位旋转的实际 IL:

IL_0092: ldarg.1
IL_0093: call instance native int [System.Windows.Forms]System.Windows.Forms.Message::get_LParam()

// As far as I can tell, this is the only instruction on which overflow could occur
IL_0098: call int32 [mscorlib]System.IntPtr::op_Explicit(native int)

IL_009d: ldc.i4 65535
IL_00a2: and
IL_00a3: ldarg.1

// Same thing here...
IL_00a4: call instance native int [System.Windows.Forms]System.Windows.Forms.Message::get_LParam()
IL_00a9: call int32 [mscorlib]System.IntPtr::op_Explicit(native int)

IL_00ae: ldc.i4.s 16
IL_00b0: shr

显然,这个例程看起来容易出现溢出问题,因为在 64 位进程中存在 Message.LParam(IntPtr)到 Int32 的转换。事实上,这个例程是错误的,因为它没有正确处理负坐标 - 它看起来像是 Windows GET_X_LPARAM 和 GET_Y_PARAM 宏到 C# 的错误端口。

但是,我看不出如何为 NCHITTEST/NCMOUSEHOVER 构建 LParam,这实际上会溢出 Int32 的范围。 (我认为低 16 位由 有符号 16 位 X 坐标组成,其余位由符号扩展的 16 位 Y 坐标组成。请纠正我,如果我错了,因为这可能是一个严重的误解)。

我无法在我的开发箱上用许多不同的显示器配置和窗口位置重现异常。

什么屏幕坐标实际上会导致此处溢出?或者这个 block 是否有任何其他方式导致溢出?

最佳答案

我认为你的问题的关键在于“多显​​示器”。 Multiple monitors can lead to negative coordinates

来自 MSDN:

Important Do not use the LOWORD or HIWORD macros to extract the x- and y- coordinates of the cursor position because these macros return incorrect results on systems with multiple monitors. Systems with multiple monitors can have negative x- and y- coordinates, and LOWORD and HIWORD treat the coordinates as unsigned quantities.

由于在 CLR 上有符号数使用 2-complements notation 表示,负数表示为“大”无符号数(最高有效位为“1”的那些);例如,-1 是 1111....1。因此,转换为(带符号的)32 位整数时会发生溢出。

编辑:(免责声明:我没有多个显示器,所以需要一些猜测)简而言之:我的猜测是您必须生成负 y 坐标。

假设坐标为(x: -1, y: -1)

作为短数字:x: 0xFFFF, y: 0xFFFF

打包成32位数字:0xFFFF FFFF

现在,这就是涉及猜测的地方:IntPtr 没有符号扩展(你能用调试器试试吗?你需要一个负坐标)。因此它变成了:

0x0000 0000 FFFF FFFF

或 4294967295 太大而无法将其转换为 Int32。

一般来说,任何负 Y 坐标的形式都是

000.(32 Zeros)..001 ...(other 31 digits) .. 0 

并且应该提出问题(您是否尝试过将显示器一个放在另一个上面?)

关于c# - 无法解释的 OverflowException 将表示屏幕坐标的 IntPtr 转换为 Int32,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15129664/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com