Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
367 views
in Technique[技术] by (71.8m points)

.net - Overcome OS Imposed Windows Form Minimum Size Limit

In an application I am developing, I need to be able to make a windows form smaller than the minimum height limit imposed by the operating system (36 px in Vista). I have tried intercepting WM_GETMINMAXINFO and providing my own information to override the OS limits, but this only works for the user. From code I can set the height to a value smaller than the limit, but my change only works until WM_WINDOWPOSCHANGED is posted to the message queue (which happens just after I change the height).

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

After much experimentation and trial-and-error, I have discovered a solution. I was overriding OnResize and conforming the size of the form to the ListBox in it (see my comment on John Saunders answer).

As I mentioned in my question, I noticed that the size of the form regresses after WM_WINDOWPOSCHANGED is sent. Further investigation revealed that the size regression actually begins when WM_WINDOWPOSCHANGING is sent.

WM_WINDOWPOSCHANGING is the sister message of WM_WINDOWPOSCHANGED which occurs before the window size actually changes. I don't know why, but for some reason WM_WINDOWPOSCHANGING blindly conforms the size of the form to the OS specified limits (apparently it does not query the window with WM_GETMINMAXINFO). Thus, I needed to intercept WM_WINDOWPOSCHANGING and override it with the size I really wanted.

This means that I am no longer conforming the size of the form using OnResize, but instead I am conforming the form size when I receive WM_WINDOWPOSCHANGING. This is even better than OnResize, because there is no associated flicker which occurs when the size is changed and then changed again when the size is conformed during OnResize.

Also, it is necessary to intercept and override WM_GETMINMAXINFO, otherwise, even intercepting WM_WINDOWPOSCHANGING will do you no good.

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;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...