Click here to Skip to main content
11,933,854 members (56,654 online)
Click here to Skip to main content
Add your own
alternative version


67 bookmarked

Metro UI (Zune like) Interface (form)

, 26 Dec 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
How to create a Zune UI Borderless form in VB.NET


The future of Windows Interfaces is probably the Zune-like ones, with a borderless form and some controls inside of it. The problem is: if you're using WindowsForm, creating that borderless form with shadows and resizing stuff isn't as easy as it seems. This article will show you how to create those forms using a bit of DWM and some other Windows APIs.


To create the desired effect, we will need to extend the non-client area, cut off the Aero's glass from the Window, and handle some resizing and moving events. Luckily, José Mendez has shown us in his article how to do some of these things.

Of course, "the non-client area trick" only works if Aero is turned on. But I've handled it on my code. Let's take a look:

Using the Code

I've tried to create a Form for you to inherit it, making it easy for you to use my code. Unluckily, the resize thing must be changed if you want to extend that functionality into a panel or some other control. So I preferred to give my code for you to add it inside your own form.

Also, you need to have a form's text and set the FormBorderStyle property to "Sizable" to make everything work properly. DWM can't extend the glass and the client-area if it can't find one, so removing your form's text + controlbox or setting the FormBorderStyle to anything else other than "Sizable" would bring you some unexpected bugs. Keep that it mind.

First, you'll need to add both classes DWM.vb and WinApi.vb to your project. Then, use this code to give your form a Zune (Metro) like shape:

#Region "Fields"
    Private dwmMargins As Dwm.MARGINS
    Private _marginOk As Boolean
    Private _aeroEnabled As Boolean = False
#End Region
#Region "Ctor"
    Public Sub New()
        SetStyle(ControlStyles.ResizeRedraw, True)


        DoubleBuffered = True

    End Sub
#End Region
#Region "Props"
    Public ReadOnly Property AeroEnabled() As Boolean
            Return _aeroEnabled
        End Get
    End Property
#End Region
#Region "Methods"
    Public Shared Function LoWord(ByVal dwValue As Integer) As Integer
        Return dwValue And &HFFFF
    End Function
    ''' <summary>
    ''' Equivalent to the HiWord C Macro
    ''' </summary>
    ''' <param name="dwValue"></param>
    ''' <returns></returns>
    Public Shared Function HiWord(ByVal dwValue As Integer) As Integer
        Return (dwValue >> 16) And &HFFFF
    End Function
#End Region

    Private Sub Form1_Activated(ByVal sender As Object, _
	ByVal e As System.EventArgs) Handles Me.Activated
        Dwm.DwmExtendFrameIntoClientArea(Me.Handle, dwmMargins)
    End Sub

    Protected Overloads Overrides Sub WndProc(ByRef m As Message)
        Dim WM_NCCALCSIZE As Integer = &H83
        Dim WM_NCHITTEST As Integer = &H84
        Dim result As IntPtr

        Dim dwmHandled As Integer = Dwm.DwmDefWindowProc_
		(m.HWnd, m.Msg, m.WParam, m.LParam, result)

        If dwmHandled = 1 Then
            m.Result = result
            Exit Sub
        End If

        If m.Msg = WM_NCCALCSIZE AndAlso CInt(m.WParam) = 1 Then
            Dim nccsp As NCCALCSIZE_PARAMS = _
              DirectCast(Marshal.PtrToStructure(m.LParam, _

            ' Adjust (shrink) the client rectangle to accommodate the border:
            nccsp.rect0.Top += 0
            nccsp.rect0.Bottom += 0
            nccsp.rect0.Left += 0
            nccsp.rect0.Right += 0

            If Not _marginOk Then
                'Set what client area would be for passing to 
                'DwmExtendIntoClientArea. Also remember that at least 
                'one of these values NEEDS TO BE > 1, else it won't work.
                dwmMargins.cyTopHeight = 0
                dwmMargins.cxLeftWidth = 0
                dwmMargins.cyBottomHeight = 1
                dwmMargins.cxRightWidth = 0
                _marginOk = True
            End If

            Marshal.StructureToPtr(nccsp, m.LParam, False)

            m.Result = IntPtr.Zero
        ElseIf m.Msg = WM_NCHITTEST AndAlso CInt(m.Result) = 0 Then
            m.Result = HitTestNCA(m.HWnd, m.WParam, m.LParam)
        End If
    End Sub

    Private Function HitTestNCA(ByVal hwnd As IntPtr, ByVal wparam _
                                      As IntPtr, ByVal lparam As IntPtr) As IntPtr
        Dim HTNOWHERE As Integer = 0
        Dim HTCLIENT As Integer = 1
        Dim HTCAPTION As Integer = 2
        Dim HTGROWBOX As Integer = 4
        Dim HTSIZE As Integer = HTGROWBOX
        Dim HTMINBUTTON As Integer = 8
        Dim HTMAXBUTTON As Integer = 9
        Dim HTLEFT As Integer = 10
        Dim HTRIGHT As Integer = 11
        Dim HTTOP As Integer = 12
        Dim HTTOPLEFT As Integer = 13
        Dim HTTOPRIGHT As Integer = 14
        Dim HTBOTTOM As Integer = 15
        Dim HTBOTTOMLEFT As Integer = 16
        Dim HTBOTTOMRIGHT As Integer = 17
        Dim HTREDUCE As Integer = HTMINBUTTON
        Dim HTZOOM As Integer = HTMAXBUTTON
        Dim HTSIZEFIRST As Integer = HTLEFT

        Dim p As New Point(LoWord(CInt(lparam)), HiWord(CInt(lparam)))

        Dim topleft As Rectangle = RectangleToScreen(New Rectangle(0, 0, _
                                   dwmMargins.cxLeftWidth, dwmMargins.cxLeftWidth))

        If topleft.Contains(p) Then
            Return New IntPtr(HTTOPLEFT)
        End If

        Dim topright As Rectangle = _
          RectangleToScreen(New Rectangle(Width - dwmMargins.cxRightWidth, 0, _
          dwmMargins.cxRightWidth, dwmMargins.cxRightWidth))

        If topright.Contains(p) Then
            Return New IntPtr(HTTOPRIGHT)
        End If

        Dim botleft As Rectangle = _
           RectangleToScreen(New Rectangle(0, Height - dwmMargins.cyBottomHeight, _
           dwmMargins.cxLeftWidth, dwmMargins.cyBottomHeight))

        If botleft.Contains(p) Then
            Return New IntPtr(HTBOTTOMLEFT)
        End If

        Dim botright As Rectangle = _
            RectangleToScreen(New Rectangle(Width - dwmMargins.cxRightWidth, _
            Height - dwmMargins.cyBottomHeight, _
            dwmMargins.cxRightWidth, dwmMargins.cyBottomHeight))

        If botright.Contains(p) Then
            Return New IntPtr(HTBOTTOMRIGHT)
        End If

        Dim top As Rectangle = _
            RectangleToScreen(New Rectangle(0, 0, Width, dwmMargins.cxLeftWidth))

        If top.Contains(p) Then
            Return New IntPtr(HTTOP)
        End If

        Dim cap As Rectangle = _
            RectangleToScreen(New Rectangle(0, dwmMargins.cxLeftWidth, _
            Width, dwmMargins.cyTopHeight - dwmMargins.cxLeftWidth))

        If cap.Contains(p) Then
            Return New IntPtr(HTCAPTION)
        End If

        Dim left As Rectangle = _
            RectangleToScreen(New Rectangle(0, 0, dwmMargins.cxLeftWidth, Height))

        If left.Contains(p) Then
            Return New IntPtr(HTLEFT)
        End If

        Dim right As Rectangle = _
            RectangleToScreen(New Rectangle(Width - dwmMargins.cxRightWidth, _
            0, dwmMargins.cxRightWidth, Height))

        If right.Contains(p) Then
            Return New IntPtr(HTRIGHT)
        End If

        Dim bottom As Rectangle = _
            RectangleToScreen(New Rectangle(0, Height - dwmMargins.cyBottomHeight, _
            Width, dwmMargins.cyBottomHeight))

        If bottom.Contains(p) Then
            Return New IntPtr(HTBOTTOM)
        End If

        Return New IntPtr(HTCLIENT)
    End Function		


dwmMargins.cyTopHeight = 0
                dwmMargins.cxLeftWidth = 0
                dwmMargins.cyBottomHeight = 1
                dwmMargins.cxRightWidth = 0 

You need to have AT LEAST one value higher than 1.

You should have something like this by now:


NICE! Now you have a Zune like shape, with shadows and everything. What else will we need? The resizing stuff, of course!

Private Const BorderWidth As Integer = 6
    Private _resizeDir As ResizeDirection = ResizeDirection.None
    Private Sub Form1_MouseDown(ByVal sender As System.Object, _
	ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
        If e.Button = Windows.Forms.MouseButtons.Left Then
            If Me.Width - BorderWidth > e.Location.X AndAlso _
		e.Location.X > BorderWidth AndAlso e.Location.Y > BorderWidth Then
                If Me.WindowState <> FormWindowState.Maximized Then
                End If
            End If
        End If
    End Sub
    Public Enum ResizeDirection
        None = 0
        Left = 1
        TopLeft = 2
        Top = 4
        TopRight = 8
        Right = 16
        BottomRight = 32
        Bottom = 64
        BottomLeft = 128
    End Enum
    Private Property resizeDir() As ResizeDirection
            Return _resizeDir
        End Get
        Set(ByVal value As ResizeDirection)
            _resizeDir = value
            'Change cursor
            Select Case value
                Case ResizeDirection.Left
                    Me.Cursor = Cursors.SizeWE
                Case ResizeDirection.Right
                    Me.Cursor = Cursors.SizeWE
                Case ResizeDirection.Top
                    Me.Cursor = Cursors.SizeNS
                Case ResizeDirection.Bottom
                    Me.Cursor = Cursors.SizeNS
                Case ResizeDirection.BottomLeft
                    Me.Cursor = Cursors.SizeNESW

                Case ResizeDirection.TopRight
                    Me.Cursor = Cursors.SizeNESW

                Case ResizeDirection.BottomRight
                    Me.Cursor = Cursors.SizeNWSE

                Case ResizeDirection.TopLeft
                    Me.Cursor = Cursors.SizeNWSE

                Case Else
                    Me.Cursor = Cursors.Default
            End Select
        End Set
    End Property

    Private Sub Form1_MouseMove(ByVal sender As System.Object, _
	ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove
        'Calculate which direction to resize based on mouse position

        If e.Location.X < BorderWidth And e.Location.Y < BorderWidth Then
            resizeDir = ResizeDirection.TopLeft

        ElseIf e.Location.X < BorderWidth And e.Location.Y > Me.Height - BorderWidth Then
            resizeDir = ResizeDirection.BottomLeft

        ElseIf e.Location.X > Me.Width - BorderWidth And e.Location.Y > _
		Me.Height - BorderWidth Then
            resizeDir = ResizeDirection.BottomRight

        ElseIf e.Location.X > Me.Width - BorderWidth And e.Location.Y < BorderWidth Then
            resizeDir = ResizeDirection.TopRight

        ElseIf e.Location.X < BorderWidth Then
            resizeDir = ResizeDirection.Left

        ElseIf e.Location.X > Me.Width - BorderWidth Then
            resizeDir = ResizeDirection.Right

        ElseIf e.Location.Y < BorderWidth Then
            resizeDir = ResizeDirection.Top

        ElseIf e.Location.Y > Me.Height - BorderWidth Then
            resizeDir = ResizeDirection.Bottom

            resizeDir = ResizeDirection.None
        End If
    End Sub

    Private Sub MoveControl(ByVal hWnd As IntPtr)
        SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0)
    End Sub

    Private Sub ResizeForm(ByVal direction As ResizeDirection)
        Dim dir As Integer = -1
        Select Case direction
            Case ResizeDirection.Left
                dir = HTLEFT
            Case ResizeDirection.TopLeft
                dir = HTTOPLEFT
            Case ResizeDirection.Top
                dir = HTTOP
            Case ResizeDirection.TopRight
                dir = HTTOPRIGHT
            Case ResizeDirection.Right
                dir = HTRIGHT
            Case ResizeDirection.BottomRight
                dir = HTBOTTOMRIGHT
            Case ResizeDirection.Bottom
                dir = HTBOTTOM
            Case ResizeDirection.BottomLeft
                dir = HTBOTTOMLEFT
        End Select

        If dir <> -1 Then
            SendMessage(Me.Handle, WM_NCLBUTTONDOWN, dir, 0)
        End If

    End Sub

    <DllImport("user32.dll")> _
    Public Shared Function ReleaseCapture() As Boolean
    End Function

    <DllImport("user32.dll")> _
    Public Shared Function SendMessage(ByVal hWnd As IntPtr, _
	ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) _
	As Integer
    End Function

    Private Const WM_NCLBUTTONDOWN As Integer = &HA1
    Private Const HTBORDER As Integer = 18
    Private Const HTBOTTOM As Integer = 15
    Private Const HTBOTTOMLEFT As Integer = 16
    Private Const HTBOTTOMRIGHT As Integer = 17 
    Private Const HTCAPTION As Integer = 2
    Private Const HTLEFT As Integer = 10
    Private Const HTRIGHT As Integer = 11
    Private Const HTTOP As Integer = 12
    Private Const HTTOPLEFT As Integer = 13
    Private Const HTTOPRIGHT As Integer = 14  

Nice, everything should be working by now. Big Grin | :-D

Ah, you can also increase and decrease border size by changing the "BorderWidth" value to whatever you want. Just remember that it needs to be an integer value.

The Last Problem

Everything works fine if you don't overlay any border, but if you do, there's a simple way to fix it. All you have to do is to add your control's mousedown and mousemove events on the Form1_MouseDown and Form1_MouseMove events. That's all. Big Grin | :-D

A Bit of Work...

With a little bit more of work and my code, you can easily create full-featured and amazing interfaces. And the coolest part is that now, you'd be able to create everything on your form! Want a Mac OS X window? Just create it! Want a Zune Clone interface? Just copy it! That simple! Big Grin | :-D

I've created a simple demonstration of what can be made without much work (that's just a preview to show something different than a black window). Check this out:


That's the Zune interface.


And this is a simple example of what can be made with a little work. That's just a sample application I've created within 5 minutes to test this article, and as you can see, it's pretty much the same as the Zune UI.

Points of Interest

It is cool to develop this kind of interface since you can have full control over your form without losing some pretty cool Vista/7 effects such as shadows.

By the way, I'd like to say sorry for my bad English.



  • 1st code revision published


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


About the Author

Brazil Brazil
No Biography provided

You may also be interested in...

Comments and Discussions

GeneralMy vote of 5 Pin
Member 116370706-Nov-15 10:42
memberMember 116370706-Nov-15 10:42 
Questionhi Sir Pin
Member 118853774-Aug-15 7:17
memberMember 118853774-Aug-15 7:17 
Questionnoresize possible? Pin
TonyStuck5-Apr-14 4:10
memberTonyStuck5-Apr-14 4:10 
Questiondwmapi.dll Pin
Member 1058056730-Mar-14 14:41
memberMember 1058056730-Mar-14 14:41 
QuestionThe Source doesn't work in Visual Studio 2012 debug Pin
Member 104465414-Dec-13 23:50
memberMember 104465414-Dec-13 23:50 
QuestionWindows XP e outros... Pin
bydario2-Jun-13 18:48
memberbydario2-Jun-13 18:48 
AnswerRe: Windows XP e outros... Pin
Danilo Dev.8-Jul-13 5:01
memberDanilo Dev.8-Jul-13 5:01 
QuestionDon't work??? Pin
dherrmann22-May-13 23:02
memberdherrmann22-May-13 23:02 
AnswerAdd this Code to the Form To Fix Auto Resize when minimizing and maximizing Pin
abdallah alsayed22-Dec-12 13:32
memberabdallah alsayed22-Dec-12 13:32 
GeneralI love you, look what I made because of you! Pin
Lagkip5-Sep-12 10:51
memberLagkip5-Sep-12 10:51 
GeneralRe: I love you, look what I made because of you! Pin
DarkerThanMe5-Sep-12 18:44
memberDarkerThanMe5-Sep-12 18:44 
GeneralRe: I love you, look what I made because of you! Pin
Lagkip6-Sep-12 6:09
memberLagkip6-Sep-12 6:09 
QuestionError Pin
Iqbal Ali7-Aug-12 4:51
memberIqbal Ali7-Aug-12 4:51 
AnswerRe: Error Pin
rockstar965-Dec-13 4:07
memberrockstar965-Dec-13 4:07 
GeneralGracias! Pin
Member 80392754-Aug-12 19:43
memberMember 80392754-Aug-12 19:43 
GeneralMy vote of 5 Pin
Lagkip13-Jun-12 9:23
memberLagkip13-Jun-12 9:23 
Questionbug Pin
cpw999cn19-Mar-12 2:46
membercpw999cn19-Mar-12 2:46 
GeneralRe: bug Pin
Member 80392754-Aug-12 19:42
memberMember 80392754-Aug-12 19:42 
Questionfull code Pin
Luige César Salvi1-Dec-11 7:27
memberLuige César Salvi1-Dec-11 7:27 
BugTitle Bar Comes Up! Pin
Member 843837728-Nov-11 11:01
memberMember 843837728-Nov-11 11:01 
GeneralMy vote of 5 Pin
Member 843837727-Nov-11 18:19
memberMember 843837727-Nov-11 18:19 
QuestionMinimized Form Problem Pin
oohoo_u28-Oct-11 7:42
memberoohoo_u28-Oct-11 7:42 
GeneralMy vote of 5 Pin
megagonzo5-Oct-11 23:42
membermegagonzo5-Oct-11 23:42 
QuestionMaximize Pin
sathya.cs7-Sep-11 0:31
membersathya.cs7-Sep-11 0:31 
Questionc# Pin
identy30-Aug-11 13:05
memberidenty30-Aug-11 13:05 
QuestionWhy WinForm and not WPF? Pin
Callon Campbell19-Jan-11 10:01
memberCallon Campbell19-Jan-11 10:01 
AnswerRe: Why WinForm and not WPF? Pin
Globin25-Jun-12 11:09
memberGlobin25-Jun-12 11:09 
AnswerRe: Why WinForm and not WPF? Pin
geordiemike17-Sep-14 5:16
membergeordiemike17-Sep-14 5:16 
GeneralProblems Pin
regbnvl26-Dec-10 0:57
memberregbnvl26-Dec-10 0:57 
GeneralRe: Problems Pin
lipinho26-Dec-10 10:48
memberlipinho26-Dec-10 10:48 
GeneralRe: Problems Pin
regbnvl26-Dec-10 10:53
memberregbnvl26-Dec-10 10:53 
GeneralRe: Problems Pin
lipinho26-Dec-10 10:58
memberlipinho26-Dec-10 10:58 
GeneralRe: Problems Pin
Sacha Barber26-Dec-10 21:02
mvpSacha Barber26-Dec-10 21:02 
GeneralRe: Problems Pin
lipinho26-Dec-10 21:11
memberlipinho26-Dec-10 21:11 
GeneralRe: Problems Pin
Ryner Lute: T.L.D29-Apr-14 19:39
memberRyner Lute: T.L.D29-Apr-14 19:39 
GeneralI think your article is misleading Pin
Sacha Barber25-Dec-10 23:11
mvpSacha Barber25-Dec-10 23:11 
GeneralRe: I think your article is misleading Pin
lipinho26-Dec-10 10:52
memberlipinho26-Dec-10 10:52 
GeneralRe: I think your article is misleading Pin
Hugo Tomas27-Dec-10 3:07
memberHugo Tomas27-Dec-10 3:07 
GeneralMy vote of 5 Pin
RaviRanjankr25-Dec-10 19:18
memberRaviRanjankr25-Dec-10 19:18 
GeneralRe: My vote of 5 Pin
lipinho25-Dec-10 19:19
memberlipinho25-Dec-10 19:19 
GeneralRe: My vote of 5 Pin
RaviRanjankr25-Dec-10 19:50
memberRaviRanjankr25-Dec-10 19:50 
GeneralMy vote of 5 Pin
aman.tur24-Dec-10 4:57
memberaman.tur24-Dec-10 4:57 
GeneralMy vote of 5 Pin
imgen23-Dec-10 20:26
memberimgen23-Dec-10 20:26 
GeneralRe: My vote of 5 Pin
lipinho24-Dec-10 8:01
memberlipinho24-Dec-10 8:01 
Generalthe black hole Pin
Rozis23-Dec-10 13:10
memberRozis23-Dec-10 13:10 
GeneralRe: the black hole Pin
lipinho23-Dec-10 16:42
memberlipinho23-Dec-10 16:42 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.151126.1 | Last Updated 26 Dec 2010
Article Copyright 2010 by lipinho
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid