Преодолеть ограничение на размер формы Windows для Windows - PullRequest
8 голосов
/ 14 июня 2009

В приложении, которое я разрабатываю, мне нужно иметь возможность сделать форму окна меньше, чем минимальный предел высоты, установленный операционной системой (36 пикселей в Vista). Я попытался перехватить WM_GETMINMAXINFO и предоставить свою собственную информацию для переопределения ограничений ОС, но это работает только для пользователя. Из кода я могу установить высоту на значение меньше предела, но мое изменение работает только до тех пор, пока WM_WINDOWPOSCHANGED не будет опубликовано в очереди сообщений (что происходит сразу после того, как я изменю высоту).

Ответы [ 6 ]

14 голосов
/ 15 июня 2009

После долгих экспериментов и проб и ошибок я нашел решение. Я переопределял OnResize и соответствовал размеру формы списку в нем (см. Мой комментарий к ответу Джона Сондерса).

Как я уже упоминал в своем вопросе, я заметил, что размер формы уменьшается после отправки WM_WINDOWPOSCHANGED. Дальнейшее расследование показало, что регрессия размера действительно начинается при отправке WM_WINDOWPOSCHANGING.

WM_WINDOWPOSCHANGING - это родственное сообщение WM_WINDOWPOSCHANGED, которое происходит до того, как размер окна действительно изменится. Я не знаю почему, но по какой-то причине WM_WINDOWPOSCHANGING вслепую согласовывает размер формы с указанными в ОС ограничениями (по-видимому, он не запрашивает окно с 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;
}
4 голосов
/ 30 ноября 2012

Алексей был так близко!

    protected override void SetBoundsCore(int x,int y,int width, int height,BoundsSpecified specified)
    {
        base.SetBoundsCore(x, y, this.MinimumSize.Width, this.MinimumSize.Height, specified);
    }

Сделал трюк для меня. Я установил минимальный размер формы в соответствии с тем, каким должен быть фактический размер формы.

В моем проекте это все, что мне нужно сделать, чтобы форма стала крошечной, возможно, потому, что установка минимального размера вызывает SetBoundsCore или, возможно, я делаю что-то еще, что вызывает ее; в этом случае, я думаю, вы должны каким-то образом вызвать SetBoundsCore самостоятельно.

1 голос
/ 11 ноября 2011

При игре с минимальным размером формы я заметил, что минимальный размер формы ограничен системным минимальным размером формы в Form.SetBoundsCore (...). Когда я разбираю IL, я обнаружил, что этот метод .Net всегда корректирует то, что вы ему даете (ширину и высоту), в SystemInformation.MinimumWindowSize, если они меньше, и у формы нет родителя, а ее FormBorderStyle - FixedSingle, Fixed3D , FixedDialog или Sizable.

Самым простым решением этой проблемы является не обработка WM_WINDOWPOSCHANGING, а просто установка FormBorderStyle = System.Windows.Forms.FormBorderStyle.None в конструкторе формы.

1 голос
/ 23 июля 2011

Я бы хотел отдать Заку больше +1, это здорово и спасло мой бекон. Для будущих читателей, вот перевод VB кода Зака:

Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Imports System.Drawing

Public Class MyForm

    ' Ghastly hack to allow the form to be narrower than the widows-imposed limit (about 132 in WIndows 7)
    ' Thanks to /767495/preodolet-ogranichenie-na-razmer-formy-windows-dlya-windows

    Private Const WM_WINDOWPOSCHANGING As Integer = &H46
    Private Const WM_GETMINMAXINFO As Integer = &H24
    Protected Overrides Sub WndProc(ByRef m As Message)
        If m.Msg = WM_WINDOWPOSCHANGING Then
            Dim windowPos As WindowPos = CType(m.GetLParam(GetType(WindowPos)), WindowPos)

            ' Make changes to windowPos

            ' Then marshal the changes back to the message
            Marshal.StructureToPtr(windowPos, m.LParam, True)
        End If

        MyBase.WndProc(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 Then
            Dim minMaxInfo As MINMAXINFO = DirectCast(m.GetLParam(GetType(MINMAXINFO)), MINMAXINFO)
            minMaxInfo.ptMinTrackSize.X = Me.MinimumSize.Width
            minMaxInfo.ptMinTrackSize.Y = Me.MinimumSize.Height
            Marshal.StructureToPtr(minMaxInfo, m.LParam, True)
        End If
    End Sub

    Private Structure WindowPos
        Public hwnd As IntPtr
        Public hwndInsertAfter As IntPtr
        Public x As Integer
        Public y As Integer
        Public width As Integer
        Public height As Integer
        Public flags As UInteger
    End Structure
    <StructLayout(LayoutKind.Sequential)> _
    Private Structure MINMAXINFO
        Dim ptReserved As Point
        Dim ptMaxSize As Point
        Dim ptMaxPosition As Point
        Dim ptMinTrackSize As Point
        Dim ptMaxTrackSize As Point
    End Structure

    .... rest of the form

End Class
0 голосов
/ 23 августа 2016

Я последовал ответу Зака, и он почти решил мою проблему. Однако в настройке с двумя мониторами форма исчезла, когда она была развернута на втором экране. По какой-то причине Windows расположила форму за пределами видимой области. Добавление теста для основного экрана решило эту проблему для меня:

if (m.Msg == (int)CWinApi.Messages.WM_GETMINMAXINFO)
{
    if (this.FormBorderStyle == System.Windows.Forms.FormBorderStyle.None)
    {
        Screen screen = Screen.FromControl(this);

        if (screen.Primary)
        {
            CWinApi.MINMAXINFO minMaxInfo = (CWinApi.MINMAXINFO)m.GetLParam(typeof(CWinApi.MINMAXINFO));

            minMaxInfo.ptMaxSize.x = screen.WorkingArea.Size.Width;
            minMaxInfo.ptMaxSize.y = screen.WorkingArea.Size.Height;
            minMaxInfo.ptMaxPosition.x = screen.WorkingArea.X;
            minMaxInfo.ptMaxPosition.y = screen.WorkingArea.Y;

            System.Runtime.InteropServices.Marshal.StructureToPtr(minMaxInfo, m.LParam, true);
        }
    }
}
0 голосов
/ 15 июня 2009

Вы имеете в виду, кроме использования другой ОС?

Как насчет "Не используйте форму"? Насколько велика эта вещь, которую вы должны отобразить? Пиксель? Требуется ли полная функциональность Windows Forms?

Теперь я точно не знаю, как это сделать, но это может быть началом для вас - подумайте за пределами (ограничивающей) рамки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...