Jump to content

Need help with subclassing text color of dark mode Header


Go to solution Solved by ioa747,

Recommended Posts

Posted

This is for the Files Au3 - AutoIt File Manager project.

If anyone could help me with subclassing the text color for a Header control, I would really appreciate it. Please keep in mind that this is a standalone Header control (_GUICtrlHeader_Create) and not the header of a ListView.

There are several great examples in the forum for subclassing the text color for a header of a ListView control. Here are some examples:

I assume that what needs to be done for a standalone header control would be very similar, but some of the constants would certainly be different. I simply have no experience with the subclassing stuff and don't understand it at all.

Thank you for your time. :)

 

Here is an example with dark mode applied to the header already that could be used as a base before subclassing gets added.

#include <SendMessage.au3>
#include <WindowsNotifsConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiHeader.au3>

Global $g_hGUI, $g_hHeader

Example()

Func Example()
    ; Create a GUI with various controls.
    Local $g_hGUI = GUICreate("Dark Mode Header", 400, 400)

    ; Set background color
    GUISetBkColor(0x121212)

    ; create header
    $g_hHeader = _GUICtrlHeader_Create($g_hGUI)
    For $i = 0 To 2
        _GUICtrlHeader_AddItem($g_hHeader, "Column" & $i, 80)
    Next

    ; apply dark mode to GUI and header
    DarkMode($g_hGUI, True)
    _WinAPI_SetWindowTheme_unr($g_hHeader, 'DarkMode_ItemsView', 'Header')

    ; Display the GUI.
    GUISetState(@SW_SHOW, $g_hGUI)

    ; Loop until the user exits.
    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop

        EndSwitch
    WEnd

    ; Delete the previous GUI and all controls.
    GUIDelete($g_hGUI)
EndFunc   ;==>Example


;--------------------------------------------------------------------------------------------------------------------------------
; https://www.autoitscript.com/forum/topic/211475-darkmode-udf-for-autoits-win32guis/#comment-1530103
;--------------------------------------------------------------------------------------------------------------------------------
Func DarkMode($hGUI, $bDarkMode = True)                               ; DarkMode

    Local Enum $DWMWA_USE_IMMERSIVE_DARK_MODE = (@OSBuild <= 18985) ? 19 : 20
    ;ConsoleWrite("$DWMWA_USE_IMMERSIVE_DARK_MODE=" & $DWMWA_USE_IMMERSIVE_DARK_MODE & @CRLF)
    ;       DWMWA_USE_IMMERSIVE_DARK_MODE ; https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
    ;       Use with DwmSetWindowAttribute. Allows the window frame for this window to be drawn in dark mode colors when the dark mode system setting is enabled.
    ;       For compatibility reasons, all windows default to light mode regardless of the system setting.
    ;       The pvAttribute parameter points to a value of type BOOL. TRUE to honor dark mode for the window, FALSE to always use light mode.
    ;       This value is supported starting with Windows 11 Build 22000.

    Local $iRet = _WinAPI_DwmSetWindowAttribute_unr($hGUI, $DWMWA_USE_IMMERSIVE_DARK_MODE, $bDarkMode)
    If Not $iRet Then Return SetError(1, 0, -1)

    _SetCtrlColorMode($hGUI, $bDarkMode)
    ;_WinAPI_SetWindowTheme_unr(GUICtrlGetHandle($ChbxDrkMode), 0, 0) ; this control needs the theme

EndFunc   ;==>DarkMode
;--------------------------------------------------------------------------------------------------------------------------------
Func _SetCtrlColorMode($hWnd, $bDarkMode = True, $sName = Default)    ; 'Explorer', 'CFD', 'DarkMode_ItemsView', etc.
    If $sName = Default Then $sName = $bDarkMode ? 'DarkMode_Explorer' : 'Explorer'
    $bDarkMode = Not Not $bDarkMode ; https://www.vbforums.com/showthread.php?900444-Windows-10-Dark-Mode-amp-VB6-apps
    If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
    Local Enum $eDefault, $eAllowDark, $eForceDark, $eForceLight, $eMax ; enum PreferredAppMode
    DllCall('uxtheme.dll', 'bool', 133, 'hwnd', $hWnd, 'bool', $bDarkMode) ; fnAllowDarkModeForWindow = 133
    DllCall('uxtheme.dll', 'int', 135, 'int', ($bDarkMode ? $eForceDark : $eForceLight)) ; fnAllowDarkModeForApp = 135
    _WinAPI_SetWindowTheme_unr($hWnd, $sName) ; https://www.autoitscript.com/forum/index.php?showtopic=211475&view=findpost&p=1530103
    DllCall('uxtheme.dll', 'none', 104) ; fnRefreshImmersiveColorPolicyState = 104  ; not needed ?
    _SendMessage($hWnd, $WM_THEMECHANGED, 0, 0) ; not needed ?
EndFunc   ;==>_SetCtrlColorMode
;--------------------------------------------------------------------------------------------------------------------------------
Func _WinAPI_SetWindowTheme_unr($hWnd, $sName = Null, $sList = Null)  ; #include <WinAPITheme.au3> ; unthoughtful unrestricting mod.
    ;Causes a window to use a different set of visual style information than its class normally uses
    Local $sResult = DllCall('UxTheme.dll', 'long', 'SetWindowTheme', 'hwnd', $hWnd, 'wstr', $sName, 'wstr', $sList)
    If @error Then Return SetError(@error, @extended, 0)
    If $sResult[0] Then Return SetError(10, $sResult[0], 0)
    Return 1
EndFunc   ;==>_WinAPI_SetWindowTheme_unr
;--------------------------------------------------------------------------------------------------------------------------------
Func _WinAPI_DwmSetWindowAttribute_unr($hWnd, $iAttribute, $iData)    ; #include <WinAPIGdi.au3> ; unthoughtful unrestricting mod.
    ;Sets the value of the specified attributes for non-client rendering to apply to the window
    Local $aCall = DllCall('dwmapi.dll', 'long', 'DwmSetWindowAttribute', 'hwnd', $hWnd, 'dword', $iAttribute, _
            'dword*', $iData, 'dword', 4)
    If @error Then Return SetError(@error, @extended, 0)
    If $aCall[0] Then Return SetError(10, $aCall[0], 0)
    Return 1
EndFunc   ;==>_WinAPI_DwmSetWindowAttribute_unr
;--------------------------------------------------------------------------------------------------------------------------------

 

Posted (edited)

Pretty much always the same.  You need the handle of the subject and subclass it.  Just need to know what notification you want to intercept.

#include <GUIConstantsEx.au3>
#include <GuiHeader.au3>
#include <WinAPI.au3>

Global $g_hHeader

Example()

Func Example()
  ; Create a GUI with various controls.
  Local $hGUI = GUICreate("Dark Mode Header", 400, 400)

  ; Set background color
  GUISetBkColor(0x121212)

  ; create header
  $g_hHeader = _GUICtrlHeader_Create($hGUI)
  For $i = 0 To 2
    _GUICtrlHeader_AddItem($g_hHeader, "Column" & $i, 80)
  Next

  Local $hDll = DllCallbackRegister(HeaderProc, 'lresult', 'hwnd;uint;wparam;lparam;uint_ptr;dword_ptr')
  _WinAPI_SetWindowSubclass($g_hHeader, DllCallbackGetPtr($hDll), 1000, 0)

  ; apply dark mode to GUI and header (commented for smaller snippet)
  ;DarkMode($hGUI, True)
  ;_WinAPI_SetWindowTheme_unr($g_hHeader, 'DarkMode_ItemsView', 'Header')

  GUISetState()

  While 1
    Switch GUIGetMsg()
      Case $GUI_EVENT_CLOSE
        ExitLoop

    EndSwitch
  WEnd
  _WinAPI_RemoveWindowSubclass($g_hHeader, DllCallbackGetPtr($hDll), 1000)
  DllCallbackFree($hDll)
EndFunc   ;==>Example

Func HeaderProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData)
  If $iMsg = $WM_LBUTTONDOWN Then ConsoleWrite("click x : " & _WinAPI_LoWord($lParam) & "  y : " & _WinAPI_HiWord($lParam) & @CRLF)
  Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>HeaderProc

 

Edited by Nine
Posted
2 hours ago, Nine said:

Pretty much always the same.  You need the handle of the subject and subclass it.  Just need to know what notification you want to intercept.

Thank you.

I tried my best with two different attempts by combining the code from other examples (which were ListView headers, specifically), but I could not get anything to work. Those examples seem to use the WM_NOTIFY message.

Here was my last failed attempt:

#include <SendMessage.au3>
#include <WindowsNotifsConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiHeader.au3>
#include <WinAPIShellEx.au3>
#include <WinAPIGdiDC.au3>

Global $g_hGUI, $g_hHeader

; Dark Mode Colors (RGB)
Global Const $COLOR_BG_DARK = 0x202020
Global Const $COLOR_TEXT_LIGHT = 0xFFFFFF
Global Const $COLOR_CONTROL_BG = 0x2B2B2B
Global Const $COLOR_EDIT_BG = 0x1E1E1E
Global Const $COLOR_BUTTON_BG = 0x333333
Global Const $COLOR_BORDER = 0x3F3F3F

; Structure for NM_CUSTOMDRAW notification
Global Const $tagNMCUSTOMDRAW = _
            $tagNMHDR & ";" & _                                                 ; Contains NM_CUSTOMDRAW / NMHDR header among other things
            "dword dwDrawStage;" & _                                            ; Current drawing stage (CDDS_*)
            "handle hdc;" & _                                                   ; Device Context Handle
            "long left;long top;long right;long bottom;" & _                    ; Drawing rectangle
            "dword_ptr dwItemSpec;" & _                                         ; Item index or other info (depending on the control)
            "uint uItemState;" & _                                              ; State Flags (CDIS_SELECTED, CDIS_FOCUS etc.)
            "lparam lItemlParam"                                                ; lParam set by the item (e.g., via LVITEM.lParam)

Example()

Func Example()
    ; Create a GUI with various controls.
    Local $g_hGUI = GUICreate("Dark Mode Header", 400, 400)

    ; Set background color
    GUISetBkColor(0x121212)

    ; create header
    $g_hHeader = _GUICtrlHeader_Create($g_hGUI)
    For $i = 0 To 2
        _GUICtrlHeader_AddItem($g_hHeader, "Column" & $i, 80)
    Next

    Local $hDll = DllCallbackRegister(HeaderProc, 'lresult', 'hwnd;uint;wparam;lparam;uint_ptr;dword_ptr')
    _WinAPI_SetWindowSubclass($g_hHeader, DllCallbackGetPtr($hDll), 1000, 0)

    ; apply dark mode to GUI and header
    DarkMode($g_hGUI, True)
    _WinAPI_SetWindowTheme_unr($g_hHeader, 'DarkMode_ItemsView', 'Header')

    ; Display the GUI.
    GUISetState(@SW_SHOW, $g_hGUI)

    ; Loop until the user exits.
    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop

        EndSwitch
    WEnd

    _WinAPI_RemoveWindowSubclass($g_hHeader, DllCallbackGetPtr($hDll), 1000)
    DllCallbackFree($hDll)

    ; Delete the previous GUI and all controls.
    GUIDelete($g_hGUI)
EndFunc   ;==>Example

Func HeaderProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData)
    ;If $iMsg = $WM_LBUTTONDOWN Then ConsoleWrite("click x : " & _WinAPI_LoWord($lParam) & "  y : " & _WinAPI_HiWord($lParam) & @CRLF)
    ;Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)

    Switch $iMsg
        Case $WM_NOTIFY
            Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
            Local $hFrom = $tNMHDR.hWndFrom
            Local $iCode = $tNMHDR.Code

            ; --- Adjust ListView Header text color ---
            If $iCode = $NM_CUSTOMDRAW Then
                Local $tNMCUSTOMDRAW = DllStructCreate($tagNMCUSTOMDRAW, $lParam)
                Local $dwDrawStage = $tNMCUSTOMDRAW.dwDrawStage
                Local $hDC = $tNMCUSTOMDRAW.hdc

                Switch $dwDrawStage
                    Case $CDDS_PREPAINT
                        Return $CDRF_NOTIFYITEMDRAW
                    Case $CDDS_ITEMPREPAINT
                        _WinAPI_SetTextColor($hDC, _ColorToCOLORREF($COLOR_TEXT_LIGHT)) ; White text
                        _WinAPI_SetBkColor($hDC, _ColorToCOLORREF($COLOR_BG_DARK))     ; Dark background
                        Return BitOR($CDRF_NEWFONT, $CDRF_NOTIFYPOSTPAINT)
                EndSwitch
            EndIf

        Case $WM_PAINT
            ; Custom Paint for better Dark Mode rendering
            Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
    EndSwitch

    ; Forward standard message to DefSubclassProc
    Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>HeaderProc

Func _ColorToCOLORREF($iColor) ;RGB to BGR
    Local $iR = BitAND(BitShift($iColor, 16), 0xFF)
    Local $iG = BitAND(BitShift($iColor, 8), 0xFF)
    Local $iB = BitAND($iColor, 0xFF)
    Return BitOR(BitShift($iB, -16), BitShift($iG, -8), $iR)
EndFunc   ;==>_ColorToCOLORREF

;--------------------------------------------------------------------------------------------------------------------------------
; https://www.autoitscript.com/forum/topic/211475-darkmode-udf-for-autoits-win32guis/#comment-1530103
;--------------------------------------------------------------------------------------------------------------------------------
Func DarkMode($hGUI, $bDarkMode = True)                               ; DarkMode

    Local Enum $DWMWA_USE_IMMERSIVE_DARK_MODE = (@OSBuild <= 18985) ? 19 : 20
    ;ConsoleWrite("$DWMWA_USE_IMMERSIVE_DARK_MODE=" & $DWMWA_USE_IMMERSIVE_DARK_MODE & @CRLF)
    ;       DWMWA_USE_IMMERSIVE_DARK_MODE ; https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
    ;       Use with DwmSetWindowAttribute. Allows the window frame for this window to be drawn in dark mode colors when the dark mode system setting is enabled.
    ;       For compatibility reasons, all windows default to light mode regardless of the system setting.
    ;       The pvAttribute parameter points to a value of type BOOL. TRUE to honor dark mode for the window, FALSE to always use light mode.
    ;       This value is supported starting with Windows 11 Build 22000.

    Local $iRet = _WinAPI_DwmSetWindowAttribute_unr($hGUI, $DWMWA_USE_IMMERSIVE_DARK_MODE, $bDarkMode)
    If Not $iRet Then Return SetError(1, 0, -1)

    _SetCtrlColorMode($hGUI, $bDarkMode)
    ;_WinAPI_SetWindowTheme_unr(GUICtrlGetHandle($ChbxDrkMode), 0, 0) ; this control needs the theme

EndFunc   ;==>DarkMode
;--------------------------------------------------------------------------------------------------------------------------------
Func _SetCtrlColorMode($hWnd, $bDarkMode = True, $sName = Default)    ; 'Explorer', 'CFD', 'DarkMode_ItemsView', etc.
    If $sName = Default Then $sName = $bDarkMode ? 'DarkMode_Explorer' : 'Explorer'
    $bDarkMode = Not Not $bDarkMode ; https://www.vbforums.com/showthread.php?900444-Windows-10-Dark-Mode-amp-VB6-apps
    If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
    Local Enum $eDefault, $eAllowDark, $eForceDark, $eForceLight, $eMax ; enum PreferredAppMode
    DllCall('uxtheme.dll', 'bool', 133, 'hwnd', $hWnd, 'bool', $bDarkMode) ; fnAllowDarkModeForWindow = 133
    DllCall('uxtheme.dll', 'int', 135, 'int', ($bDarkMode ? $eForceDark : $eForceLight)) ; fnAllowDarkModeForApp = 135
    _WinAPI_SetWindowTheme_unr($hWnd, $sName) ; https://www.autoitscript.com/forum/index.php?showtopic=211475&view=findpost&p=1530103
    DllCall('uxtheme.dll', 'none', 104) ; fnRefreshImmersiveColorPolicyState = 104  ; not needed ?
    _SendMessage($hWnd, $WM_THEMECHANGED, 0, 0) ; not needed ?
EndFunc   ;==>_SetCtrlColorMode
;--------------------------------------------------------------------------------------------------------------------------------
Func _WinAPI_SetWindowTheme_unr($hWnd, $sName = Null, $sList = Null)  ; #include <WinAPITheme.au3> ; unthoughtful unrestricting mod.
    ;Causes a window to use a different set of visual style information than its class normally uses
    Local $sResult = DllCall('UxTheme.dll', 'long', 'SetWindowTheme', 'hwnd', $hWnd, 'wstr', $sName, 'wstr', $sList)
    If @error Then Return SetError(@error, @extended, 0)
    If $sResult[0] Then Return SetError(10, $sResult[0], 0)
    Return 1
EndFunc   ;==>_WinAPI_SetWindowTheme_unr
;--------------------------------------------------------------------------------------------------------------------------------
Func _WinAPI_DwmSetWindowAttribute_unr($hWnd, $iAttribute, $iData)    ; #include <WinAPIGdi.au3> ; unthoughtful unrestricting mod.
    ;Sets the value of the specified attributes for non-client rendering to apply to the window
    Local $aCall = DllCall('dwmapi.dll', 'long', 'DwmSetWindowAttribute', 'hwnd', $hWnd, 'dword', $iAttribute, _
            'dword*', $iData, 'dword', 4)
    If @error Then Return SetError(@error, @extended, 0)
    If $aCall[0] Then Return SetError(10, $aCall[0], 0)
    Return 1
EndFunc   ;==>_WinAPI_DwmSetWindowAttribute_unr
;--------------------------------------------------------------------------------------------------------------------------------

 

  • Solution
Posted (edited)

my effort to learn

#include <GUIConstantsEx.au3>
#include <GuiHeader.au3>
#include <WinAPI.au3>

; === Global Variables and Constants ===
Global $g_hGUI, $g_hHeader
Global $g_hOldGUIProc = 0 ; Storage for the original GUI Window pointer.
Global $g_hGUISubclass
Global Const $CLR_WHITE = 0xFFFFFF ; The text color

; Structure Definitions (using $tagNMHDR and $tagRECT which are defined in includes)
Global Const $tagNMCUSTOMDRAW = $tagNMHDR & ";dword DrawStage;handle hdc;" & $tagRECT & ";dword_ptr ItemSpec;uint ItemState;lparam lItemParam;"


Example()

Func Example()
    ; Create a GUI with various controls.
    $g_hGUI = GUICreate("Dark Mode Header", 400, 400)

    ; Set background color
    GUISetBkColor(0x121212)

    ; dummy button for stealing 1st focus
    GUICtrlCreateButton("dummy", -100, 0, 10, 10)

    ; create header
    $g_hHeader = _GUICtrlHeader_Create($g_hGUI)
    For $i = 0 To 2
        _GUICtrlHeader_AddItem($g_hHeader, "Column" & $i, 80)
    Next

    ; apply dark mode to GUI and header
    DarkMode($g_hGUI, True)
    _WinAPI_SetWindowTheme_unr($g_hHeader, 'DarkMode_ItemsView', 'Header')

    ; === SUBCLASSING THE PARENT GUI ===
    ; Register the callback function to intercept WM_NOTIFY messages from the header.
    $g_hGUISubclass = DllCallbackRegister("_GUISubclass", "ptr", "hwnd;uint;wparam;lparam")

    ; Subclass the Parent GUI window (using the built-in $GWL_WNDPROC).
    $g_hOldGUIProc = _WinAPI_SetWindowLong($g_hGUI, $GWL_WNDPROC, DllCallbackGetPtr($g_hGUISubclass))
    ; --------------------------------------

    ; Display the GUI.
    GUISetState(@SW_SHOW, $g_hGUI)

    ; Loop until the user exits.
    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop
        EndSwitch
    WEnd

    ; Restore the original window procedure and free Dll resources before exiting.
    _WinAPI_SetWindowLong($g_hGUI, $GWL_WNDPROC, $g_hOldGUIProc)
    DllCallbackFree($g_hGUISubclass)

    ; Delete the previous GUI and all controls.
    GUIDelete($g_hGUI)
EndFunc   ;==>Example


; Intercepts WM_NOTIFY messages from the Header control to set the text color for dark mode.
Func _GUISubclass($hWnd, $iMsg, $wParam, $lParam)
    ; Check if the message is WM_NOTIFY
    If $iMsg = $WM_NOTIFY Then
        Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam)

        ; Check if the notification is from the Header control AND is a Custom Draw message.
        If $tNMHDR.hwndfrom = $g_hHeader And $tNMHDR.code = $NM_CUSTOMDRAW Then
            Local $tNMCustomDraw = DllStructCreate($tagNMCUSTOMDRAW, $lParam)

            ; STEP 1: Intercept Pre-Paint (Value 1). Request item notifications.
            If $tNMCustomDraw.DrawStage = $CDDS_PREPAINT Then
                Return $CDRF_NOTIFYITEMDRAW ; Tell the system to send CDDS_ITEMPREPAINT next.
            EndIf

            ; STEP 2: Intercept Item Pre-Paint (Value 65537). Set the text color.
            If BitAND($tNMCustomDraw.DrawStage, $CDDS_ITEMPREPAINT) Then
                ; Set the text color to white
                _WinAPI_SetTextColor($tNMCustomDraw.hdc, $CLR_WHITE)

                ; Tell the system to use the new font settings and continue.
                Return $CDRF_NEWFONT
            EndIf
        EndIf
    EndIf

    ; Pass the message to the original Window Procedure
    Return _WinAPI_CallWindowProc($g_hOldGUIProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>_GUISubclass

;--------------------------------------------------------------------------------------------------------------------------------
Func DarkMode($hGUI, $bDarkMode = True)                                ; DarkMode
    ; Sets the main GUI window to use immersive dark mode.
    Local Enum $DWMWA_USE_IMMERSIVE_DARK_MODE = (@OSBuild <= 18985) ? 19 : 20

    Local $iRet = _WinAPI_DwmSetWindowAttribute_unr($hGUI, $DWMWA_USE_IMMERSIVE_DARK_MODE, $bDarkMode)
    If Not $iRet Then Return SetError(1, 0, -1)

    _SetCtrlColorMode($hGUI, $bDarkMode)
EndFunc   ;==>DarkMode
;--------------------------------------------------------------------------------------------------------------------------------
Func _SetCtrlColorMode($hWnd, $bDarkMode = True, $sName = Default)     ; 'Explorer', 'CFD', 'DarkMode_ItemsView', etc.
    ; Helper function to apply dark mode theme to controls within the window.
    If $sName = Default Then $sName = $bDarkMode ? 'DarkMode_Explorer' : 'Explorer'
    $bDarkMode = Not Not $bDarkMode
    If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
    Local Enum $eDefault, $eAllowDark, $eForceDark, $eForceLight, $eMax ; enum PreferredAppMode
    DllCall('uxtheme.dll', 'bool', 133, 'hwnd', $hWnd, 'bool', $bDarkMode) ; fnAllowDarkModeForWindow = 133
    DllCall('uxtheme.dll', 'int', 135, 'int', ($bDarkMode ? $eForceDark : $eForceLight)) ; fnAllowDarkModeForApp = 135
    _WinAPI_SetWindowTheme_unr($hWnd, $sName)
    DllCall('uxtheme.dll', 'none', 104) ; fnRefreshImmersiveColorPolicyState = 104
    _SendMessage($hWnd, $WM_THEMECHANGED, 0, 0)
EndFunc   ;==>_SetCtrlColorMode
;--------------------------------------------------------------------------------------------------------------------------------
Func _WinAPI_SetWindowTheme_unr($hWnd, $sName = Null, $sList = Null)
    ; Causes a window to use a different set of visual style information than its class normally uses
    Local $sResult = DllCall('UxTheme.dll', 'long', 'SetWindowTheme', 'hwnd', $hWnd, 'wstr', $sName, 'wstr', $sList)
    If @error Then Return SetError(@error, @extended, 0)
    If $sResult[0] Then Return SetError(10, $sResult[0], 0)
    Return 1
EndFunc   ;==>_WinAPI_SetWindowTheme_unr
;--------------------------------------------------------------------------------------------------------------------------------
Func _WinAPI_DwmSetWindowAttribute_unr($hWnd, $iAttribute, $iData)
    ; Sets the value of the specified attributes for non-client rendering to apply to the window
    Local $aCall = DllCall('dwmapi.dll', 'long', 'DwmSetWindowAttribute', 'hwnd', $hWnd, 'dword', $iAttribute, _
            'dword*', $iData, 'dword', 4)
    If @error Then Return SetError(@error, @extended, 0)
    If $aCall[0] Then Return SetError(10, $aCall[0], 0)
    Return 1
EndFunc   ;==>_WinAPI_DwmSetWindowAttribute_unr
;--------------------------------------------------------------------------------------------------------------------------------

 

Edited by ioa747
remove extra #include

I know that I know nothing

Posted
29 minutes ago, ioa747 said:

my effort to learn

This is phenomenal work. And for my own learning part of this process, your comments every step of the way throughout your example is extremely beneficial. I've read the code comments but I'm going to go through it a few more times to make sure that I take in all of the complex details.

Thank you for your help and for your time. I appreciate it. :)

Posted (edited)

simplification to GUIRegisterMsg

#include <GUIConstantsEx.au3>
#include <GuiHeader.au3>
#include <WinAPI.au3>

; === Global Variables and Constants ===
Global $g_hGUI, $g_hHeader
Global Const $CLR_WHITE = 0xFFFFFF ; The text color

; Structure Definitions (using $tagNMHDR and $tagRECT which are defined in includes)
Global Const $tagNMCUSTOMDRAW = $tagNMHDR & ";dword DrawStage;handle hdc;" & $tagRECT & ";dword_ptr ItemSpec;uint ItemState;lparam lItemParam;"

Example()

Func Example()
    ; Create a GUI with various controls.
    $g_hGUI = GUICreate("Dark Mode Header", 400, 400)

    ; Set background color
    GUISetBkColor(0x121212)

    ; dummy button for stealing 1st focus
    GUICtrlCreateButton("dummy", -100, 0, 10, 10)

    ; create header
    $g_hHeader = _GUICtrlHeader_Create($g_hGUI)
    For $i = 0 To 2
        _GUICtrlHeader_AddItem($g_hHeader, "Column" & $i, 80)
    Next

    ; apply dark mode to GUI and header
    DarkMode($g_hGUI, True)
    _WinAPI_SetWindowTheme_unr($g_hHeader, 'DarkMode_ItemsView', 'Header')

    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY_Handler")

    ; Display the GUI.
    GUISetState(@SW_SHOW, $g_hGUI)

    ; Loop until the user exits.
    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop
        EndSwitch
    WEnd

    ; Delete the previous GUI and all controls.
    GUIDelete($g_hGUI)
EndFunc   ;==>Example

Func WM_NOTIFY_Handler($hWnd, $iMsg, $wParam, $lParam)
    ; Check if the message is WM_NOTIFY
    If $iMsg = $WM_NOTIFY Then
        Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam)

        ; === HEADER LOGIC ===
        If $tNMHDR.hwndfrom = $g_hHeader And $tNMHDR.code = $NM_CUSTOMDRAW Then
            Local $tNMCustomDraw = DllStructCreate($tagNMCUSTOMDRAW, $lParam)

            ; STEP 1 (CDDS_PREPAINT): Request item notifications.
            If $tNMCustomDraw.DrawStage = $CDDS_PREPAINT Then
                Return $CDRF_NOTIFYITEMDRAW
            EndIf

            ; STEP 2 (CDDS_ITEMPREPAINT): Set text color.
            If BitAND($tNMCustomDraw.DrawStage, $CDDS_ITEMPREPAINT) Then
                ; Set the text color to white
                _WinAPI_SetTextColor($tNMCustomDraw.hdc, $CLR_WHITE)

                ; Tell the system to use the new font settings and continue.
                Return $CDRF_NEWFONT
            EndIf

        EndIf

        ; === LISTVIEW LOGIC ===
        ;...

    EndIf

    ; Pass all other messages to the default window procedure.
    Return $GUI_RUNDEFMSG
EndFunc ;==>WM_NOTIFY_Handler

;--------------------------------------------------------------------------------------------------------------------------------
Func DarkMode($hGUI, $bDarkMode = True)                                ; DarkMode
    ; Sets the main GUI window to use immersive dark mode.
    Local Enum $DWMWA_USE_IMMERSIVE_DARK_MODE = (@OSBuild <= 18985) ? 19 : 20

    Local $iRet = _WinAPI_DwmSetWindowAttribute_unr($hGUI, $DWMWA_USE_IMMERSIVE_DARK_MODE, $bDarkMode)
    If Not $iRet Then Return SetError(1, 0, -1)

    _SetCtrlColorMode($hGUI, $bDarkMode)
EndFunc   ;==>DarkMode
;--------------------------------------------------------------------------------------------------------------------------------
Func _SetCtrlColorMode($hWnd, $bDarkMode = True, $sName = Default)     ; 'Explorer', 'CFD', 'DarkMode_ItemsView', etc.
    ; Helper function to apply dark mode theme to controls within the window.
    If $sName = Default Then $sName = $bDarkMode ? 'DarkMode_Explorer' : 'Explorer'
    $bDarkMode = Not Not $bDarkMode
    If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
    Local Enum $eDefault, $eAllowDark, $eForceDark, $eForceLight, $eMax ; enum PreferredAppMode
    DllCall('uxtheme.dll', 'bool', 133, 'hwnd', $hWnd, 'bool', $bDarkMode) ; fnAllowDarkModeForWindow = 133
    DllCall('uxtheme.dll', 'int', 135, 'int', ($bDarkMode ? $eForceDark : $eForceLight)) ; fnAllowDarkModeForApp = 135
    _WinAPI_SetWindowTheme_unr($hWnd, $sName)
    DllCall('uxtheme.dll', 'none', 104) ; fnRefreshImmersiveColorPolicyState = 104
    _SendMessage($hWnd, $WM_THEMECHANGED, 0, 0)
EndFunc   ;==>_SetCtrlColorMode
;--------------------------------------------------------------------------------------------------------------------------------
Func _WinAPI_SetWindowTheme_unr($hWnd, $sName = Null, $sList = Null)
    ; Causes a window to use a different set of visual style information than its class normally uses
    Local $sResult = DllCall('UxTheme.dll', 'long', 'SetWindowTheme', 'hwnd', $hWnd, 'wstr', $sName, 'wstr', $sList)
    If @error Then Return SetError(@error, @extended, 0)
    If $sResult[0] Then Return SetError(10, $sResult[0], 0)
    Return 1
EndFunc   ;==>_WinAPI_SetWindowTheme_unr
;--------------------------------------------------------------------------------------------------------------------------------
Func _WinAPI_DwmSetWindowAttribute_unr($hWnd, $iAttribute, $iData)
    ; Sets the value of the specified attributes for non-client rendering to apply to the window
    Local $aCall = DllCall('dwmapi.dll', 'long', 'DwmSetWindowAttribute', 'hwnd', $hWnd, 'dword', $iAttribute, _
            'dword*', $iData, 'dword', 4)
    If @error Then Return SetError(@error, @extended, 0)
    If $aCall[0] Then Return SetError(10, $aCall[0], 0)
    Return 1
EndFunc   ;==>_WinAPI_DwmSetWindowAttribute_unr
;--------------------------------------------------------------------------------------------------------------------------------

 

Edited by ioa747

I know that I know nothing

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...