A window that's star-shaped, circular or tank-shaped

Create windows of any geometric shape using SetWindowRgn - works with UserControls too!

Clock Sample Project

Just for fun, its surprisingly easy now to create Windows or controls of any shape whatsoever under Visual Basic. This article demonstrates using SetWindowsRgn to create Windows with a variety of geometric shapes.

The trick here is to use the SetWindowRgn function. This function allows you to set the clipping region for a window including the border. The shape of your region depends upon how you created it. You can create elliptical, polygonal, rectangular, and round regions via calls to the CreateEllipticalRgn, CreatePolygonRgn, CreateRectRgn, and CreateRoundRgn functions. You pass to the creation function the coordinates bounding the region that you wish to set, and the function returns a handle to the region. Once you have the handle to the region, you can pass it to SetWindowRgn, whereupon the window assumes the shape.

In addition to this, you can also join regions together to make composite regions using CombineRgn. The region for your window can have a hole in it, or consist of disjointed regions, anything!

The declares you require to get started are:

' ===============================================================
' API declares for creating regions and setting a window's region
' ===============================================================

' Point
Type POINTAPI
    X As Long
    Y As Long
End Type

' Change region of a window:
Declare Function SetWindowRgn Lib "user32" _
    (ByVal hWnd As Long, ByVal hRgn As Long, ByVal bRedraw As Boolean) As Long

' Precanned region creation functions:
Declare Function CreateEllipticRgn Lib "gdi32" _
    (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Declare Function CreateRectRgn Lib "gdi32" _
    (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Declare Function CreateRoundRectRgn Lib "gdi32" _
    (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long, ByVal X3 As Long, _
    ByVal Y3 As Long) As Long

' Polygon region creation functions:
Declare Function CreatePolygonRgn Lib "gdi32" _
    (lpPoint As POINTAPI, ByVal nCount As Long, ByVal nPolyFillMode As Long) As Long
Declare Function CreatePolyPolygonRgn Lib "gdi32" _
    (lpPoint As POINTAPI, lpPolyCounts As Long, _
    ByVal nCount As Long, ByVal nPolyFillMode As Long) As Long

' Polygon type:
Public Const WINDING = 2
' Region combination:
Declare Function CombineRgn Lib "gdi32" _
    (ByVal hDestRgn As Long, _
    ByVal hSrcRgn1 As Long, ByVal hSrcRgn2 As Long, _
    ByVal nCombineMode As Long) As Long
    
' Region combination types:
    Public Const RGN_AND = 1
    Public Const RGN_COPY = 5
    Public Const RGN_DIFF = 4
    Public Const RGN_MAX = RGN_COPY
    Public Const RGN_MIN = RGN_AND
    Public Const RGN_OR = 2
    Public Const RGN_XOR = 3
' Region combination return values:
    Public Const COMPLEXREGION = 3
    Public Const SIMPLEREGION = 2
    Public Const NULLREGION = 1

' GDI Clear up:
Declare Function DeleteObject Lib "gdi32" _
    (ByVal hObject As Long) As Long

And here is the code which will make a VB form or control elliptical:

Private Sub MakeEllipse( _
    byVal lHwnd As Long, ByVal lWidth As Long, ByVal lHeight As Long)
Dim hRgn As Long
    hRgn = CreateEllipticRgn(0,0,lWidth,lHeight)
    ' Change the region:
    SetWindowRgn lHWnd, hRgn, 1
End Sub

' For a form:
Private Sub Form_Load()
    MakeEllipse Me.Hwnd, _
        Me.Width\Screen.TwipsPerPixelX, _
        Me.Height\Screen.TwipsPerPixelY
End Sub

' For a control:
Private Sub UserControl_InitProperties
    MakeEllipse UserControl.Hwnd, _
        UserControl.Width\Screen.TwipsPerPixelX, _
        UserControl.Height\Screen.TwipsPerPixelY
End Sub

Private Sub UserControl_ReadProperties
    MakeEllipse UserControl.Hwnd, _
        UserControl.Width\Screen.TwipsPerPixelX, _
        UserControl.Height\Screen.TwipsPerPixelY
End Sub

And that's it. Have fun filling in the backgrounds, and try out the source code, which demonstrates a number of other techniques, including:

  • more advanced regions (including holed and separated) using CombineRgn
  • a simple circular clock
  • how to trigger the system menu 'Move' command in code
  • moving a form in response to a mouse down.