WM_NCHITTEST,HTCAPTION和最大化窗口

时间:2010-05-10 14:36:18

标签: winforms winapi

我正在通过指定边框样式NONE和WM_NCHITTEST的自定义处理来创建自定义绘制窗口。我已将某个区域定义为“我的窗口标题”,并在此区域返回WM_NCHITTEST的HTCAPTION结果。当窗口处于正常状态时,我的行为是预期的。可以通过拖动“我的窗口标题”来移动窗口,并且可以通过双击来最大化窗口。

问题在于窗口的行为处于最大化状态。我仍然在'我的窗口标题'区域返回WM_NCHITTEST的HTCAPTION结果,并且可以通过再次双击将窗口恢复到原始大小,但它仍然可以移动,这不是我想要的。我该怎么做才能解决这种问题?


修正:

    protected override void WndProc(ref Message m)
    {
        if(m.Msg == WM_NCHITTEST)
        {
            Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
            pos = this.PointToClient(pos);
            if(HitTestForNC(ref m, pos))
            {
                if(WindowState != FormWindowState.Maximized || m.Result != (IntPtr)HitTestValues.HTCAPTION)
                {
                    return;
                }
            }
        }
        else if(m.Msg == WM_GETMINMAXINFO)
        {
            base.WndProc(ref m);
            MinMaxInfo mmi = (MinMaxInfo)Marshal.PtrToStructure(m.LParam, typeof(MinMaxInfo));
            mmi.ptMaxPosition = Screen.FromControl(this).WorkingArea.Location;
            mmi.ptMaxSize = Screen.FromControl(this).WorkingArea.Size;
            Marshal.StructureToPtr(mmi, m.LParam, false);
            return;
        }
        base.WndProc(ref m);
    }

    protected override void OnMouseDoubleClick(MouseEventArgs e)
    {
        if(e.Button == MouseButtons.Left)
        {
            Message m = new Message();
            if(HitTestForNC(ref m, e.Location))
            {
                if(m.Result == (IntPtr)HitTestValues.HTCAPTION && WindowState == FormWindowState.Maximized)
                {
                    WindowState = FormWindowState.Normal;
                    return;
                }
            }
        }
        base.OnMouseDoubleClick(e);
    }

HitTestForNC方法负责评估我的自定义绘制表单上的命中测试结果。实现可能看起来很难看,但它很简单。

3 个答案:

答案 0 :(得分:3)

这是我用来防止窗口在最大化时可拖动的代码。

// Indicates the form caption
Const HT_CAPTION As Integer = &H2
// Windows Message Non Client Button Down
Const WM_NCLBUTTONDOWN As Integer = &HA1

//Routine to implement the 'Drag Window' functionality.
Private Sub frm_Drag(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
  Handles Me.MouseDown

  //Do not move the form if it is maximized.
  If Not Me.WindowState = FormWindowState.Maximized Then
     If e.Button = Windows.Forms.MouseButtons.Left Then
        sender.Capture = False
        Me.WndProc(Message.Create(Me.Handle, WM_NCLBUTTONDOWN, _
        CType(HT_CAPTION, IntPtr), IntPtr.Zero))
     End If
  End If
End Sub

答案 1 :(得分:2)

您描述的内容有点奇怪 - 通常无法移动最大化的窗口。特别是它占据整个桌面区域,而AFAIK系统在其标题(即 - 命中测试的区域为HT_CAPTION)被拖动时不会“拖动”它。

请指出更多信息:

  1. 您有多少个桌面(它是多监视器系统)?
  2. 您是否回复WM_GETMINMAXINFO以阻止您的窗口占据整个桌面区域?
  3. BTW我可以想象一个解决方法:当你的窗口最大化时 - 不要在命中测试时返回HT_CAPTION。相反,您可以返回HT_CLIENT,这会阻止您的窗口拖动。

    但是,双击时,您必须手动实现窗口的“恢复”。然后,您应该在WM_LBUTTONDBLCLK上回复并手动恢复您的职位。

答案 2 :(得分:2)

从Windows 7开始,预期和正确的行为是拖动的最大化窗口应可拖动。使用记事本或任何其他Windows应用程序尝试: - 停靠或最大化的Windows将自动恢复为“恢复”大小并可拖动。