שתף באמצעות


How to remove the white space at top of form

Question

Thursday, September 3, 2020 3:38 PM

Hi everybody,

I have problem with winform application and need to help.

I create a new form, i want hide the title bar but the form can be resize and move. I try set some below attributes but when run it, it always have a whitespace at top of the form

- formborderstyle = sizable

- control box = false

- me.text = ""

How can I remove it?

Please help me, thank you very much!

All replies (11)

Thursday, September 3, 2020 3:59 PM

Hi everybody,

I have problem with winform application and need to help.

I create a new form, i want hide the title bar but the form can be resize and move. I try set some below attributes but when run it, it always have a whitespace at top of the form

- formborderstyle = sizable

- control box = false

- me.text = ""

How can I remove it?

Please help me, thank you very much!

Hi

- formborderstyle = none

Regards Les, Livingston, Scotland


Thursday, September 3, 2020 4:35 PM

Thank you Les,

I tried it before.

But I cannot resize the form by hold on the edge and move mouse when set it.


Thursday, September 3, 2020 4:39 PM

Hi

That is correct. You need to take account of that if you use the Borders = None.

You would need to work to build your own resize and relocate for the Form.

It is much easier to live with the Form Title text and what you call white space. BTW why do you want to not have the title bar at the top of the Form?

Regards Les, Livingston, Scotland


Friday, September 4, 2020 6:45 AM

I create a new form, i want hide the title bar but the form can be resize and move. 

It is now done with DWM , mainly DwmExtendFrameIntoClientArea


Friday, September 4, 2020 9:41 AM

It look great! Could you share me more about how Can I do it? Ex: code example


Friday, September 4, 2020 11:06 AM | 1 vote

I adapted the MSDN C++ code from Custom Window Frame Using DWM  :

Imports System.Runtime.InteropServices

' Reference : https://docs.microsoft.com/en-us/windows/win32/dwm/customframe

Public Class Form1

    <StructLayout(LayoutKind.Sequential)>
    Public Structure MARGINS
        Public cxLeftWidth, cxRightWidth, cyTopHeight, cyBottomHeight As Integer
        Public Sub New(ByVal left As Integer, ByVal right As Integer, ByVal top As Integer, ByVal bottom As Integer)
            cxLeftWidth = left
            cyTopHeight = top
            cxRightWidth = right
            cyBottomHeight = bottom
        End Sub
    End Structure

    <DllImport("Dwmapi.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Public Shared Function DwmExtendFrameIntoClientArea(ByVal hwnd As IntPtr, ByRef margins As MARGINS) As Integer
    End Function

    <DllImport("Dwmapi.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Public Shared Function DwmIsCompositionEnabled(ByRef enabled As Boolean) As Integer
    End Function

    <DllImport("Dwmapi.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Public Shared Function DwmDefWindowProc(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByRef plResult As IntPtr) As Boolean
    End Function

    Public Const WM_CREATE As Integer = &H1
    Public Const WM_ACTIVATE As Integer = &H6
    Public Const WM_ACTIVATEAPP As Integer = &H1C
    Public Const WM_NCCALCSIZE As Integer = &H83
    Public Const WM_NCHITTEST As Integer = &H84
    Public Const WM_NCACTIVATE As Integer = &H86
    Public Const WM_RBUTTONDOWN As Integer = &H204
    Public Const WM_RBUTTONUP As Integer = &H205
    Public Const WM_NCLBUTTONDOWN As Integer = &HA1
    Public Const WM_NCLBUTTONUP As Integer = &HA2
    Public Const WM_NCRBUTTONDOWN As Integer = &HA4
    Public Const WM_NCRBUTTONUP As Integer = &HA5

    Public Const WS_OVERLAPPED As Integer = &H0, WS_POPUP As Integer = &H80000000, WS_CHILD As Integer = &H40000000, WS_MINIMIZE As Integer = &H20000000, WS_VISIBLE As Integer = &H10000000, WS_DISABLED As Integer = &H8000000, WS_CLIPSIBLINGS As Integer = &H4000000, WS_CLIPCHILDREN As Integer = &H2000000, WS_MAXIMIZE As Integer = &H1000000, WS_CAPTION As Integer = &HC00000, WS_BORDER As Integer = &H800000, WS_DLGFRAME As Integer = &H400000, WS_VSCROLL As Integer = &H200000, WS_HSCROLL As Integer = &H100000, WS_SYSMENU As Integer = &H80000, WS_THICKFRAME As Integer = &H40000, WS_TABSTOP As Integer = &H10000, WS_MINIMIZEBOX As Integer = &H20000, WS_MAXIMIZEBOX As Integer = &H10000
    Public Const WS_OVERLAPPEDWINDOW As Integer = WS_OVERLAPPED Or WS_CAPTION Or WS_SYSMENU Or WS_THICKFRAME Or WS_MINIMIZEBOX Or WS_MAXIMIZEBOX

    Public Const SWP_NOREDRAW As Integer = &H8, SWP_FRAMECHANGED As Integer = &H20, SWP_NOCOPYBITS As Integer = &H100, SWP_NOOWNERZORDER As Integer = &H200, SWP_NOSENDCHANGING As Integer = &H400, SWP_NOREPOSITION As Integer = SWP_NOOWNERZORDER, SWP_DEFERERASE As Integer = &H2000, SWP_ASYNCWINDOWPOS As Integer = &H4000

    <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Public Shared Function SetWindowPos(ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal x As Integer, ByVal y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal flags As Integer) As Boolean
    End Function

    <StructLayout(LayoutKind.Sequential)>
    Public Structure RECT
        Public left As Integer
        Public top As Integer
        Public right As Integer
        Public bottom As Integer
        Public Sub New(left As Integer, top As Integer, right As Integer, bottom As Integer)
            Me.left = left
            Me.top = top
            Me.right = right
            Me.bottom = bottom
        End Sub
    End Structure

    <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Public Shared Function GetWindowRect(hWnd As IntPtr, ByRef lpRect As RECT) As Boolean
    End Function

    <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Public Shared Function AdjustWindowRectEx(ByRef lpRect As RECT, ByVal dwStyle As Integer, ByVal bMenu As Boolean, ByVal dwExStyle As Integer) As Boolean
    End Function

    Public Const HTNOWHERE As Integer = 0, HTTRANSPARENT As Integer = -1, HTCAPTION As Integer = 2, HTSYSMENU As Integer = 3, HTGROWBOX As Integer = 4, HTMENU As Integer = 5,
    HTHSCROLL As Integer = 6, HTVSCROLL As Integer = 7, HTMINBUTTON As Integer = 8, HTMAXBUTTON As Integer = 9, HTLEFT As Integer = 10, HTRIGHT As Integer = 11, HTTOP As Integer = 12,
    HTTOPLEFT As Integer = 13, HTTOPRIGHT As Integer = 14, HTBOTTOM As Integer = 15, HTBOTTOMLEFT As Integer = 16, HTBOTTOMRIGHT As Integer = 17, HTBORDER As Integer = 18,
    HTCLOSE As Integer = 20, HTHELP As Integer = 21, HTMDIMAXBUTTON As Integer = 66, HTMDIMINBUTTON As Integer = 67, HTMDICLOSE As Integer = 68

    Public Structure NCCALCSIZE_PARAMS
        Public rect0 As RECT
        Public rect1 As RECT
        Public rect2 As RECT
        Public lppos As IntPtr
    End Structure

    Public Shared Function HIWORD(ByVal i As Integer) As Integer
        Return CShort(i >> 16)
    End Function

    Public Shared Function LOWORD(ByVal i As Integer) As Integer
        Return CShort(i And &HFFFF)
    End Function

    Public Shared Function GET_X_LPARAM(ByVal lParam As IntPtr) As Integer
        Return LOWORD(lParam.ToInt32())
    End Function

    Public Shared Function GET_Y_LPARAM(ByVal lParam As IntPtr) As Integer
        Return HIWORD(lParam.ToInt32())
    End Function

    <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Public Shared Function DestroyWindow(hWnd As IntPtr) As Boolean
    End Function

    Private Shared windowMargins As MARGINS
    Private Const TOPEXTENDWIDTH As Integer = 2
    Private Const LEFTEXTENDWIDTH As Integer = 2
    Private Const RIGHTEXTENDWIDTH As Integer = 2
    Private Const BOTTOMEXTENDWIDTH As Integer = 2

    Friend WithEvents Button1 As Button

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Button1 = New Button()
        Button1.Location = New Point(350, 6)
        Button1.Text = "Test Button"
        Button1.BackColor = Color.Transparent
        Button1.UseCompatibleTextRendering = True
        Me.Controls.Add(Button1)

        Me.BackColor = System.Drawing.Color.Black

        CenterToScreen()
    End Sub

    Protected Overrides Sub WndProc(ByRef m As Message)
        Dim fCallDWP As Boolean = True
        Dim fDwmEnabled As Boolean = False
        Dim lRet As Integer = 0
        Dim hr As Integer = 0
        ' Winproc worker for custom frame issues.
        hr = DwmIsCompositionEnabled(fDwmEnabled)
        If (hr = 0) Then
            lRet = CustomCaptionProc(m.HWnd, m.Msg, m.WParam, m.LParam, fCallDWP)
        End If
        ' Winproc worker for the rest of the application.
        If (fCallDWP) Then
            MyBase.WndProc(m)
        Else
            m.Result = CType(lRet, IntPtr)
        End If
    End Sub

    Private Shared Function CustomCaptionProc(ByVal hWnd As IntPtr, ByVal message As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByRef pfCallDWP As Boolean) As Integer
        Dim lRet As IntPtr = IntPtr.Zero
        Dim hr As Integer = 0
        Dim fCallDWP As Boolean = True

        fCallDWP = Not DwmDefWindowProc(hWnd, message, wParam, lParam, lRet)
        ' Handle window creation.
        If (message = WM_CREATE) Then
            Dim rcClient As RECT = New RECT()
            GetWindowRect(hWnd, rcClient)
            SetWindowPos(hWnd, IntPtr.Zero, rcClient.left, rcClient.top, (rcClient.right - rcClient.left), (rcClient.bottom - rcClient.top), SWP_FRAMECHANGED)

            fCallDWP = True
            lRet = IntPtr.Zero
        End If

        'If (message = WM_ACTIVATE Or message = WM_NCACTIVATE Or message = WM_ACTIVATEAPP) Then
        If (message = WM_ACTIVATE) Then
            windowMargins.cxLeftWidth = LEFTEXTENDWIDTH
            windowMargins.cxRightWidth = RIGHTEXTENDWIDTH
            windowMargins.cyBottomHeight = BOTTOMEXTENDWIDTH
            windowMargins.cyTopHeight = TOPEXTENDWIDTH
            DwmExtendFrameIntoClientArea(hWnd, windowMargins)

            fCallDWP = True
            lRet = IntPtr.Zero
        End If

        ' Handle the non-client size message.
        If ((message = WM_NCCALCSIZE) And (wParam = CType(1, IntPtr))) Then
            Dim pncsp As NCCALCSIZE_PARAMS = CType(Marshal.PtrToStructure(lParam, GetType(NCCALCSIZE_PARAMS)), NCCALCSIZE_PARAMS)
            pncsp.rect0.Top = pncsp.rect0.Top + 0
            pncsp.rect0.bottom = pncsp.rect0.bottom + 0
            pncsp.rect0.left = pncsp.rect0.left - 0
            pncsp.rect0.right = pncsp.rect0.right - 0
            Marshal.StructureToPtr(pncsp, lParam, False)
            ' No need to pass the message on to the DefWindowProc.
            lRet = IntPtr.Zero
            fCallDWP = False

        End If

        ' Handle hit testing in the NCA if not handled by DwmDefWindowProc.
        If ((message = WM_NCHITTEST) And (lRet = IntPtr.Zero)) Then
            lRet = HitTestNCA(hWnd, wParam, lParam)
            If (lRet <> CType(HTNOWHERE, IntPtr)) Then
                fCallDWP = False
            End If
        End If

        ' Close window on Right mouse button
        If (message = WM_NCRBUTTONDOWN) Then
            System.Threading.Thread.Sleep(200)
            DestroyWindow(hWnd)
        End If

        pfCallDWP = fCallDWP
        Return CType(lRet, Integer)
    End Function

    Private Shared Function HitTestNCA(ByVal hWnd As IntPtr, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
        ' Get the point coordinates for the hit test.
        Dim ptMouse As New Point(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))

        ' Get the window rectangle.
        Dim rcWindow As RECT = Nothing
        GetWindowRect(hWnd, rcWindow)

        ' Get the frame rectangle, adjusted for the style without a caption.
        Dim rcFrame As New RECT(0, 0, 0, 0)
        AdjustWindowRectEx(rcFrame, WS_OVERLAPPEDWINDOW And Not WS_CAPTION, False, 0)
        Dim uRow As UShort = 1
        Dim uCol As UShort = 1
        Dim fOnResizeBorder As Boolean = False

        ' Determine if the point is at the top or bottom of the window.
        If ptMouse.Y >= rcWindow.top AndAlso ptMouse.Y < rcWindow.top + TOPEXTENDWIDTH Then
            fOnResizeBorder = (ptMouse.Y < (rcWindow.top - rcFrame.top))
            uRow = 0
        ElseIf ptMouse.Y < rcWindow.bottom AndAlso ptMouse.Y >= rcWindow.bottom - BOTTOMEXTENDWIDTH Then
            uRow = 2
        End If

        ' Determine if the point is at the left or right of the window.
        If ptMouse.X >= rcWindow.left AndAlso ptMouse.X < rcWindow.left + LEFTEXTENDWIDTH Then
            uCol = 0 ' left side
        ElseIf ptMouse.X < rcWindow.right AndAlso ptMouse.X >= rcWindow.right - RIGHTEXTENDWIDTH Then
            uCol = 2 ' right side
        End If

        'Dim hitTests(,) As Integer = {
        '    {HTTOPLEFT, If(fOnResizeBorder, HTTOP, HTCAPTION), HTTOPRIGHT},
        '    {HTLEFT, HTNOWHERE, HTRIGHT},
        '    {HTBOTTOMLEFT, HTBOTTOM, HTBOTTOMRIGHT}
        '}
        Dim hitTests(,) As Integer = {
            {HTTOPLEFT, If(fOnResizeBorder, HTTOP, HTCAPTION), HTTOPRIGHT},
            {HTLEFT, HTCAPTION, HTRIGHT},
            {HTBOTTOMLEFT, HTBOTTOM, HTBOTTOMRIGHT}
        }

        Return New IntPtr(hitTests(uRow, uCol))
    End Function

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        MessageBox.Show("Button clicked", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub
End Class

Friday, September 4, 2020 4:32 PM

I tried it and it work well.

But have other problem: when I set window state = maximized some control nearby the edge of form will be go out of screen.


Friday, September 4, 2020 5:07 PM

I tried it and it work well.

But have other problem: when I set window state = maximized some control nearby the edge of form will be go out of screen.

You can increase borders when the window is maximized, in WM_NCCALCSIZE

For example, I add 6 to top when it is maximized :

If (IsZoomed(hWnd)) Then
    pncsp.rect0.top = pncsp.rect0.top + 6
    pncsp.rect0.bottom = pncsp.rect0.bottom + 0
    pncsp.rect0.left = pncsp.rect0.left - 0
    pncsp.rect0.right = pncsp.rect0.right - 0
Else
    pncsp.rect0.top = pncsp.rect0.top + 0
    pncsp.rect0.bottom = pncsp.rect0.bottom + 0
    pncsp.rect0.left = pncsp.rect0.left - 0
    pncsp.rect0.right = pncsp.rect0.right - 0
End If

with :

    <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Public Shared Function IsZoomed(hWnd As IntPtr) As Boolean
    End Function

Friday, September 4, 2020 11:16 PM

That look great! Let me try it. But let me know if you have any other notices when apply this one. Because my application already have many users. We must be carefully


Saturday, September 5, 2020 9:24 AM

The border size should be calculated from Windows System Metrics 

This works on my OS (Windows 10 - 1909) =>

Dim nBorderWidth = GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER)
Dim nBorderHeight = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER)

If (IsZoomed(hWnd)) Then
    pncsp.rect0.top = pncsp.rect0.top + nBorderHeight
    pncsp.rect0.bottom = pncsp.rect0.bottom - nBorderHeight
    pncsp.rect0.left = pncsp.rect0.left + nBorderWidth
    pncsp.rect0.right = pncsp.rect0.right - nBorderWidth
Else
    pncsp.rect0.top = pncsp.rect0.top + 0
    pncsp.rect0.bottom = pncsp.rect0.bottom + 0
    pncsp.rect0.left = pncsp.rect0.left - 0
    pncsp.rect0.right = pncsp.rect0.right - 0
End If

with :

    <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Public Shared Function GetSystemMetrics(nIndex As Integer) As Integer
    End Function
    
    Public Const SM_CXDLGFRAME = 7
    Public Const SM_CYDLGFRAME = 8
    Public Const SM_CXFIXEDFRAME = SM_CXDLGFRAME ' ;win40 name change
    Public Const SM_CYFIXEDFRAME = SM_CYDLGFRAME ' ;win40 name change
    Public Const SM_CXFRAME = 32
    Public Const SM_CYFRAME = 33
    Public Const SM_CXPADDEDBORDER = 92

I added OnPaint to colorize the borders in Red and, when maximized, I get (left part of the window, button at (1, 1)) =>


Monday, September 14, 2020 8:54 AM

Hi Lisa Bui,

Did you solve your problem? If your question has been answered then please click the "Mark as Answer" Link at the bottom of the correct post(s), so that it will help other members to find the solution quickly if they face a similar issue.

Best Regards,

Xingyu Zhao

MSDN Community Support
Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.