顶级窗口大小

时间:2014-06-03 10:40:25

标签: vb.net winforms winapi .net-4.0

  
      
  1. 为什么顶级窗口的最小尺寸限制为 2x2 像素?
  2.   
  3. 是否可以覆盖此约束,以便我可以将宽度/高度设置为< 2 即可。
  4.   

如果您运行示例应用程序并更改窗口大小,让我们说1,1您将看到大小限制为2,2

Application

示例应用

Public Class Form1

    Public Sub New()
        Me.InitializeComponent()
        Me.wnd = New Window With {.BackColor = Color.Red, .Bounds = New Rectangle(100, 100, 200, 200)}
        Me.grid = New PropertyGrid With {.Dock = DockStyle.Fill, .SelectedObject = Me.wnd, .TabIndex = 1}
        Me.btn = New Button With {.Text = "Set {width=1, height=1} using SetWindowPos.", .Dock = DockStyle.Top, .Height = 30, .TabIndex = 0}
        Me.Controls.AddRange({Me.grid, Me.btn})
    End Sub

    Private Sub HandleDisposed(sender As Object, e As EventArgs) Handles Me.Disposed
        If (Not Me.grid Is Nothing) Then Me.grid.Dispose()
        If (Not Me.wnd Is Nothing) Then Me.wnd.Dispose()
        If (Not Me.btn Is Nothing) Then Me.btn.Dispose()
    End Sub

    Private Sub HandleButtonClick(sender As Object, e As EventArgs) Handles btn.Click
        Window.SetWindowPos(New HandleRef(Me.wnd, Me.wnd.Handle), Nothing, 0, 0, 1, 1, (Window.SWP_DRAWFRAME Or Window.SWP_NOMOVE Or Window.SWP_NOZORDER Or Window.SWP_NOOWNERZORDER))
        Me.grid.Refresh()
    End Sub

    Private WithEvents wnd As Window
    Private WithEvents grid As PropertyGrid
    Private WithEvents btn As Button

    Public Class Window
        Inherits Control

        Public Sub New()
            Me.SetTopLevel(True)
        End Sub

        Protected Overrides Sub OnHandleCreated(e As System.EventArgs)
            Try
                If (IntPtr.Size = 4) Then
                    Dim style As Int32 = (GetWindowLong32(New HandleRef(Me, Me.Handle), GWL_STYLE) And Not (WS_CAPTION Or WS_THICKFRAME Or WS_MINIMIZE Or WS_MAXIMIZE Or WS_SYSMENU))
                    Dim exstyle As Int32 = (GetWindowLong32(New HandleRef(Me, Me.Handle), GWL_EXSTYLE) And Not (WS_EX_DLGMODALFRAME Or WS_EX_CLIENTEDGE Or WS_EX_STATICEDGE))
                    SetWindowLong32(New HandleRef(Me, Me.Handle), GWL_STYLE, New HandleRef(Nothing, New IntPtr(style)))
                    SetWindowLong32(New HandleRef(Me, Me.Handle), GWL_EXSTYLE, New HandleRef(Nothing, New IntPtr(exstyle)))
                Else
                    Dim style As Int64 = (GetWindowLong64(New HandleRef(Me, Me.Handle), GWL_STYLE) And Not CLng(WS_CAPTION Or WS_THICKFRAME Or WS_MINIMIZE Or WS_MAXIMIZE Or WS_SYSMENU))
                    Dim exstyle As Int64 = (GetWindowLong64(New HandleRef(Me, Me.Handle), GWL_EXSTYLE) And Not CLng(WS_EX_DLGMODALFRAME Or WS_EX_CLIENTEDGE Or WS_EX_STATICEDGE))
                    SetWindowLong64(New HandleRef(Me, Me.Handle), GWL_STYLE, New HandleRef(Nothing, New IntPtr(style)))
                    SetWindowLong64(New HandleRef(Me, Me.Handle), GWL_EXSTYLE, New HandleRef(Nothing, New IntPtr(exstyle)))
                End If
                SetWindowPos(New HandleRef(Me, Me.Handle), New HandleRef(Nothing, New IntPtr(HWND_TOPMOST)), 0, 0, 0, 0, (SWP_DRAWFRAME Or SWP_NOMOVE Or SWP_NOSIZE))
            Catch ex As Exception
                Throw ex
            Finally
                MyBase.OnHandleCreated(e)
            End Try
        End Sub

        <DllImport("user32.dll", EntryPoint:="GetWindowLong", CharSet:=CharSet.Auto)> _
        Friend Shared Function GetWindowLong32(ByVal hWnd As HandleRef, ByVal nIndex As Integer) As Int32
        End Function

        <DllImport("user32.dll", EntryPoint:="GetWindowLongPtr", CharSet:=CharSet.Auto)> _
        Friend Shared Function GetWindowLong64(ByVal hWnd As HandleRef, ByVal nIndex As Integer) As Int64
        End Function

        <DllImport("user32.dll", EntryPoint:="SetWindowLong", CharSet:=CharSet.Auto)> _
        Friend Shared Function SetWindowLong32(ByVal hWnd As HandleRef, ByVal nIndex As Integer, ByVal dwNewLong As HandleRef) As Int32
        End Function

        <DllImport("user32.dll", EntryPoint:="SetWindowLongPtr", CharSet:=CharSet.Auto)> _
        Friend Shared Function SetWindowLong64(ByVal hWnd As HandleRef, ByVal nIndex As Integer, ByVal dwNewLong As HandleRef) As Int64
        End Function

        <DllImport("user32.dll", CharSet:=CharSet.Auto, ExactSpelling:=True)> _
        Friend Shared Function SetWindowPos(ByVal hWnd As HandleRef, ByVal hWndInsertAfter As HandleRef, ByVal x As Integer, ByVal y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal flags As Integer) As Boolean
        End Function

        Friend Const GWL_EXSTYLE As Integer = -20
        Friend Const GWL_STYLE As Integer = -16
        Friend Const HWND_TOPMOST As Integer = -1
        Friend Const SWP_DRAWFRAME As Integer = &H20
        Friend Const SWP_NOMOVE As Integer = 2
        Friend Const SWP_NOSIZE As Integer = 1
        Friend Const SWP_NOZORDER As Integer = 4
        Friend Const SWP_NOOWNERZORDER As Integer = &H200
        Friend Const WS_CAPTION As Integer = &HC00000
        Friend Const WS_THICKFRAME As Integer = &H40000
        Friend Const WS_MAXIMIZE As Integer = &H1000000
        Friend Const WS_MINIMIZE As Integer = &H20000000
        Friend Const WS_SYSMENU As Integer = &H80000
        Friend Const WS_EX_DLGMODALFRAME As Integer = 1
        Friend Const WS_EX_CLIENTEDGE As Integer = &H200
        Friend Const WS_EX_STATICEDGE As Integer = &H20000

    End Class

End Class 

1 个答案:

答案 0 :(得分:4)

窗口的最小尺寸通常限制为最小尺寸,仍然允许用户可以访问系统菜单和字幕按钮。即使对于无边框窗户,也不完全合适。您可以通过在创建窗口后显式设置Size属性来使其更小,通常Load事件处理程序是您的第一个机会。或OnHandleCreated()。

但是,Windows仍然限制它为2x2,“为什么”是难以捉摸的。当然, 想知道的是如何解决它。您可以通过拦截WM_GETMINMAXINFO消息并降低最小磁道大小来实现此目的。演示方法的示例表单类:

Imports System.Runtime.InteropServices

Public Class Form1
    Protected Overrides Sub WndProc(ByRef m As Message)
        MyBase.WndProc(m)
        If m.Msg = WM_GETMINMAXINFO Then
            Dim mmi = DirectCast(Marshal.PtrToStructure(m.LParam, GetType(MINMAXINFO)), MINMAXINFO)
            mmi.ptMinTrackSize = New Point(0, 0)
            Marshal.StructureToPtr(mmi, m.LParam, False)
        End If
    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.Size = New Size(0, 0)
        MsgBox(Me.Size.ToString())
    End Sub

    Private Const WM_GETMINMAXINFO As Integer = &h24
    Private Structure MINMAXINFO
        Public ptReserved As Point
        Public ptMaxSize As Point
        Public ptMaxPosition As Point
        Public ptMinTrackSize As Point
        Public ptMaxTrackSize As Point
    End Structure
End Class

在Windows 8.1上测试。我不能保证它适用于所有Windows版本。它应该。