Axe
Axe

Reputation: 6335

Adding a custom button in title bar VB.NET

I was just wondering if there was a possible way to add a custom button into the title bar using VB.NET. I've seen many such questions on Stack Overflow but failed to get a sure-shot and a working answer.

Can anyone help me around with this issue? I've checked on Google and other website too but it fails to render. I want the code to work on Windows XP, Windows Vista and Windows 7.

I would be grateful if you will be able to give a working code and the button must even be able to accept click events and post it to the form it is on for some action.

Thanks in advance

Upvotes: 3

Views: 9009

Answers (3)

Shahin
Shahin

Reputation: 12843

As Matthew Scharley writes in his answer here:

The following will work in XP, I have no Vista machine handy to test it, but I think you're issues are steming from an incorrect hWnd somehow. Anyway, on with the poorly commented code.

I think this doesn't show up graphically in Vista and 7. The translated version of Matthew's code is as follows:

' The state of our little button
Private _buttState As ButtonState = ButtonState.Normal
Private _buttPosition As New Rectangle()

<DllImport("user32.dll")> _
Private Shared Function GetWindowDC(hWnd As IntPtr) As IntPtr
End Function
<DllImport("user32.dll")> _
Private Shared Function GetWindowRect(hWnd As IntPtr, ByRef lpRect As Rectangle) As Integer
End Function
<DllImport("user32.dll")> _
Private Shared Function ReleaseDC(hWnd As IntPtr, hDC As IntPtr) As Integer
End Function
Protected Overrides Sub WndProc(ByRef m As Message)
    Dim x As Integer, y As Integer
    Dim windowRect As New Rectangle()
    GetWindowRect(m.HWnd, windowRect)

    Select Case m.Msg
        ' WM_NCPAINT
        ' WM_PAINT
        Case &H85, &Ha
            MyBase.WndProc(m)

            DrawButton(m.HWnd)

            m.Result = IntPtr.Zero

            Exit Select

        ' WM_ACTIVATE
        Case &H86
            MyBase.WndProc(m)
            DrawButton(m.HWnd)

            Exit Select

        ' WM_NCMOUSEMOVE
        Case &Ha0
            ' Extract the least significant 16 bits
            x = (CInt(m.LParam) << 16) >> 16
            ' Extract the most significant 16 bits
            y = CInt(m.LParam) >> 16

            x -= windowRect.Left
            y -= windowRect.Top

            MyBase.WndProc(m)

            If Not _buttPosition.Contains(New Point(x, y)) AndAlso _buttState = ButtonState.Pushed Then
                _buttState = ButtonState.Normal
                DrawButton(m.HWnd)
            End If

            Exit Select

        ' WM_NCLBUTTONDOWN
        Case &Ha1
            ' Extract the least significant 16 bits
            x = (CInt(m.LParam) << 16) >> 16
            ' Extract the most significant 16 bits
            y = CInt(m.LParam) >> 16

            x -= windowRect.Left
            y -= windowRect.Top

            If _buttPosition.Contains(New Point(x, y)) Then
                _buttState = ButtonState.Pushed
                DrawButton(m.HWnd)
            Else
                MyBase.WndProc(m)
            End If

            Exit Select

        ' WM_NCLBUTTONUP
        Case &Ha2
            ' Extract the least significant 16 bits
            x = (CInt(m.LParam) << 16) >> 16
            ' Extract the most significant 16 bits
            y = CInt(m.LParam) >> 16

            x -= windowRect.Left
            y -= windowRect.Top

            If _buttPosition.Contains(New Point(x, y)) AndAlso _buttState = ButtonState.Pushed Then
                _buttState = ButtonState.Normal
                ' [[TODO]]: Fire a click event for your button 
                '           however you want to do it.
                DrawButton(m.HWnd)
            Else
                MyBase.WndProc(m)
            End If

            Exit Select

        ' WM_NCHITTEST
        Case &H84
            ' Extract the least significant 16 bits
            x = (CInt(m.LParam) << 16) >> 16
            ' Extract the most significant 16 bits
            y = CInt(m.LParam) >> 16

            x -= windowRect.Left
            y -= windowRect.Top

            If _buttPosition.Contains(New Point(x, y)) Then
                m.Result = DirectCast(18, IntPtr)
            Else
                ' HTBORDER
                MyBase.WndProc(m)
            End If

            Exit Select
        Case Else

            MyBase.WndProc(m)
            Exit Select
    End Select
End Sub

Private Sub DrawButton(hwnd As IntPtr)
    Dim hDC As IntPtr = GetWindowDC(hwnd)
    Dim x As Integer, y As Integer

    Using g As Graphics = Graphics.FromHdc(hDC)
        ' Work out size and positioning
        Dim CaptionHeight As Integer = Bounds.Height - ClientRectangle.Height
        Dim ButtonSize As Size = SystemInformation.CaptionButtonSize
        x = Bounds.Width - 4 * ButtonSize.Width
        y = (CaptionHeight - ButtonSize.Height) \ 2
        _buttPosition.Location = New Point(x, y)

        ' Work out color
        Dim color As Brush
        If _buttState = ButtonState.Pushed Then
            color = Brushes.LightGreen
        Else
            color = Brushes.Red
        End If

        ' Draw our "button"
        g.FillRectangle(color, x, y, ButtonSize.Width, ButtonSize.Height)
    End Using

    ReleaseDC(hwnd, hDC)
End Sub

Private Sub Form1_Load(sender As Object, e As EventArgs)
    _buttPosition.Size = SystemInformation.CaptionButtonSize
End Sub

Upvotes: 1

IAmTimCorey
IAmTimCorey

Reputation: 16757

Here is an example with some working code:

http://www.dreamincode.net/forums/topic/69215-2008-custom-title-bar/

Basically, you need to create a form with no border, then roll your own "Titlebar" which will basically be an area at the top that you can customize however you want. This is a difficult solution to fully implement properly, but it is probably the way that will best accomplish this.

Upvotes: 1

Joel Coehoorn
Joel Coehoorn

Reputation: 415735

If you mean winforms, I can think of two ways to do this:

  • Hide the titlebar and replace it with your own, which I don't recommend.
  • Build the button as a very small form that you keep docked in the correct position every time your window moves.

Upvotes: 4

Related Questions