Как нарисовать пользовательскую кнопку в заголовке Windows Forms в Windows 10 с помощью VB.NET?

Я ищу, чтобы отобразить настраиваемую кнопку в заголовке формы, используя VB.NET и Windows Forms.

Я прочитал и скопировал код из Как нарисовать пользовательскую кнопку в заголовке окна с помощью Windows Forms? и Добавление настраиваемой кнопки в строку заголовка VB. NET

Проблема с этими двумя вопросами и ответами в том, что они очень старые и не работают на моем компьютере с Windows 10.

Когда я использую следующий код

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

Когда я запускаю этот код в режиме отладки из Visual Studio 2019, пользовательская кнопка никогда не отображается!

введите описание изображения здесь

Когда я меняю код WM_NCPAINT (все строки прокомментированы) вот так

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

Получаю следующий результат

введите описание изображения здесь

Если я активирую VS Studio 2019 и вернусь в свое приложение, я увижу следующий результат.

введите описание изображения здесь

Я жду первого PrintScreen с красным прямоугольником. Последний PrintScreen неверен, потому что кнопки Minimize и Close имеют разный стиль!

Что неверно в моем коде?

Спасибо за любую помощь.


person schlebe    schedule 16.03.2021    source источник
comment
Подробная информация о текущем положении кнопок панели заголовков извлекается с помощью отправки WM_GETTITLEBARINFOEX сообщение. См. Реализацию здесь: Установка ширины формы в соответствии с текстом в строке заголовка. Тогда вам понадобится следующее: Пользовательский фрейм окна с использованием DWM   -  person Jimi    schedule 16.03.2021
comment
Вы также можете проверить это: Необычные формы Windows   -  person Jimi    schedule 16.03.2021
comment
@Jimi: Необычные Windows Forms перерисовывают кнопки «Свернуть» / «Развернуть» / «Закрыть». Ищу решение, где все эти кнопки используются повторно.   -  person schlebe    schedule 16.03.2021
comment
Вот о чем первый комментарий. Другой - на всякий случай.   -  person Jimi    schedule 16.03.2021
comment
В CodeProject я также нашел codeproject.com/ Статьи / 107306 /   -  person schlebe    schedule 16.03.2021
comment
Я знаю этот пост. Это отчасти интересно, потому что здесь используются некоторые методы рендеринга темы. Но он перерисовывает содержимое окна после удаления рамки по умолчанию (настройка FormBorderStyle = none). Если вы используете версию DWM, стандартные кнопки и рамка сохраняются, но у вас есть полный контроль над областью, которая обычно занимает панель заголовка, которая теперь является клиентской областью, поэтому вы можете рисовать там все, что захотите. Или просто поместите стандартную кнопку (или что-нибудь еще), как будто вы добавляете ее в ClientArea окна как обычно (более или менее :).   -  person Jimi    schedule 16.03.2021
comment
Спасибо, но моя проблема в том, что все, что описано в разделе «Пользовательский фрейм окна с использованием DWM», предназначено для C ++! У вас есть примеры для VB.Net с DWM?   -  person schlebe    schedule 16.03.2021
comment
Вы можете взять большинство определений функций и типов из моего сообщения здесь: Как создать полупрозрачный или размытый фон в Windows Form - Другой поможет вам приблизиться к этому: Как правильно определить размер неклиентской области для Aero?. Вы можете найти другие сообщения (VB.Net и C # очень похожи), используя DwmExtendFrameIntoClientArea в качестве ключевого слова поиска.   -  person Jimi    schedule 16.03.2021