0

I search to display a custom Button in Form's Titlebar using VB.NET and Windows Forms.

I have read and copied code from How to draw custom button in Window Titlebar with Windows Forms? and Adding a custom button in title bar VB.NET

The problem with these 2 Q&A is that they are very old and don't work on my PC that turns on Windows 10.

When I use following code

Public Class Form1

Private Const WM_PAINT As Integer = &HF
Private Const WM_NCPAINT As Integer = &H85
Private Const WM_ACTIVATE As Integer = &H86

Private oButtonState = ButtonState.Normal
Private oButtonPos = New Rectangle()

Declare Function GetWindowDC Lib "user32" (ByVal hwnd As IntPtr) As IntPtr
Declare Function GetWindowRect Lib "user32" (ByVal hWnd As IntPtr, ByRef lpRect As Rectangle) As Boolean
Declare Function ReleaseDC Lib "user32" (ByVal hWnd As IntPtr, ByVal prmlngHDc As IntPtr) As <Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.Bool)> Boolean

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    Dim x As Integer
    Dim y As Integer
    Dim wRect As Rectangle = New Rectangle()

    Select Case m.Msg
        Case WM_NCPAINT
            MyBase.WndProc(m)
            DrawButton(m.HWnd)
            m.Result = IntPtr.Zero
        Case WM_PAINT
            MyBase.WndProc(m)
            DrawButton(m.HWnd)
            m.Result = IntPtr.Zero
        Case WM_ACTIVATE
            MyBase.WndProc(m)
            DrawButton(m.HWnd)
        Case Else
            MyBase.WndProc(m)
    End Select
End Sub

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

    Using g As Graphics = Graphics.FromHdc(hDC)
        Dim iCaptionHeight = Bounds.Height - Me.ClientRectangle.Height
        Dim oButtonSize As Size = SystemInformation.CaptionButtonSize
        x = Bounds.Width - 4 * oButtonSize.Width
        y = (iCaptionHeight - oButtonSize.Height) / 2
        oButtonPos.Location = New Point(x, y)

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

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

    ReleaseDC(hwnd, hDC)
End Sub

End Class

When I run this code in debug mode from Visual Studio 2019, custom button is never displayed !

enter image description here

When I change WM_NCPAINT code (all lines are commented) like this

Case WM_NCPAINT
            'MyBase.WndProc(m)
            'DrawButton(m.HWnd)
            'm.Result = IntPtr.Zero

I obtain following result

enter image description here

If I activate VS Studio 2019 and I go back to my application, I can see following result.

enter image description here

What I'm expexting is first PrintScreen with red rectangle. Last PrintScreen is not correct because Minimize and Close buttons have a distinct style !

What is false in my code ?

Thanks for any help.

schlebe
  • 3,387
  • 5
  • 37
  • 50
  • Details on the current position of the TitleBar Buttons are retrieved sending a [WM_GETTITLEBARINFOEX](https://learn.microsoft.com/en-us/windows/win32/menurc/wm-gettitlebarinfoex) message. See an implementation here: [Setting form's width according to text in title bar](https://stackoverflow.com/a/66570957/7444103) -- Then you need this: [Custom Window Frame Using DWM](https://learn.microsoft.com/en-us/windows/win32/dwm/customframe) – Jimi Mar 16 '21 at 11:26
  • You could also test this: [Fancy Windows Forms](https://www.codeproject.com/articles/33716/fancy-windows-forms) – Jimi Mar 16 '21 at 11:35
  • @Jimi: Fancy Windows Forms redraw Minimize/Maximize/Close buttons. I search a solution where all these buttons are reused. – schlebe Mar 16 '21 at 12:56
  • That's what the first comment is about. The other is a *just in case you find it interesting*. – Jimi Mar 16 '21 at 12:58
  • On CodeProject I have also found https://www.codeproject.com/Articles/107306/gTitleBar-Custom-TitleBar-for-Borderless-Forms-VB – schlebe Mar 16 '21 at 13:13
  • I know that post. That's partially interesting, because it uses some of the Theme rendering methods. But it re-draws the Window content after removing the default frame (setting `FormBorderStyle = none`). If you use the DWM version, the standard Buttons and Frame are preserved, but you have full control over the area that's usually occupied by the TitleBar, which is now Client Area, so you can draw anything you want there. Or just put a standard Button (or anything else) as if you're adding it to the Window's ClientArea as usual (more or less :). – Jimi Mar 16 '21 at 13:19
  • Thanks, but my problem is that all what is described in Custom Window Frame Using DWM is for C++ ! Have you some examples for VB.Net with DWM ? – schlebe Mar 16 '21 at 14:17
  • You can take most of the Functions and Types definitions from my post here: [How to create a semi transparent or blurred backcolor in a Windows Form](https://stackoverflow.com/a/51580871/7444103) -- This other will get you near it: [How to determine correctly the Non-Client Area Size for Aero?](https://stackoverflow.com/q/16111595/7444103). You can find other posts (VB.Net and C# are quite similar) using `DwmExtendFrameIntoClientArea` as the search keyword. – Jimi Mar 16 '21 at 14:35

0 Answers0