I have a problem that when I handle the WM_NCCALCSIZE windows message in which I set my own client area of the form then the Form.ClientSize property no longer works properly. In other words resizing the form via Form.ClientSize property does not work properly. Here is an example form which demonstrates the behaviour.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace CustomFormTest
{
public class Form1 : Form
{
public Form1() {
Button button = new Button();
button.Dock = DockStyle.Fill;
button.Text = "Weird!";
button.Click += delegate(object sender, EventArgs e)
{
this.ClientSize = this.ClientSize;
};
this.Controls.Add(button);
}
protected override void WndProc(ref Message m) {
switch (m.Msg) {
case (int)Win32Api.WindowMessages.WM_NCCALCSIZE: // calculate client rectangle
this.CalculateClientRectangle(ref m);
break;
default:
base.WndProc(ref m);
break;
}
}
private void CalculateClientRectangle(ref Message m) {
if (m.WParam == Win32Api.WParamTrue) {
Win32Api.NCCALCSIZE_PARAMS ncParams = (Win32Api.NCCALCSIZE_PARAMS)m.GetLParam(typeof(Win32Api.NCCALCSIZE_PARAMS));
ncParams.ProposedRectangle = GetClientRectangle(ncParams.ProposedRectangle);
Marshal.StructureToPtr(ncParams, m.LParam, false);
} else {
Win32Api.RECT ncRect = (Win32Api.RECT)m.GetLParam(typeof(Win32Api.RECT));
ncRect = GetClientRectangle(ncRect);
Marshal.StructureToPtr(ncRect, m.LParam, false);
m.Result = IntPtr.Zero;
}
}
private Win32Api.RECT GetClientRectangle(Win32Api.RECT proposedRectangle) {
Win32Api.RECT realClientRectangle = proposedRectangle;
realClientRectangle.Top += 30;
realClientRectangle.Left += 10;
realClientRectangle.Right -= 10;
realClientRectangle.Bottom -= 10;
return realClientRectangle;
}
private sealed class Win32Api
{
public enum WindowMessages
{
WM_NCCALCSIZE = 0x0083,
}
public static readonly IntPtr WParamTrue = new IntPtr(1);
public static readonly IntPtr WParamFalse = IntPtr.Zero;
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public RECT(int left, int top, int right, int bottom) {
this.Left = left;
this.Top = top;
this.Right = right;
this.Bottom = bottom;
}
public RECT(Rectangle rect) {
this.Left = rect.Left;
this.Top = rect.Top;
this.Right = rect.Right;
this.Bottom = rect.Bottom;
}
public Rectangle Rectangle {
get { return new Rectangle(this.Left, this.Top, this.Right - this.Left, this.Bottom - this.Top); }
}
}
[StructLayout(LayoutKind.Sequential)]
public struct NCCALCSIZE_PARAMS
{
public RECT ProposedRectangle;
public RECT BeforeMoveRectangle;
public RECT BeforeMoveClientRectangle;
public WINDOWPOS lpPos;
}
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPOS
{
public IntPtr hwnd;
public IntPtr hWndInsertAfter;
public int x;
public int y;
public int cx;
public int cy;
public uint flags;
}
}
}
}

Problems with handling WM_NCCALCSIZE and setting Form.ClientSize property
DaveJohnson
DataBound
I am surprised because the controls inside the form accurately position themselves according to the new client rectangle (Dock) without any need for me to do anything.
I am intercepting the message because I do my own painting of the non-client area of the form (my own borders and titlebar).
From what I have seen it seems that the form calculates it's non-client area based on the titlebar size and border size of the form. I can not find a way to notify the framework that I have changed the non-client area nor can I determine how the framework knows about it in the first place.
kadonk
Hi,