获取WM_NCHITTEST消息的坐标?

时间:2010-12-17 14:12:16

标签: c# winforms wndproc

如何在C#代码中获取WM_NCHITTEST消息的坐标?
我希望得到最快的方式,因为性能是必需的。

3 个答案:

答案 0 :(得分:13)

直到今天早上,我已经与Thomas Levesques的回答100%同意了,我从msdn中提取了相同的信息,而且代码(貌似)工作得很好。但是,有一种情况会让你感到困惑,我今天下午花了三个小时才找到原因。

我的症状是,在我的一台开发机器上,在VS2010 IDE中,我的控件只能通过点击我在某个y位置点击它来选择。窗体顶部的非常小的控件无法通过单击进行选择。不可点击的区域大小看起来与Windows窗体设计器周围的IDE大小相同,所以起初我以为我有一些奇怪的鲜为人知的DesignMode问题。最令人困惑的是,完全相同的项目(在不同的机器上检出TFS)不会显示此行为。

以下是发生的事情:

考虑一下你有一个双显示器设置,如图所示(抱歉德国截图,我手头没有英文操作系统):

Double monitor setup

如您所见,监视器2的左上角位于坐标(1280,-256)处。如果您使用上面显示的解决方案,如果鼠标确实在-30,您将获得65505之类的y。这是因为这些位置存储为LParam的高阶和低阶WORD。因此,执行(lParam.ToInt32() & 0xFFFF0000) >> 16将为y位置提供正确的位。但是,将此转换为int会产生65505,因为您正在转换为错误的数据类型。

解决方案:

int x = (short)(lParam.ToInt32() & 0x0000FFFF);
int y = (short)((lParam.ToInt32() & 0xFFFF0000) >> 16);
Point pos = new Point(x, y);

投射到short会为您提供正确的位置值。我也投了x,因为你可以安排你的显示器,使第二个显示器留在主显示器上,因此x位置会有同样的问题。

我最近发现Point的一个构造函数将为你工作。所以,简短版本是:

Point pos = new Point(lParam.ToInt32());

答案 1 :(得分:11)

来自MSDN:

  

<强>的wParam
    不使用此参数。

     

<强> lParam的
  低位字指定   光标的x坐标。该   坐标是相对于   屏幕的左上角。
  高阶词指定了   光标的y坐标。该   坐标是相对于   屏幕的左上角。

所以你只需要从消息lParam中提取低阶和高阶词:

int x = lParam.ToInt32() & 0x0000FFFF;
int y = (int)((lParam.ToInt32() & 0xFFFF0000) >> 16)
Point pos = new Point(x, y);

我不会太担心性能,因为这些操作只是位级算术......

请注意,这些坐标是相对于屏幕的。如果您想要相对于控件(或表单)的坐标,可以使用PointToClient方法:

Point relativePos = theControl.PointToClient(pos);

答案 2 :(得分:8)

我知道这个问题已经回答了,但除了......

Point p = new Point(m.LParam.ToInt32());

System.Drawing.Point现在有一个专门设计用于接受这个确切值的构造函数。严格地说,我认为这可能是最简单的方式。

说实话,我不知道在发布其他答案时这个构造函数是否存在。

所有人都说,这可能不是更快,因为takrl的答案几乎肯定是前面提到的构造函数在内部的作用。