3

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

Axe
  • 6,285
  • 3
  • 31
  • 38

3 Answers3

4

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.
Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • Thanks for that answer but are you sure there is no function in the Windows DLLs to add a button to the title bar? I've seen codes that use these APIs but don't work that well! Please help me out – Axe May 30 '11 at 05:19
1

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.

IAmTimCorey
  • 16,412
  • 5
  • 39
  • 75
1

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
Community
  • 1
  • 1
Shahin
  • 12,543
  • 39
  • 127
  • 205
  • 1
    I was glad you can ahead, gave me a code piece to help me out. I currently have Windows 7 and it fails to render. I've not really tried it on Windows XP. But once again, thanks for your help! The following code seems to give an error saying that 18 cannot be converted to IntPtr: "m.Result = DirectCast(18, IntPtr)". Once again, thanks for your help! Cheers – Axe May 30 '11 at 06:06
  • Your welcome :) honestly I tried this code in c# and it works so i did convert it to VB.NET. good luck – Shahin May 30 '11 at 11:29