克服操作系统强加的Windows窗体最小大小限制

Zac*_*son 9 .net minimum-size winforms

在我正在开发的应用程序中,我需要能够使窗口形式小于操作系统施加的最小高度限制(在Vista中为36像素).我试图拦截WM_GETMINMAXINFO并提供我自己的信息来覆盖操作系统限制,但这仅适用于用户.从代码我可以将高度设置为小于限制的值,但我的更改只有在WM_WINDOWPOSCHANGED发布到消息队列(这是在我更改高度之后发生)之后才有效.

Zac*_*son 15

经过大量的实验和反复试验,我发现了一个解决方案.我重写了OnResize,并将表单的大小与其中的ListBox一致(请参阅我对John Saunders的评论).

正如我在我的问题中提到的,我注意到在发送WM_WINDOWPOSCHANGED之后表单的大小会消退.进一步的调查显示,当发送WM_WINDOWPOSCHANGING时,大小回归实际上开始了.

WM_WINDOWPOSCHANGING是WM_WINDOWPOSCHANGED的姐妹消息,它在窗口大小实际发生变化之前发生.我不知道为什么,但由于某种原因,WM_WINDOWPOSCHANGING盲目地将窗体的大小与OS指定的限制一致(显然它不会使用WM_GETMINMAXINFO查询窗口).因此,我需要拦截WM_WINDOWPOSCHANGING并用我真正想要的大小覆盖它.

这意味着我不再使用OnResize来符合表单的大小,而是在接收WM_WINDOWPOSCHANGING时符合表单大小.这甚至比OnResize更好,因为在更改大小时没有相关的闪烁,然后在OnResize期间符合大小时再次更改.

此外,有必要拦截和覆盖WM_GETMINMAXINFO,否则,即使拦截WM_WINDOWPOSCHANGING也没有用.

using System.Runtime.InteropServices;

private const int WM_WINDOWPOSCHANGING = 0x0046;
private const int WM_GETMINMAXINFO = 0x0024;

protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_WINDOWPOSCHANGING)
    {
        WindowPos windowPos = (WindowPos)m.GetLParam(typeof(WindowPos));

        // Make changes to windowPos

        // Then marshal the changes back to the message
        Marshal.StructureToPtr(windowPos, m.LParam, true);
    }

    base.WndProc(ref m);

    // Make changes to WM_GETMINMAXINFO after it has been handled by the underlying
    // WndProc, so we only need to repopulate the minimum size constraints
    if (m.Msg == WM_GETMINMAXINFO)
    {
        MinMaxInfo minMaxInfo = (MinMaxInfo)m.GetLParam(typeof(MinMaxInfo));
        minMaxInfo.ptMinTrackSize.x = this.MinimumSize.Width;
        minMaxInfo.ptMinTrackSize.y = this.MinimumSize.Height;
        Marshal.StructureToPtr(minMaxInfo, m.LParam, true);
   }
}

struct WindowPos
{
     public IntPtr hwnd;
     public IntPtr hwndInsertAfter;
     public int x;
     public int y;
     public int width;
     public int height;
     public uint flags;
}

struct POINT
{
    public int x;
    public int y;
}

struct MinMaxInfo
{
    public POINT ptReserved;
    public POINT ptMaxSize;
    public POINT ptMaxPosition;
    public POINT ptMinTrackSize;
    public POINT ptMaxTrackSize;
}
Run Code Online (Sandbox Code Playgroud)