WM_NCHITTEST, HTCAPTION and maximized window
I'm creating a custom drawn window by specifying border style NONE and custom processing of WM_NCHITTEST. I've defined some area as 'my window caption' and returning HTCAPTION result for WM_NCHITTEST in this area. When window is in normal state the behavior is expected by me. The window can be moved by dragging 'my window caption' and can be maximized by double clicking on it.
The problem is with the behavior of my window in maximized state. I still returning HTCAPTION result for WM_NCHITTEST in area of 'my window caption' and window can be restored to original size by double clicking on it again, but it's also still can be moved and this isn't what I want. What should I do to fix such behavior?
Fix:
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 method is responsible for evaluation of hit te开发者_StackOverflow社区st result on my custom drawn form. The implementation may look ugly, but it's pretty simple.
This is the code I use to prevent the window from being draggable when maximized.
// 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
What you describe is a bit weird - the maximized window can't usually be moved. In particular it occupies the whole desktop area, and AFAIK the system doesn't 'drag' it when its caption (i.e. - the area for which hit test was HT_CAPTION
) is dragged.
Can you please specify more info:
- How many desktops do you have (is it a multi-monitor system)?
- Do you respond on
WM_GETMINMAXINFO
to prevent your window from occupying the whole desktop area?
BTW I can imagine a workaround: when your window is maximized - don't return HT_CAPTION
on hit test. Instead you may return HT_CLIENT
, this will prevent your window from dragging.
However you'll have to manually implement "restoring" of your window when double-clicked. You should then respond on WM_LBUTTONDBLCLK
and restore your position manually.
From Windows 7 the expected and correct behaviour is that maximized windows that are dragged should be draggable. Try it with Notepad or any other windows app:- Windows that are docked or maximized will automatically revert to the "restore" size and be draggable.
精彩评论