Click here to Skip to main content
Licence CPOL
First Posted 9 Feb 2004
Views 51,680
Bookmarked 16 times

Moving a borderless window - an alternate way

By | 9 Feb 2004 | Article
How to move a borderless form by adding or removing the border part.

Introduction

The "traditional" way of moving a borderless VB form is to move the form when the mouse button is clicked down and the mouse moves. However, this flickers and is not as intuitive as it could be because "normal" windows only move when you drag the caption. The solution is to have your form borderless and have the caption bar appear when the mouse moves to the top part of the form and disappear again when the mouse moves of the caption bar...thus:

Option Explicit

Public Enum enSetWindowPos
    SWP_FRAMECHANGED = &H20 ' The frame changed: send WM_NCCALCSIZE
    SWP_HIDEWINDOW = &H80
    SWP_NOACTIVATE = &H10
    SWP_NOCOPYBITS = &H100
    SWP_NOMOVE = &H2
    SWP_NOOWNERZORDER = &H200 ' Don't do owner Z ordering
    SWP_NOREDRAW = &H8
    SWP_NOSIZE = &H1
    SWP_NOZORDER = &H4
    SWP_SHOWWINDOW = &H40
End Enum

Private Declare Function SetWindowPos Lib "user32" _
    (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, _
    ByVal x As Long, ByVal y As Long, ByVal cx As Long, _
    ByVal cy As Long, ByVal wFlags As Long) As Long
'\\ Get Window Long Indexes...
Public Enum enGetWindowLong
    GWL_EXSTYLE = (-20)
    GWL_HINSTANCE = (-6)
    GWL_HWNDPARENT = (-8)
    GWL_ID = (-12)
    GWL_STYLE = (-16)
    GWL_USERDATA = (-21)
    GWL_WNDPROC = (-4)
End Enum

Private Declare Function GetWindowLong Lib "user32" _
   Alias "GetWindowLongA" (ByVal hwnd As Long, _
   ByVal nIndex As Long) As Long
Private Declare Function SetWindowLong Lib "user32" _
   Alias "SetWindowLongA" (ByVal hwnd As Long, _
   ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

'\\ Window Style
Public Enum enWindowStyles
    WS_BORDER = &H800000
    WS_CAPTION = &HC00000
    WS_CHILD = &H40000000
    WS_CLIPCHILDREN = &H2000000
    WS_CLIPSIBLINGS = &H4000000
    WS_DISABLED = &H8000000
    WS_DLGFRAME = &H400000
    WS_EX_ACCEPTFILES = &H10&
    WS_EX_DLGMODALFRAME = &H1&
    WS_EX_NOPARENTNOTIFY = &H4&
    WS_EX_TOPMOST = &H8&
    WS_EX_TRANSPARENT = &H20&
    WS_EX_TOOLWINDOW = &H80&
    WS_GROUP = &H20000
    WS_HSCROLL = &H100000
    WS_MAXIMIZE = &H1000000
    WS_MAXIMIZEBOX = &H10000
    WS_MINIMIZE = &H20000000
    WS_MINIMIZEBOX = &H20000
    WS_OVERLAPPED = &H0&
    WS_POPUP = &H80000000
    WS_SYSMENU = &H80000
    WS_TABSTOP = &H10000
    WS_THICKFRAME = &H40000
    WS_VISIBLE = &H10000000
    WS_VSCROLL = &H200000
    '\\ New from 95/NT4 onwards
    WS_EX_MDICHILD = &H40
    WS_EX_WINDOWEDGE = &H100
    WS_EX_CLIENTEDGE = &H200
    WS_EX_CONTEXTHELP = &H400
    WS_EX_RIGHT = &H1000
    WS_EX_LEFT = &H0
    WS_EX_RTLREADING = &H2000
    WS_EX_LTRREADING = &H0
    WS_EX_LEFTSCROLLBAR = &H4000
    WS_EX_RIGHTSCROLLBAR = &H0
    WS_EX_CONTROLPARENT = &H10000
    WS_EX_STATICEDGE = &H20000
    WS_EX_APPWINDOW = &H40000
    WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE Or WS_EX_CLIENTEDGE)
    WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE Or _
                             WS_EX_TOOLWINDOW Or WS_EX_TOPMOST)
End Enum

Dim oldVal As FormBorderStyleConstants
Dim lCaptionHeight As Long
Public Enum SystemMetricsIndexes
    SM_CXSCREEN = 0
    SM_CYSCREEN = 1
    SM_CXVSCROLL = 2
    SM_CYHSCROLL = 3
    SM_CYCAPTION = 4
    SM_CXBORDER = 5
    SM_CYBORDER = 6
    SM_CXDLGFRAME = 7
    SM_CYDLGFRAME = 8
    SM_CYVTHUMB = 9
    SM_CXHTHUMB = 10
    SM_CXICON = 11
    SM_CYICON = 12
    SM_CXCURSOR = 13
    SM_CYCURSOR = 14
    SM_CYMENU = 15
    SM_CXFULLSCREEN = 16
    SM_CYFULLSCREEN = 17
    SM_CYKANJIWINDOW = 18
    SM_MOUSEPRESENT = 19
    SM_CYVSCROLL = 20
    SM_CXHSCROLL = 21
    SM_DEBUG = 22
    SM_SWAPBUTTON = 23
    SM_RESERVED1 = 24
    SM_RESERVED2 = 25
    SM_RESERVED3 = 26
    SM_RESERVED4 = 27
    SM_CXMIN = 28
    SM_CYMIN = 29
    SM_CXSIZE = 30
    SM_CYSIZE = 31
    SM_CXFRAME = 32
    SM_CYFRAME = 33
    SM_CXMINTRACK = 34
    SM_CYMINTRACK = 35
    SM_CXDOUBLECLK = 36
    SM_CYDOUBLECLK = 37
    SM_CXICONSPACING = 38
    SM_CYICONSPACING = 39
    SM_MENUDROPALIGNMENT = 40
    SM_PENWINDOWS = 41
    SM_DBCSENABLED = 42
    SM_CMOUSEBUTTONS = 43
    SM_SECURE = 44
    SM_CXEDGE = 45
    SM_CYEDGE = 46
    SM_CXMINSPACING = 47
    SM_CYMINSPACING = 48
    SM_CXSMICON = 49
    SM_CYSMICON = 50
    SM_CYSMCAPTION = 51
    SM_CXSMSIZE = 52
    SM_CYSMSIZE = 53
    SM_CXMENUSIZE = 54
    SM_CYMENUSIZE = 55
    SM_ARRANGE = 56
    SM_CXMINIMIZED = 57
    SM_CYMINIMIZED = 58
    SM_CXMAXTRACK = 59
    SM_CYMAXTRACK = 60
    SM_CXMAXIMIZED = 61
    SM_CYMAXIMIZED = 62
    SM_NETWORK = 63
    SM_CLEANBOOT = 67
    SM_CXDRAG = 68
    SM_CYDRAG = 69
    SM_SHOWSOUNDS = 70
    SM_CXMENUCHECK = 71 '/* Use instead of GetMenuCheckMarkDimensions()! */
    SM_CYMENUCHECK = 72
    SM_SLOWMACHINE = 73
    SM_MIDEASTENABLED = 74
    SM_MOUSEWHEELPRESENT = 75
    SM_XVIRTUALSCREEN = 76
    SM_YVIRTUALSCREEN = 77
    SM_CXVIRTUALSCREEN = 78
    SM_CYVIRTUALSCREEN = 79
    SM_CMONITORS = 80
    SM_SAMEDISPLAYFORMAT = 81
End Enum

Private Declare Function GetSystemMetrics Lib _
  "user32" (ByVal nIndex As SystemMetricsIndexes) As Long

Public Property Get RuntimeFormBorderStyle() As FormBorderStyleConstants

RuntimeFormBorderStyle = oldVal

End Property

Public Property Let RuntimeFormBorderStyle(ByVal newVal_
                                 As FormBorderStyleConstants)


If newVal <> oldVal Then
    Select Case newVal
    Case vbBSNone
        WindowStyle(WS_BORDER) = False
        WindowStyle(WS_CAPTION) = False
        WindowStyle(WS_DLGFRAME) = False
        WindowStyle(WS_EX_DLGMODALFRAME) = False
        WindowStyle(WS_EX_TOOLWINDOW) = False
        WindowStyle(WS_MAXIMIZEBOX) = Me.MaxButton
        WindowStyle(WS_MINIMIZEBOX) = Me.MinButton
        WindowStyle(WS_SYSMENU) = Me.ControlBox
        WindowStyle(WS_THICKFRAME) = False
        WindowStyle(WS_VSCROLL) = False
        WindowStyle(WS_EX_WINDOWEDGE) = False
        WindowStyle(WS_EX_CLIENTEDGE) = False
        WindowStyle(WS_EX_CONTROLPARENT) = False
        WindowStyle(WS_EX_STATICEDGE) = False
        WindowStyle(WS_EX_APPWINDOW) = False
        
    Case vbFixedDialog
        WindowStyle(WS_BORDER) = True
        WindowStyle(WS_CAPTION) = True
        WindowStyle(WS_DLGFRAME) = True
        WindowStyle(WS_EX_DLGMODALFRAME) = True
        WindowStyle(WS_EX_TOOLWINDOW) = False
        WindowStyle(WS_MAXIMIZEBOX) = Me.MaxButton
        WindowStyle(WS_MINIMIZEBOX) = Me.MinButton
        WindowStyle(WS_SYSMENU) = Me.ControlBox
        WindowStyle(WS_THICKFRAME) = False
        WindowStyle(WS_EX_WINDOWEDGE) = True
        WindowStyle(WS_EX_CLIENTEDGE) = False
        WindowStyle(WS_EX_STATICEDGE) = False
        WindowStyle(WS_EX_APPWINDOW) = Me.ShowInTaskbar

        
    Case vbFixedSingle
        WindowStyle(WS_BORDER) = True
        WindowStyle(WS_CAPTION) = True
        WindowStyle(WS_DLGFRAME) = True
        WindowStyle(WS_EX_DLGMODALFRAME) = False
        WindowStyle(WS_EX_TOOLWINDOW) = False
        WindowStyle(WS_MAXIMIZEBOX) = Me.MaxButton
        WindowStyle(WS_MINIMIZEBOX) = Me.MinButton
        WindowStyle(WS_SYSMENU) = Me.ControlBox
        WindowStyle(WS_THICKFRAME) = True
        WindowStyle(WS_EX_WINDOWEDGE) = True
        WindowStyle(WS_EX_CLIENTEDGE) = False
        WindowStyle(WS_EX_STATICEDGE) = False
        WindowStyle(WS_EX_APPWINDOW) = Me.ShowInTaskbar
        
    Case vbFixedToolWindow
        WindowStyle(WS_BORDER) = True
        WindowStyle(WS_CAPTION) = True
        WindowStyle(WS_DLGFRAME) = True
        WindowStyle(WS_EX_DLGMODALFRAME) = False
        WindowStyle(WS_EX_TOOLWINDOW) = True
        WindowStyle(WS_MAXIMIZEBOX) = Me.MaxButton
        WindowStyle(WS_MINIMIZEBOX) = Me.MinButton
        WindowStyle(WS_SYSMENU) = Me.ControlBox
        WindowStyle(WS_THICKFRAME) = False
        WindowStyle(WS_EX_WINDOWEDGE) = True
        WindowStyle(WS_EX_CLIENTEDGE) = False
        WindowStyle(WS_EX_STATICEDGE) = False
        WindowStyle(WS_EX_APPWINDOW) = Me.ShowInTaskbar
    
    Case vbSizable
        WindowStyle(WS_BORDER) = True
        WindowStyle(WS_CAPTION) = True
        WindowStyle(WS_DLGFRAME) = True
        WindowStyle(WS_EX_DLGMODALFRAME) = False
        WindowStyle(WS_EX_TOOLWINDOW) = False
        WindowStyle(WS_MAXIMIZEBOX) = Me.MaxButton
        WindowStyle(WS_MINIMIZEBOX) = Me.MinButton
        WindowStyle(WS_SYSMENU) = Me.ControlBox
        WindowStyle(WS_THICKFRAME) = True
        WindowStyle(WS_EX_WINDOWEDGE) = True
        WindowStyle(WS_EX_CLIENTEDGE) = False
        WindowStyle(WS_EX_APPWINDOW) = Me.ShowInTaskbar

        
    Case vbSizableToolWindow
        WindowStyle(WS_BORDER) = True
        WindowStyle(WS_CAPTION) = True
        WindowStyle(WS_DLGFRAME) = True
        WindowStyle(WS_EX_DLGMODALFRAME) = False
        WindowStyle(WS_EX_TOOLWINDOW) = True
        WindowStyle(WS_MAXIMIZEBOX) = Me.MaxButton
        WindowStyle(WS_MINIMIZEBOX) = Me.MinButton
        WindowStyle(WS_SYSMENU) = Me.ControlBox
        WindowStyle(WS_THICKFRAME) = False
        WindowStyle(WS_EX_WINDOWEDGE) = True
        WindowStyle(WS_EX_CLIENTEDGE) = False
        WindowStyle(WS_EX_STATICEDGE) = False
        WindowStyle(WS_EX_APPWINDOW) = Me.ShowInTaskbar
    
    End Select
    '\\ Refresh the window
    Call SetWindowPos(Me.hwnd, 0, 0, 0, 0, 0, _
          SWP_NOMOVE + SWP_NOSIZE + SWP_FRAMECHANGED)
    Me.Refresh
    oldVal = newVal
    
End If

End Property


Public Property Let WindowStyle(ByVal Index _
         As enWindowStyles, ByVal newVal As Boolean)

Dim gwIndex As enGetWindowLong
Dim lCurStyle As Long

If Index = WS_EX_ACCEPTFILES Or Index = WS_EX_APPWINDOW _
   Or Index = WS_EX_CLIENTEDGE Or Index = WS_EX_CONTEXTHELP _
   Or Index = WS_EX_CONTROLPARENT Or Index = WS_EX_DLGMODALFRAME _
   Or Index = WS_EX_LEFT Or Index = WS_EX_LEFTSCROLLBAR _
   Or Index = WS_EX_LTRREADING Or Index = WS_EX_MDICHILD _
   Or Index = WS_EX_NOPARENTNOTIFY Or Index = WS_EX_OVERLAPPEDWINDOW _
   Or Index = WS_EX_PALETTEWINDOW Or Index = WS_EX_RIGHT _
   Or Index = WS_EX_RIGHTSCROLLBAR Or Index = WS_EX_RTLREADING _
   Or Index = WS_EX_STATICEDGE Or Index = WS_EX_TOOLWINDOW _
   Or Index = WS_EX_TOPMOST Or Index = WS_EX_TRANSPARENT _
   Or Index = WS_EX_WINDOWEDGE Then
    '\\ Extended window style
    gwIndex = GWL_EXSTYLE
Else
    '\\ Standard window style
    gwIndex = GWL_STYLE
End If

lCurStyle = GetWindowLong(Me.hwnd, gwIndex)
If newVal Then
    lCurStyle = lCurStyle Or Index
Else
    lCurStyle = lCurStyle And (Not Index)
End If
Call SetWindowLong(Me.hwnd, gwIndex, lCurStyle)

End Property

Public Property Get WindowStyle(ByVal _
         Index As enWindowStyles) As Boolean

Dim gwIndex As enGetWindowLong
Dim lCurStyle As Long

If Index = WS_EX_ACCEPTFILES Or Index = WS_EX_APPWINDOW _
   Or Index = WS_EX_CLIENTEDGE Or Index = WS_EX_CONTEXTHELP _
   Or Index = WS_EX_CONTROLPARENT Or Index = WS_EX_DLGMODALFRAME _
   Or Index = WS_EX_LEFT Or Index = WS_EX_LEFTSCROLLBAR _
   Or Index = WS_EX_LTRREADING Or Index = WS_EX_MDICHILD _
   Or Index = WS_EX_NOPARENTNOTIFY Or Index = WS_EX_OVERLAPPEDWINDOW _
   Or Index = WS_EX_PALETTEWINDOW Or Index = WS_EX_RIGHT _
   Or Index = WS_EX_RIGHTSCROLLBAR Or Index = WS_EX_RTLREADING _
   Or Index = WS_EX_STATICEDGE Or Index = WS_EX_TOOLWINDOW _
   Or Index = WS_EX_TOPMOST Or Index = WS_EX_TRANSPARENT _
   Or Index = WS_EX_WINDOWEDGE Then
    '\\ Extended window style
    gwIndex = GWL_EXSTYLE
Else
    '\\ Standard window style
    gwIndex = GWL_STYLE
End If

lCurStyle = GetWindowLong(Me.hwnd, gwIndex)

WindowStyle = (lCurStyle Or Index) = lCurStyle

End Property
Private Sub Form_Load()

'\\ calculate the height of a caption bar
lCaptionHeight = (GetSystemMetrics(SM_CYCAPTION) _
                     + GetSystemMetrics(SM_CYBORDER))


oldVal = Me.BorderStyle
RuntimeFormBorderStyle = vbBSNone

End Sub

Private Sub Form_MouseMove(Button As Integer, _
          Shift As Integer, x As Single, y As Single)

If y < lCaptionHeight And Me.RuntimeFormBorderStyle = vbBSNone Then
    Me.RuntimeFormBorderStyle = vbSizable
Else
    Me.RuntimeFormBorderStyle = vbBSNone
End If

End Sub

Although this seems like a lot of code, it does make a more intuitive interface when it comes to borderless forms that can be moved and resized.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Duncan Edwards Jones

Software Developer (Senior)
JP Morgan
Ireland Ireland

Member

Follow on Twitter Follow on Twitter
C# / SQL Server developer
Microsoft MVP 2006, 2007
Visual Basic .NET

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralGood Attempt Pinmembersarthakganguly7:11 10 Mar '11  
GeneralSerious defects PinmemberMerrion8:08 30 Jun '04  
QuestionRe: Serious defects Pinmembershengh8:08 3 Apr '06  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120517.1 | Last Updated 10 Feb 2004
Article Copyright 2004 by Duncan Edwards Jones
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid