Jump to content

Recommended Posts

Posted
3 minutes ago, WildByDesign said:

Is it more efficient to continuously check registry or check _WinAPI_ShouldAppsUseDarkMode?
Whichever is most efficient is likely what we should go with.
What is the best (safest) way to do this? AdlibRegister? _Timer_SetTimer?

..none of that is needed nor advised.
There is a broadcast. Am busy at the moment so I can't jump to an answer, but the constant reading is not a welcomed answer to the task.
Look into WM_SETTINGCHANGE

AI example ( not tested ) :

#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
#include <WinAPISys.au3>

; Create a dummy GUI to catch broadcasted messages
Local $hGUI = GUICreate("ThemeListener")
GUIRegisterMsg($WM_SETTINGCHANGE, "WM_SETTINGCHANGE")

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

Func WM_SETTINGCHANGE($hWnd, $iMsg, $wParam, $lParam)
    ; lParam is a pointer to a string indicating what changed
    Local $tString = DllStructCreate("wchar[256]", $lParam)
    Local $sParam = DllStructGetData($tString, 1)

    ; "ImmersiveColorSet" indicates a Light/Dark mode change
    If $sParam = "ImmersiveColorSet" Then
        Local $iMode = RegRead("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", "AppsUseLightTheme")
        If $iMode = 0 Then
            ConsoleWrite("System switched to DARK mode" & @CRLF)
        Else
            ConsoleWrite("System switched to LIGHT mode" & @CRLF)
        EndIf
    EndIf
    
    Return $GUI_RUNDEFMSG
EndFunc

 

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting  image.gif.922e3a93535f431de08b31ee669cc446.gif
autoit_scripter_blue_userbar.png

Posted (edited)
2 hours ago, argumentum said:

Look into WM_SETTINGCHANGE

https://learn.microsoft.com/en-us/windows/win32/winmsg/wm-settingchange

 

When we talk about GLOBAL PENS I meant exactly that when you say about it here:

I note that you was mention WM_THEMECHANGED instead WM_SETTINGCHANGE

I thought WM_THEMECHANGED is fired when theme is changed in the environment out of the window.



Reading:
https://learn.microsoft.com/en-us/windows/win32/winmsg/wm-themechanged

Quote

Broadcast to every window following a theme change event. Examples of theme change events are the activation of a theme, the deactivation of a theme, or a transition from one theme to another.

I think It is what you are looking for but maybe I'm wrong?

Let me know what you mean about those 2 messages.

 

btw.

I think you should also read:

https://learn.microsoft.com/en-us/windows/win32/api/uxtheme/nf-uxtheme-isthemeactive

https://learn.microsoft.com/en-us/windows/win32/api/uxtheme/nf-uxtheme-openthemedata

https://learn.microsoft.com/en-us/windows/win32/api/uxtheme/nf-uxtheme-closethemedata

 

Edited by mLipok

Signature beginning:
Please remember: "AutoIt"..... *  Wondering who uses AutoIt and what it can be used for ? * Forum Rules *
ADO.au3 UDF * POP3.au3 UDF * XML.au3 UDF * IE on Windows 11 * How to ask ChatGPT for AutoIt Codefor other useful stuff click the following button:

Spoiler

Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind. 

My contribution (my own projects): * Debenu Quick PDF Library - UDF * Debenu PDF Viewer SDK - UDF * Acrobat Reader - ActiveX Viewer * UDF for PDFCreator v1.x.x * XZip - UDF * AppCompatFlags UDF * CrowdinAPI UDF * _WinMergeCompare2Files() * _JavaExceptionAdd() * _IsBeta() * Writing DPI Awareness App - workaround * _AutoIt_RequiredVersion() * Chilkatsoft.au3 UDF * TeamViewer.au3 UDF * JavaManagement UDF * VIES over SOAP * WinSCP UDF * GHAPI UDF - modest begining - comunication with GitHub REST APIErrorLog.au3 UDF - A logging Library * Include Dependency Tree (Tool for analyzing script relations) * Show_Macro_Values.au3 *

 

My contribution to others projects or UDF based on  others projects: * _sql.au3 UDF  * POP3.au3 UDF *  RTF Printer - UDF * XML.au3 UDF * ADO.au3 UDF SMTP Mailer UDF * Dual Monitor resolution detection * * 2GUI on Dual Monitor System * _SciLexer.au3 UDF * SciTE - Lexer for console pane

Useful links: * Forum Rules * Forum etiquette *  Forum Information and FAQs * How to post code on the forum * AutoIt Online Documentation * AutoIt Online Beta Documentation * SciTE4AutoIt3 getting started * Convert text blocks to AutoIt code * Games made in Autoit * Programming related sites * Polish AutoIt Tutorial * DllCall Code Generator * 

Wiki: Expand your knowledge - AutoIt Wiki * Collection of User Defined Functions * How to use HelpFile * Good coding practices in AutoIt * 

OpenOffice/LibreOffice/XLS Related: WriterDemo.au3 * XLS/MDB from scratch with ADOX

IE Related:  * How to use IE.au3  UDF with  AutoIt v3.3.14.x * Why isn't Autoit able to click a Javascript Dialog? * Clicking javascript button with no ID * IE document >> save as MHT file * IETab Switcher (by LarsJ ) * HTML Entities * _IEquerySelectorAll() (by uncommon) * IE in TaskSchedulerIE Embedded Control Versioning (use IE9+ and HTML5 in a GUI) * PDF Related:How to get reference to PDF object embeded in IE * IE on Windows 11

I encourage you to read: * Global Vars * Best Coding Practices * Please explain code used in Help file for several File functions * OOP-like approach in AutoIt * UDF-Spec Questions *  EXAMPLE: How To Catch ConsoleWrite() output to a file or to CMD *

I also encourage you to check awesome @trancexx code:  * Create COM objects from modules without any demand on user to register anything. * Another COM object registering stuffOnHungApp handlerAvoid "AutoIt Error" message box in unknown errors  * HTML editor

winhttp.au3 related : * https://www.autoitscript.com/forum/topic/206771-winhttpau3-download-problem-youre-speaking-plain-http-to-an-ssl-enabled-server-port/

"Homo sum; humani nil a me alienum puto" - Publius Terentius Afer
"Program are meant to be read by humans and only incidentally for computers and execute" - Donald Knuth, "The Art of Computer Programming"
:naughty:  :ranting:, be  :) and       \\//_.

Anticipating Errors :  "Any program that accepts data from a user must include code to validate that data before sending it to the data store. You cannot rely on the data store, ...., or even your programming language to notify you of problems. You must check every byte entered by your users, making sure that data is the correct type for its field and that required fields are not empty."

Signature last update: 2023-04-24

Posted (edited)
18 minutes ago, mLipok said:

I note that you was mention WM_THEMECHANGED instead WM_SETTINGCHANGE
I thought WM_THEMECHANGED is fired when theme is changed in the environment out of the window.

yes and yes, but since I don't have the time to know for sure ( because that'd mean that I tested ), am throwing ideas.
WM_THEMECHANGED should be the one but if that didn't work, then maybe WM_SETTINGCHANGE is another option.
WM_SETTINGCHANGE will trigger more often but if the parameter we're interested on is the same, no action should be taken.
That's a heck of a lot better than Adlib a RegRead :D 

There is another one before WM_THEMECHANGED  too. In WM_THEMECHANGED, I'd place an Adlib 500 ms. to actually do the work, because they trigger a few in a row when it triggers.

Edited by argumentum
more

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting  image.gif.922e3a93535f431de08b31ee669cc446.gif
autoit_scripter_blue_userbar.png

Posted
2 hours ago, argumentum said:

AI example ( not tested ) :

I just got a chance to test it now. WM_SETTINGCHANGE with lParam value of ImmersiveColorSet is exactly what we need. The example works wonderfully. :)

25 minutes ago, mLipok said:

I think It is what you are looking for but maybe I'm wrong?

The WM_THEMECHANGED message only works for full theme changes. It would mean changing the default Aero theme to some other theme or vice versa. It does not trigger for simply changing between dark mode and light mode. From what I've read, WM_SETTINGCHANGE with lParam value of ImmersiveColorSet is needed on Win10/11.

27 minutes ago, mLipok said:

Thank you. I will check these out. :)

 

Posted

AllowDarkModeForWindowWithParentFallback

New function in recent Windows 11 builds.
bAutoThemeChange- it will automatically switch the controls whenever theme change happens between light and dark mode.

typedef bool (WINAPI* AllowDarkModeForWindowWithParentFallback_t)(HWND, bool bAutoThemeChange); // ordinal 145

To apply to all controls, just call AllowDarkModeForWindowWithParentFallback on the main HWND

AllowDarkModeForWindowWithParentFallback(hWnd, TRUE);

All supported controls will automatically get dark mode.

 

Is there anyone that can make an AutoIt _WinAPI function for the new Win11 function?

Posted
6 minutes ago, WildByDesign said:

To apply to all controls, just call AllowDarkModeForWindowWithParentFallback on the main HWND

AllowDarkModeForWindowWithParentFallback(hWnd, TRUE);

All supported controls will automatically get dark mode.

 

Is there anyone that can make an AutoIt _WinAPI function for the new Win11 function?

It looks promising.
There will be a need to test how this act for MDI and any child window.

 

Signature beginning:
Please remember: "AutoIt"..... *  Wondering who uses AutoIt and what it can be used for ? * Forum Rules *
ADO.au3 UDF * POP3.au3 UDF * XML.au3 UDF * IE on Windows 11 * How to ask ChatGPT for AutoIt Codefor other useful stuff click the following button:

Spoiler

Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind. 

My contribution (my own projects): * Debenu Quick PDF Library - UDF * Debenu PDF Viewer SDK - UDF * Acrobat Reader - ActiveX Viewer * UDF for PDFCreator v1.x.x * XZip - UDF * AppCompatFlags UDF * CrowdinAPI UDF * _WinMergeCompare2Files() * _JavaExceptionAdd() * _IsBeta() * Writing DPI Awareness App - workaround * _AutoIt_RequiredVersion() * Chilkatsoft.au3 UDF * TeamViewer.au3 UDF * JavaManagement UDF * VIES over SOAP * WinSCP UDF * GHAPI UDF - modest begining - comunication with GitHub REST APIErrorLog.au3 UDF - A logging Library * Include Dependency Tree (Tool for analyzing script relations) * Show_Macro_Values.au3 *

 

My contribution to others projects or UDF based on  others projects: * _sql.au3 UDF  * POP3.au3 UDF *  RTF Printer - UDF * XML.au3 UDF * ADO.au3 UDF SMTP Mailer UDF * Dual Monitor resolution detection * * 2GUI on Dual Monitor System * _SciLexer.au3 UDF * SciTE - Lexer for console pane

Useful links: * Forum Rules * Forum etiquette *  Forum Information and FAQs * How to post code on the forum * AutoIt Online Documentation * AutoIt Online Beta Documentation * SciTE4AutoIt3 getting started * Convert text blocks to AutoIt code * Games made in Autoit * Programming related sites * Polish AutoIt Tutorial * DllCall Code Generator * 

Wiki: Expand your knowledge - AutoIt Wiki * Collection of User Defined Functions * How to use HelpFile * Good coding practices in AutoIt * 

OpenOffice/LibreOffice/XLS Related: WriterDemo.au3 * XLS/MDB from scratch with ADOX

IE Related:  * How to use IE.au3  UDF with  AutoIt v3.3.14.x * Why isn't Autoit able to click a Javascript Dialog? * Clicking javascript button with no ID * IE document >> save as MHT file * IETab Switcher (by LarsJ ) * HTML Entities * _IEquerySelectorAll() (by uncommon) * IE in TaskSchedulerIE Embedded Control Versioning (use IE9+ and HTML5 in a GUI) * PDF Related:How to get reference to PDF object embeded in IE * IE on Windows 11

I encourage you to read: * Global Vars * Best Coding Practices * Please explain code used in Help file for several File functions * OOP-like approach in AutoIt * UDF-Spec Questions *  EXAMPLE: How To Catch ConsoleWrite() output to a file or to CMD *

I also encourage you to check awesome @trancexx code:  * Create COM objects from modules without any demand on user to register anything. * Another COM object registering stuffOnHungApp handlerAvoid "AutoIt Error" message box in unknown errors  * HTML editor

winhttp.au3 related : * https://www.autoitscript.com/forum/topic/206771-winhttpau3-download-problem-youre-speaking-plain-http-to-an-ssl-enabled-server-port/

"Homo sum; humani nil a me alienum puto" - Publius Terentius Afer
"Program are meant to be read by humans and only incidentally for computers and execute" - Donald Knuth, "The Art of Computer Programming"
:naughty:  :ranting:, be  :) and       \\//_.

Anticipating Errors :  "Any program that accepts data from a user must include code to validate that data before sending it to the data store. You cannot rely on the data store, ...., or even your programming language to notify you of problems. You must check every byte entered by your users, making sure that data is the correct type for its field and that required fields are not empty."

Signature last update: 2023-04-24

Posted
14 minutes ago, WildByDesign said:

New function in recent Windows 11 builds.
bAutoThemeChange- it will automatically switch the controls whenever theme change happens between light and dark mode.

559928100-ca1856af-869b-46a4-aaa5-ba3caa

...not too sure that is worth it because is not all that well put together. Also, no support for older versions like the one we have already.
Status bar and tabs still not there....

I would let it go until mature. My 2 cents.

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting  image.gif.922e3a93535f431de08b31ee669cc446.gif
autoit_scripter_blue_userbar.png

Posted
10 minutes ago, argumentum said:

...not too sure that is worth it because is not all that well put together. Also, no support for older versions like the one we have already.
Status bar and tabs still not there....

That is not good. Yuck. I would much rather be able to continue to have things working well for all Win10/11 users.

Thanks to the help of many users of this community, with the various subclassed controls and more, in my opinion, I believe that what we have is already much better than what Microsoft provides.

Posted

@argumentum I'm getting multiple hits on the WM_SETTINGCHANGE function each time I switch color modes. This would fire off the theme switching function multiple times in quick succession. Can you please check this?

Func WM_SETTINGCHANGE($hWnd, $iMsg, $wParam, $lParam)
    ; lParam is a pointer to a string indicating what changed
    Local $tString = DllStructCreate("wchar[256]", $lParam)
    Local $sParam = DllStructGetData($tString, 1)
    Local Static $iModePrev

    ; "ImmersiveColorSet" indicates a Light/Dark mode change
    If $sParam = "ImmersiveColorSet" Then
        Local $iMode = RegRead("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", "AppsUseLightTheme")
        If $iModePrev <> $iMode Then
            $iModePrev = $iMode
        Else
            Return
        EndIf
        If $iMode = 0 Then
            ConsoleWrite("System switched to DARK mode" & @CRLF)
        Else
            ConsoleWrite("System switched to LIGHT mode" & @CRLF)
        EndIf
    EndIf
    
    Return $GUI_RUNDEFMSG
EndFunc

I added the Static for $iMode to avoid multiple hits:

Local $iMode = RegRead("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", "AppsUseLightTheme")
If $iModePrev <> $iMode Then
    $iModePrev = $iMode
Else
    Return
EndIf

It seems to work perfectly from my own testing. No more multiple hits in a row.

Question: Do I need to convert $iMode to Boolean or just leave it as is?

Posted (edited)

I'm trying to come up with a logical approach for dealing with Static (label) controls in the UDF. Those controls can be a bit more personal and have custom colors, as we see in the Sample GUI with the green background for the Green Label. Simply inverting colors is not appropriate for this. In the Sample GUI, I have to fix the colors for some Static controls after any theme changes.

I have an idea (concept) that I have been thinking about for a few weeks now but I need some help.

For the purpose of easily sharing a single file back and forth for anyone wanting to help, I am using/modifying the SampleControls.au3 in Dark Mode by @UEZ. The part that I am messing around with is the _WM_CTLCOLOR() function which is subclassed using  GUIRegisterMsg($WM_CTLCOLORSTATIC, "_WM_CTLCOLOR") in the example.

My current testing addition in that function (which also has comments about the idea/concept) is the following:

; Testing area for Static (label) control ==========================================================================================
    ;
    ; Not Working: _WinAPI_GetTextColor, _WinAPI_GetBkColor and _WinAPI_GetBkMode giving incorrect return values?
    ; IDEA:
    ;   - If TextColor = 0x000000 or 0xFFFFFF, invert and set inverted color
    ;   - If TextColor <> 0x000000 or 0xFFFFFF, leave color as is since it is likely customized for a reason
    ;   - If BkColor = 0x000000 or 0xFFFFFF, invert and set inverted color
    ;   - If BkColor <> 0x000000 or 0xFFFFFF, leave color as is since it is likely customized for a reason
    ;   - Can we detect fill (brush) color currently in use? Pixel color? Can we get pixel color if window is not yet visible?
    ;   - If fill (brush) color <> 0x000000 or 0xFFFFFF, leave brush color since it is likely custom (eg. green background of $g_hLabelGreen)
    ;   - Possibly use NULL_BRUSH for transparent background if fill (brush) color = 0x000000 or 0xFFFFFF
    If _WinAPI_GetClassName($hCtrl) = "Static" Then
        ConsoleWrite("TextColor: " & "0x" & Hex(_WinAPI_GetTextColor($hDC), 6) & @CRLF)
        ConsoleWrite("BkColor:   " & "0x" & Hex(_WinAPI_GetBkColor($hDC), 6) & @CRLF)
        ConsoleWrite("BkMode:    " & _WinAPI_GetBkMode($hDC) & @CRLF)
        ConsoleWrite(" " & @CRLF)
    EndIf
    ;
    ; Testing area for Static (label) control ==========================================================================================

The biggest problem that I am having is that _WinAPI_GetTextColor, _WinAPI_GetBkColor and _WinAPI_GetBkMode are giving incorrect return values from what I can tell. If I don't get the correct colors, then I cannot make a determination on what should be done with the color.

Anyway, here is the full testing script that includes my little addition from above:

Unfortunately I do not have enough attachment space in forum to add as attachment. My easier way to copy/paste a large chunk of code in this forum is to click "popup" and then Ctrl+A to Select All and Ctrl+C to copy. I used to do the whole mouse drag thing here in the forum but not fun for larger code examples.

; Coded by UEZ / WildByDesign build 2026-04-28 beta
; Should be DPI aware
#cs
+----------------------+------------------------------------------+-------------------------+
| Theme Name           | Suitable for                             | From Windows            |
+----------------------+------------------------------------------+-------------------------+
| DarkMode_Explorer    | Button, Scrollbar, Slider, TreeView,     | Win10 1809 (Build 17763)|
|                      | ListView, UpDown, Spinner                |                         |
+----------------------+------------------------------------------+-------------------------+
| DarkMode_CFD         | Edit, ComboBox (incl. child Edit)        | Win10 1809 (Build 17763)|
+----------------------+------------------------------------------+-------------------------+
| DarkMode_DarkTheme   | Checkbox, RadioButton, GroupBox          | Win10 1809 (Build 17763)|
+----------------------+------------------------------------------+-------------------------+
| DarkMode_ItemsView   | ListView Header (SysHeader32)            | Win10 1903 (Build 18362)|
+----------------------+------------------------------------------+-------------------------+
| DarkMode_CopyEngine  | ProgressBar                              | Win10 1809 (Build 17763)|
+----------------------+------------------------------------------+-------------------------+
| DarkMode_NormalDark  | general use, rarely needed               | Win10 1809 (Build 17763)|
+----------------------+------------------------------------------+-------------------------+
#ce

#include <Array.au3>
#include <APIConstants.au3>
#include <AVIConstants.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <GuiDateTimePicker.au3>
#include <GuiImageList.au3>
#include <GuiMenu.au3>
#include <GuiMonthCal.au3>
#include <GuiScrollBars.au3>
#include <GuiStatusBar.au3>
#include <GuiTab.au3>
#include <GuiTreeView.au3>
#include <ListViewConstants.au3>
#include <Timers.au3>
#include <TreeViewConstants.au3>
#include <WinAPIConstants.au3>
#include <WinAPIGdi.au3>
#include <WinAPIProc.au3>
#include <WinAPIRes.au3>
#include <WinAPIShellEx.au3>
#include <WinAPISys.au3>
#include <WinAPISysWin.au3>
#include <WinAPITheme.au3>
#include <WindowsConstants.au3>

#Region DPI Constants
;https://learn.microsoft.com/en-us/windows/win32/api/windef/ne-windef-dpi_awareness
Global Enum $DPI_AWARENESS_INVALID = -1, $DPI_AWARENESS_UNAWARE = 0, $DPI_AWARENESS_SYSTEM_AWARE = 1, $DPI_AWARENESS_PER_MONITOR_AWARE = 2

;https://learn.microsoft.com/en-us/windows/win32/hidpi/dpi-awareness-context
Global Const $DPI_AWARENESS_CONTEXT_UNAWARE = $DPI_AWARENESS_UNAWARE - 1
Global Const $DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = $DPI_AWARENESS_UNAWARE - 2
Global Const $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = $DPI_AWARENESS_UNAWARE - 3
Global Const $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = $DPI_AWARENESS_UNAWARE - 4
Global Const $DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED = $DPI_AWARENESS_UNAWARE - 5

;enum _MONITOR_DPI_TYPE
Global Enum $MDT_EFFECTIVE_DPI = 0, $MDT_ANGULAR_DPI, $MDT_RAW_DPI
Global Const $MDT_DEFAULT = $MDT_EFFECTIVE_DPI

;Windows Message Codes
Global Const $WM_DPICHANGED = 0x02E0, $WM_DPICHANGED_BEFOREPARENT = 0x02E2, $WM_DPICHANGED_AFTERPARENT = 0x02E3, $WM_GETDPISCALEDSIZE = 0x02E4


;DpiChangeBehavior
Global Const $DDC_DEFAULT = 0
Global Const $DDC_DISABLE_ALL = 1
Global Const $DDC_DISABLE_RESIZE = 2
Global Const $DDC_DISABLE_CONTROL_RELAYOUT = 4

Global Const $DCDC_DEFAULT = 0
Global Const $DCDC_DISABLE_FONT_UPDATE = 1
Global Const $DCDC_DISABLE_RELAYOUT = 2
#EndRegion DPI Constants

Enum $IHCM_USE_CACHED_VALUE, $IHCM_REFRESH
Enum $APPMODE_DEFAULT = 0, $APPMODE_ALLOWDARK, $APPMODE_FORCEDARK, $APPMODE_FORCELIGHT, $APPMODE_MAX
Const $PRF_CLIENT = 0x04
Const $ODS_HOTLIGHT = 0x0040
Const $TCM_SETBKCOLOR = 0x132D
Const $fDefFontSize = 8.5, $fDefPixel = $fDefFontSize * 96 / 72 ; 8.5pt * 96/72 = ~11.33px

; Dark Mode Colors (RGB) - used throughout WM_CTLCOLOR, custom draw, and GDI painting
Global Const $COLOR_BG_DARK = 0x202020        ; main window background
Global Const $COLOR_TEXT_LIGHT = 0xF0F0F0     ; default text color
Global Const $COLOR_CONTROL_BG = 0x2B2B2B     ; generic control background
Global Const $COLOR_EDIT_BG = 0x1E1E1E        ; edit/list background
Global Const $COLOR_BUTTON_BG = 0x333333      ; button / selected tab background
Global Const $COLOR_BORDER = 0x3F3F3F         ; subtle border (edit, listbox, tab)
Global Const $COLOR_BORDER2 = 0xA0A0A0        ; brighter border (checkbox outline)
Global Const $COLOR_HOTTRACK_MENU = 0x3A3A3A  ; menu item hover highlight
Global Const $COLOR_BORDER_LIGHT = 0xB0B0B0   ; bright border on hover (date control)
Global Const $COLOR_MENU_SELECT = 0x505050    ; color selecting menu
Global Const $COLOR_TAB_ACCENT = 0x0078D4
Global Const $COLOR_TAB_ACCENT_LIGHT = 0x60CDFF
Global Const $COLOR_TITLE_DARK = 0x181818

; Global variables for subclassing (MUST be declared before _Example()!)
Global $g_hGUI = 0, $g_hTab, $g_ListView
Global $g_aControls[150][3] = [[0, 0, 0]] ; [ControlID, hWnd, OldWndProc]
Global $g_aCtrlDPI[150][7] = [[0, 0, 0, 0, 0, 0, ""]]  ; [CtrlID, xpos, ypos, w, h, fontsize, fontname]
Global $g_iControlCount = 0, $g_iCtrlCountDPI = 0
Global $g_pSubclassProc = 0

; Global brushes for _WM_CTLCOLOR (avoids memory leaks)
Global $g_hBrushEdit = 0
Global $g_hBrushButton = 0
Global $g_hBrushBg = 0
Global $g_hBrushGreen
Global $g_hLabelGreen = 0, $g_idLabelGreen
Global $g_idLabelPic, $g_hLabelPic
Global $g_idInput, $g_idUpDown, $g_hUpDown
Global $g_hMenu = 0, $g_hMenu1, $g_hMenu2, $g_hMenuFont = 0
Global $g_idDate = 0, $g_hDate = 0
Global $g_hTreeView2 = 0

; Global variable for tab subclassing
Global $g_hTab_CB, $g_pTab_CB, $g_hProc

; Global variable for SysDateTimePick32 subclassing
Global $g_hDateProc_CB, $g_pDateProc_CB, $g_hDateOldProc

; 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)

Global $g_aMenuText = []        ; top-level menu texts (populated by _MakeMenuOwnerDraw)
Global $arMenuItems[1][8]       ; owner-draw menu item data
$arMenuItems[0][0] = 0
Global $arSideItems[1][10]      ; side/context menu item data
$arSideItems[0][0] = 0

Const $ODT_MENU = 1
Const $ODS_SELECTED = 0x0001
Const $ODS_DISABLED = 0x0004

Global Enum $idAbout = 5000
Global $g_hMenu_Sys, $g_idAboutMenu, $g_AboutDummy, $g_hStatusbar
Global $g_bHover = False

Const $HCBT_CREATEWND = 3, $HCBT_DESTROYWND = 4, $HCBT_ACTIVATE = 5, $g_iFlagDefault = BitOR($MB_TOPMOST, $MB_ICONINFORMATION)
Global $g_hMsgBoxHook, $g_hSubMsgBox, $g_idTImer, $g_sBtn1_Txt = "Close", $g_sBtn2_Txt, $g_sBtn3_Txt
Global $g_Timeout = 0, $g_hMsgBoxOldProc, $g_hMsgBoxBrush, $g_hMsgBoxBtn = 0, $g_bMsgBoxClosing = False, $g_bNCLButtonDown = False, $g_bMsgBoxInitialized = False
Global $g_hMsgBoxSubProc = DllCallbackRegister("_MsgBoxProc", "lresult", "hwnd;uint;wparam;lparam")


_GDIPlus_Startup()
Global $AWARENESS

; Select DPI awareness level based on OS build:
; Win8.1-Win10 14393: PER_MONITOR_AWARE via Shcore.dll
; Win10 14393+:       PER_MONITOR_AWARE_V2 (full non-client DPI scaling)
; older:              SYSTEM_AWARE fallback
Switch @OSBuild
    Case 9200 To 13999
        $AWARENESS = $DPI_AWARENESS_PER_MONITOR_AWARE
    Case @OSBuild > 13999
        $AWARENESS = $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
    Case Else
        $AWARENESS = $DPI_AWARENESS_SYSTEM_AWARE
EndSwitch

; Set DPI awareness and retrieve current DPI (96 = 100%)
Global $g_iDPI = _WinAPI_SetDPIAwareness($AWARENESS), $aPos

Global $g_fScale = $g_iDPI / 96.0, $g_aStatusbarParts[4] = [75, 150, 300, 400], $g_hCtrlFont = 0, $g_aCustomFonts[0]

_Example()
_GDIPlus_Shutdown()

Func _Example()
    ; Create global brushes
    $g_hBrushEdit = _WinAPI_CreateSolidBrush(_ColorToCOLORREF($COLOR_EDIT_BG))
    $g_hBrushButton = _WinAPI_CreateSolidBrush(_ColorToCOLORREF($COLOR_BUTTON_BG))
    $g_hBrushBg = _WinAPI_CreateSolidBrush(_ColorToCOLORREF($COLOR_BG_DARK))
    Local $sAutoitExample = StringRegExpReplace(@AutoItExe, "\\[^\\]+$", "") & "\Examples\GUI"
    
    #Region GUI
    $g_hGUI = GUICreate("Sample GUI with Dark Mode", 400 * $g_fScale, 424 * $g_fScale)
    GUISetIcon(@SystemDir & "\mspaint.exe", 0)
    GUISetBkColor($COLOR_BG_DARK, $g_hGUI)

    $g_hMenu_Sys = _GUICtrlMenu_GetSystemMenu($g_hGUI)
    _GUICtrlMenu_AppendMenu($g_hMenu_Sys, $MF_SEPARATOR, 0, 0)
    _GUICtrlMenu_AppendMenu($g_hMenu_Sys, $MF_STRING, $idAbout, "About")

    ; Register GUI-level WM_CTLCOLOR messages
    GUIRegisterMsg($WM_CTLCOLOREDIT, "_WM_CTLCOLOR")
    GUIRegisterMsg($WM_CTLCOLORLISTBOX, "_WM_CTLCOLOR")
    GUIRegisterMsg($WM_CTLCOLORBTN, "_WM_CTLCOLOR")
    GUIRegisterMsg($WM_CTLCOLORSTATIC, "_WM_CTLCOLOR")
    GUIRegisterMsg($WM_MEASUREITEM, "_WM_MEASUREITEM")
    GUIRegisterMsg($WM_DRAWITEM, "_WM_DRAWITEM")
    GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY")
    GUIRegisterMsg($WM_ACTIVATE, "_WM_ACTIVATE")
    GUIRegisterMsg($WM_WINDOWPOSCHANGED, "_WM_WINDOWPOSCHANGED")
    GUIRegisterMsg($WM_MENUCOMMAND, "_WM_MENUCOMMAND")
    GUIRegisterMsg($WM_SYSCOMMAND, "_WM_SYSCOMMAND")
    GUIRegisterMsg($WM_DPICHANGED, "_WM_DPICHANGED")
    #EndRegion GUI

    #Region MENU
    Global $g_aMenuText[4]
    $g_aMenuText[0] = "Menu &One"
    $g_aMenuText[1] = "Menu &Two"
    $g_aMenuText[2] = "Menu Th&ree"
    $g_aMenuText[3] = "Menu &Four"

    Local $idMenu1 = GUICtrlCreateMenu($g_aMenuText[0])
    Local $idMenu2 = GUICtrlCreateMenu($g_aMenuText[1])
    GUICtrlCreateMenu($g_aMenuText[2])
    GUICtrlCreateMenu($g_aMenuText[3])
    GUICtrlCreateMenuItem("SubMenu One &A", $idMenu1)
    GUICtrlCreateMenuItem("SubMenu One &B", $idMenu1)
    $g_idAboutMenu = GUICtrlCreateMenuItem("About", $idMenu1)
    $g_hMenu1 = GUICtrlGetHandle($idMenu1)
    $g_hMenu2 = GUICtrlGetHandle($idMenu2)

    ; Owner-draw Top-Level Menu creation
    _CreateMenuFont($g_fScale)
    _MakeMenuOwnerDraw($g_hGUI)
    _EnableMenuHotTrack($g_hMenu)
    #EndRegion MENU

    #Region CONTEXT MENU
    Local $idContextMenu = GUICtrlCreateContextMenu()
    GUICtrlCreateMenuItem("Context Menu", $idContextMenu)
    GUICtrlCreateMenuItem("", $idContextMenu)
    GUICtrlCreateMenuItem("&Properties", $idContextMenu)
    #EndRegion CONTEXT MENU

    #Region PIC
    Local $idPic = GUICtrlCreatePic("", 0, 2, 169, 68)
    GUICtrlSetImage($idPic, $sAutoitExample & "\logo4.gif")
    GUICtrlSetTip(-1, "#Region PIC")
    _AddControlForDPI($idPic, 0, 2, 169, 68, 0, "")
    $g_idLabelPic = GUICtrlCreateLabel("Sample Pic", 75, 1, 63, 15)
    $g_hLabelPic = GUICtrlGetHandle($g_idLabelPic)
    _AddControlForDPI($g_idLabelPic, 75, 1, 63, 15)
    #EndRegion PIC

    #Region AVI
    Local $idAvi = GUICtrlCreateAvi($sAutoitExample & "\SampleAVI.avi", 0, 184, 12, 32, 32, $ACS_AUTOPLAY)
    GUICtrlSetTip(-1, "#Region AVI")
    _AddControlForDPI($idAvi, 184, 12, 32, 32, 0, "")
    Local $idLabelAvi = GUICtrlCreateLabel("Sample avi", 175, 50)
    $aPos = ControlGetPos($g_hGUI, "", $idLabelAvi)
    _AddControlForDPI($idLabelAvi, 175, 50, $aPos[2], $aPos[3])
    #EndRegion AVI

    #Region TAB
    Local $idTab = GUICtrlCreateTab(240, 2, 150, 70), $g_hTab = GUICtrlGetHandle($idTab)
    _AddControlForSubclass($idTab)
    _AddControlForDPI($idTab, 240, 2, 150, 70)
    
    GUICtrlCreateTabItem("One")
    GUICtrlSetTip(-1, "#Region TAB1")
    Local $idLabelTab = GUICtrlCreateLabel("Sample Tab with TabItems", 250, 40)
    $aPos = ControlGetPos($g_hGUI, "", $idLabelTab)
    _AddControlForDPI($idLabelTab, 250, 40, $aPos[2], $aPos[3])
    
    GUICtrlCreateTabItem("Two")
    GUICtrlSetTip(-1, "#Region TAB2")
    Local $idCheckBoxTab2 = GUICtrlCreateCheckbox("Checkbox", 250, 30, 120, 20)
    GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)
    _AddControlForDPI($idCheckBoxTab2, 250, 30, 120, 20)
    _WinAPI_SetWindowTheme(GUICtrlGetHandle($idCheckBoxTab2), "DarkMode_DarkTheme", 0)
    
    GUICtrlCreateTabItem("Three")
    GUICtrlSetTip(-1, "#Region TAB3")
    
    GUICtrlCreateTabItem("Four")
    GUICtrlSetTip(-1, "#Region TAB4")
        
    GUICtrlCreateTabItem("Five")
    GUICtrlSetTip(-1, "#Region TAB5")
    
    GUICtrlCreateTabItem("")

    #EndRegion TAB

    #Region COMBO
    Local $idCombo = GUICtrlCreateCombo("", 250, 80, 120, 100, $CBS_DROPDOWNLIST)
    GUICtrlSetData($idCombo, "Sample Combo|Item 2|Item 3", "Sample Combo")
    _AddControlForSubclass($idCombo)
    GUICtrlSetTip(-1, "#Region COMBO")
    _AddControlForDPI($idCombo, 250, 80, 120, 100)
    #EndRegion COMBO

    #Region PROGRESS
    Local $idProgress = GUICtrlCreateProgress(60, 80, 150, 20)
;~  _AddControlForSubclass($idProgress)
    GUICtrlSetTip(-1, "#Region PROGRESS")
    GUICtrlSetData(-1, 60)
    _AddControlForDPI($idProgress, 60, 80, 150, 20)
    Local $idLabelProgress = GUICtrlCreateLabel("Progress:", 5, 82, 46, 12)
    _AddControlForDPI($idLabelProgress, 5, 82, 46, 12)
    #EndRegion PROGRESS

    #Region EDIT
    Local $idEdit = GUICtrlCreateEdit(@CRLF & "  Sample Edit Control", 10, 110, 150, 70), $hEditCtrl = GUICtrlGetHandle($idEdit)
    _WinAPI_SetWindowLong($hEditCtrl, $GWL_EXSTYLE, BitAND(_WinAPI_GetWindowLong($hEditCtrl, $GWL_EXSTYLE), BitNOT($WS_EX_CLIENTEDGE)))

    _AddControlForSubclass($idEdit)
    GUICtrlSetTip(-1, "#Region EDIT")
    _AddControlForDPI($idEdit, 10, 110, 150, 70)
    #EndRegion EDIT

    #Region LIST
    Local $idList = GUICtrlCreateList("", 5, 190, 100, 90), $hList = GUICtrlGetHandle($idList)
    _WinAPI_SetWindowLong($hList, $GWL_EXSTYLE, BitAND(_WinAPI_GetWindowLong($hList, $GWL_EXSTYLE), BitNOT($WS_EX_CLIENTEDGE)))
    _AddControlForSubclass($idList)
    GUICtrlSetTip(-1, "#Region LIST")
    GUICtrlSetData(-1, "A.Sample|B.List|C.Control|D.Here", "B.List")
    _AddControlForDPI($idList, 5, 190, 100, 90)
    #EndRegion LIST

    #Region ICON
    Local $idIcon = GUICtrlCreateIcon("explorer.exe", 0, 175, 120)
    GUICtrlSetTip(-1, "#Region ICON")
    _AddControlForDPI($idIcon, 175, 120, 32, 32, 0, "")
    Local $idLabelIcon = GUICtrlCreateLabel("Icon", 180, 160, 50, 20)
    _AddControlForDPI($idLabelIcon, 180, 160, 50, 20)
    #EndRegion ICON

    #Region LIST VIEW
    Local $idListView = GUICtrlCreateListView("Sample|ListView|", 110, 190, 110, 80, $LVS_REPORT)
    _AddControlForSubclass($idListView)
    GUICtrlSetBkColor($idListView, $COLOR_EDIT_BG)
    GUICtrlSetColor($idListView, $COLOR_TEXT_LIGHT)
    GUICtrlSetTip(-1, "#Region LIST VIEW")
    GUICtrlCreateListViewItem("A|One", $idListView)
    GUICtrlCreateListViewItem("B|Two", $idListView)
    GUICtrlCreateListViewItem("C|Three", $idListView)
    $g_ListView = GUICtrlGetHandle($idListView)
    _AddControlForDPI($idListView, 110, 190, 110, 80)
    #EndRegion LIST VIEW

    #Region GROUP WITH RADIO BUTTONS
    Local $idGroup = GUICtrlCreateGroup("Sample Group", 230, 120)
    GUICtrlSetColor($idGroup, $COLOR_TEXT_LIGHT)
    $aPos = ControlGetPos($g_hGUI, "", $idGroup)
    _AddControlForDPI($idGroup, 230, 120, $aPos[2], $aPos[3])
    Local $idRadio1 = GUICtrlCreateRadio("Radio One", 250, 140, 80)
    GUICtrlSetTip($idRadio1, "#Region RADIO1")
    GUICtrlSetState($idRadio1, $GUI_CHECKED)
    $aPos = ControlGetPos($g_hGUI, "", $idRadio1)
    _AddControlForDPI($idRadio1, 250, 140, 80, $aPos[3])
    Local $idRadio2 = GUICtrlCreateRadio("Radio Two", 250, 165, 80)
    GUICtrlSetTip($idRadio2, "#Region RADIO2")
    $aPos = ControlGetPos($g_hGUI, "", $idRadio2)
    _AddControlForDPI($idRadio2, 250, 165, 80, $aPos[3])
    GUICtrlCreateGroup("", -99, -99, 1, 1)
    _WinAPI_SetWindowTheme(GUICtrlGetHandle($idRadio1), "DarkMode_DarkTheme", 0)
    _WinAPI_SetWindowTheme(GUICtrlGetHandle($idRadio2), "DarkMode_DarkTheme", 0)
    _WinAPI_SetWindowTheme(GUICtrlGetHandle($idGroup), "DarkMode_DarkTheme", 0)
    #EndRegion GROUP WITH RADIO BUTTONS

    #Region UPDOWN
    Local $idLabelUpDown = GUICtrlCreateLabel("UpDown", 350, 115)
    GUICtrlSetColor(-1, $COLOR_TEXT_LIGHT)
    $aPos = ControlGetPos($g_hGUI, "", $idLabelUpDown)
    _AddControlForDPI($idLabelUpDown, 350, 115, $aPos[2], $aPos[3])
    $g_idInput = GUICtrlCreateInput("42", 350, 130, 40, 20)
    _AddControlForSubclass($g_idInput)
    _AddControlForDPI($g_idInput, 350, 130, 40, 20)
    $g_idUpDown = GUICtrlCreateUpdown(-1)
    _AddControlForSubclass($g_idUpDown)
    $aPos = ControlGetPos($g_hGUI, "", $g_idUpDown)
    _AddControlForDPI($g_idUpDown, $aPos[0], $aPos[1], $aPos[2], $aPos[3])
    $g_hUpDown = GUICtrlGetHandle($g_idUpDown)
    #EndRegion UPDOWN

    #Region LABEL
    $g_idLabelGreen = GUICtrlCreateLabel("Green" & @CRLF & "Label", 350, 165, 40, 40)
    $g_hLabelGreen = GUICtrlGetHandle($g_idLabelGreen)
    GUICtrlSetTip($g_idLabelGreen, "#Region LABEL")
    $g_hBrushGreen = _WinAPI_CreateSolidBrush(_ColorToCOLORREF(0x00FF00)) ; green background
    _AddControlForDPI($g_idLabelGreen, 350, 165, 40, 40)
    #EndRegion LABEL
    
    #Region SLIDER
    Local $idLabelSlider = GUICtrlCreateLabel("Slider:", 235, 215)
    $aPos = ControlGetPos($g_hGUI, "", $idLabelSlider)
    _AddControlForDPI($idLabelSlider, 235, 215, $aPos[2], $aPos[3])
    Local $idSlider = GUICtrlCreateSlider(270, 210, 120, 30)
    _AddControlForSubclass($idSlider)
    GUICtrlSetTip(-1, "#Region SLIDER")
    GUICtrlSetData(-1, 30)
    _AddControlForDPI($idSlider, 270, 210, 120, 30)
    #EndRegion SLIDER

    #Region INPUT
    Local $idInput2 = GUICtrlCreateInput("Sample Input Box", 235, 255, 130, 20)
    _AddControlForSubclass($idInput2)
    GUICtrlSetTip(-1, "#Region INPUT")
    _AddControlForDPI($idInput2, 235, 255, 130, 20)
    #EndRegion INPUT

    #Region DATE
    $g_idDate = GUICtrlCreateDate("", 5, 280, 200, 20)
    $g_hDate = GUICtrlGetHandle($g_idDate)
    _AddControlForSubclass($g_idDate)
    GUICtrlSetTip(-1, "#Region DATE")
    _AddControlForDPI($g_idDate, 5, 280, 200, 20)
    Local $idLabelDate = GUICtrlCreateLabel("(Date control expands into a calendar)", 10, 305, 200, 20)
    _AddControlForDPI($idLabelDate, 10, 305, 200, 20)
    #EndRegion DATE

    #Region BUTTON
    Local $idButton = GUICtrlCreateButton("Sample Button", 10, 330, 100, 30)
    _AddControlForSubclass($idButton)
    GUICtrlSetTip(-1, "#Region BUTTON")
    _AddControlForDPI($idButton, 10, 330, 100, 30)
    #EndRegion BUTTON

    #Region CHECKBOX
    Local $idCheckBox = GUICtrlCreateCheckbox("Checkbox", 130, 335, 80, 20)
    GUICtrlSetTip(-1, "#Region CHECKBOX")
    GUICtrlSetState(-1, $GUI_CHECKED)
    _WinAPI_SetWindowTheme(GUICtrlGetHandle($idCheckBox), "DarkMode_DarkTheme", 0)
    _AddControlForDPI($idCheckBox, 130, 335, 80, 20)
    #EndRegion CHECKBOX

    #Region TREEVIEW ONE
    Local $idTreeView1 = GUICtrlCreateTreeView(210, 290, 80, 80), $hTreeview1 = GUICtrlGetHandle($idTreeView1)
    _AddControlForSubclass($idTreeView1)
    GUICtrlSetBkColor($idTreeView1, $COLOR_EDIT_BG)
    GUICtrlSetColor($idTreeView1, $COLOR_TEXT_LIGHT)
    GUICtrlSetTip(-1, "#Region TREEVIEW ONE")
    _AddControlForDPI($idTreeView1, 210, 290, 80, 80)
    Local $idTreeViewItem = GUICtrlCreateTreeViewItem("TreeView", $idTreeView1)
    GUICtrlCreateTreeViewItem("Item1", $idTreeViewItem)
    GUICtrlCreateTreeViewItem("Item2", $idTreeViewItem)
    GUICtrlCreateTreeViewItem("Foo", -1)
    GUICtrlSetState($idTreeViewItem, $GUI_EXPAND)
    #EndRegion TREEVIEW ONE

    #Region TREEVIEW TWO
    Local $idTreeView2 = GUICtrlCreateTreeView(295, 290, 103, 80, $TVS_CHECKBOXES)
    _AddControlForSubclass($idTreeView2)
    _AddControlForDPI($idTreeView2, 295, 290, 103, 80)
    GUICtrlSetBkColor($idTreeView2, $COLOR_EDIT_BG)
    GUICtrlSetColor($idTreeView2, $COLOR_TEXT_LIGHT)
    GUICtrlSetTip(-1, "#Region TREEVIEW TWO")
    GUICtrlCreateTreeViewItem("TreeView", $idTreeView2)
    GUICtrlCreateTreeViewItem("With", $idTreeView2)
    GUICtrlCreateTreeViewItem("$TVS_CHECKBOXES", $idTreeView2)
    GUICtrlSetState(-1, $GUI_CHECKED)
    GUICtrlCreateTreeViewItem("Style", $idTreeView2)
    $g_hTreeView2 = GUICtrlGetHandle($idTreeView2)
    _SetDarkTreeViewCheckboxes($g_hTreeView2)
    #EndRegion TREEVIEW TWO

    #Region Statusbar
    $g_hStatusbar = _GUICtrlStatusBar_Create($g_hGUI)
    _AddControlHandleForSubclass($g_hStatusbar)

    _GUICtrlStatusBar_SetParts($g_hStatusbar, $g_aStatusbarParts)
    _GUICtrlStatusBar_SetText($g_hStatusbar, "Part 0", 0)
    _GUICtrlStatusBar_SetText($g_hStatusbar, "Part 1", 1)
    _GUICtrlStatusBar_SetText($g_hStatusbar, "Part 2", 2)
    _GUICtrlStatusBar_SetText($g_hStatusbar, "Part 3", 3)
    $aPos = ControlGetPos($g_hGUI, "", _WinAPI_GetDlgCtrlID($g_hStatusbar))
    _AddControlForDPI(_WinAPI_GetDlgCtrlID($g_hStatusbar), $aPos[0], $aPos[1], $aPos[2], $aPos[3])
    #EndRegion Statusbar

    ; Apply Dark Mode
    _ApplyDarkModeToAllControls()

    ; Handle scrollbars for windows that have them
    _EnableDarkScrollBars()

    ; Register a custom window procedure for the tab control for owner-drawing
    $g_hTab_CB = DllCallbackRegister("_WinProc", "ptr", "hwnd;uint;wparam;lparam")
    $g_pTab_CB = DllCallbackGetPtr($g_hTab_CB)
    $g_hProc = _WinAPI_SetWindowLong($g_hTab, $GWL_WNDPROC, $g_pTab_CB)

    ; Register a custom window procedure for the date control for owner-drawing
    $g_hDateProc_CB = DllCallbackRegister("_DateProc", "ptr", "hwnd;uint;wparam;lparam")
    $g_pDateProc_CB = DllCallbackGetPtr($g_hDateProc_CB)
    $g_hDateOldProc = _WinAPI_SetWindowLong($g_hDate, $GWL_WNDPROC, $g_pDateProc_CB)

    $g_AboutDummy = GUICtrlCreateDummy()
    _ApplyDPIScaling($g_fScale)

    ; Applying dark mode to Tooltips - thanks to WildByDesign
    Local $aData = _WinAPI_EnumProcessWindows(0, False)
    For $i = 1 To $aData[0][0]
        If $aData[$i][1] = "tooltips_class32" Then _WinAPI_SetWindowTheme($aData[$i][0], "DarkMode_Explorer", "ToolTip")
    Next
    
    ; Force initial border draw on all custom-bordered controls
    For $i = 0 To $g_iControlCount - 1
        Local $hCtrl = $g_aControls[$i][1]
        If $hCtrl Then
            Local $sClass = _WinAPI_GetClassName($hCtrl)
            If _IsBorderedControl($sClass) Then
                _WinAPI_SetWindowPos($hCtrl, 0, 0, 0, 0, 0, BitOR($SWP_NOMOVE, $SWP_NOSIZE, $SWP_NOZORDER, $SWP_FRAMECHANGED))
            EndIf
        EndIf
    Next

    GUISetState(@SW_SHOW)

    _OverpaintWhiteLine()
        
    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_RESTORE
;~              _WinAPI_RedrawWindow($g_hGUI, 0, 0, BitOR($RDW_INVALIDATE, $RDW_UPDATENOW))
                _WinAPI_LockWindowUpdate($g_hGUI)
                _ApplyDPIScaling($g_fScale)
                _OverpaintWhiteLine()
                _WinAPI_LockWindowUpdate(0)
            Case $GUI_EVENT_CLOSE
                _CleanupSubclassing()
                _CleanupBrushes()
                ExitLoop
            Case $g_AboutDummy
                MsgBoxEx("Example coded by UEZ :-)", "About", 5)
        EndSwitch
    WEnd
    ; Restore the original window procedure for the tab control
    _WinAPI_SetWindowLong($g_hTab, $GWL_WNDPROC, $g_hProc)
    DllCallbackFree($g_hTab_CB)

    _WinAPI_SetWindowLong($g_hDate, $GWL_WNDPROC, $g_hDateOldProc)
    DllCallbackFree($g_hDateProc_CB)

    GUIDelete()
EndFunc   ;==>_Example

Func _ApplyDPIScaling($fNewScale)
    ; Create new control font BEFORE applying - old font deleted AFTER all controls receive the new one.
    ; This avoids a brief moment where controls hold a deleted font handle (causes tiny/invisible text).
    ; _WinAPI_CreateFont with negative height = character height (matches GUICtrlSetFont point size behavior).
    Local $hOldFont = $g_hCtrlFont
    $g_hCtrlFont = _WinAPI_CreateFont(-Round($fDefPixel * $fNewScale), 0, 0, 0, $FW_NORMAL, False, False, False, _
                                      $DEFAULT_CHARSET, $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $PROOF_QUALITY, $DEFAULT_PITCH, "Arial")

    ; Cleanup previous custom fonts from last DPI pass
    For $j = 0 To UBound($g_aCustomFonts) - 1
        If $g_aCustomFonts[$j] Then _WinAPI_DeleteObject($g_aCustomFonts[$j])
    Next
    ReDim $g_aCustomFonts[0]
    
    _WinAPI_LockWindowUpdate($g_hGUI) ; suppress repaints during bulk repositioning
    
    Local $i, $hCtrl
    For $i = 0 To $g_iCtrlCountDPI - 1
        ; Reposition using logical coordinates - GUICtrlSetPos handles DPI translation internally
        GUICtrlSetPos($g_aCtrlDPI[$i][0], $g_aCtrlDPI[$i][1] * $fNewScale, $g_aCtrlDPI[$i][2] * $fNewScale, _
                      $g_aCtrlDPI[$i][3] * $fNewScale, $g_aCtrlDPI[$i][4] * $fNewScale)
                      
        ; Apply font via WM_SETFONT - bypasses AutoIt's cached DC which would ignore DPI changes
        If $g_aCtrlDPI[$i][5] > 0 Then
            $hCtrl = GUICtrlGetHandle($g_aCtrlDPI[$i][0])
            If $hCtrl Then
                Local $hFont
                If $g_aCtrlDPI[$i][5] = $fDefFontSize And ($g_aCtrlDPI[$i][6] = "" Or $g_aCtrlDPI[$i][6] = "Arial") Then
                    ; standard font - use shared handle
                    $hFont = $g_hCtrlFont
                Else
                    ; custom size/face - create dedicated font scaled to current DPI
                    Local $iH = -Round(_WinAPI_MulDiv($g_aCtrlDPI[$i][5], Round($fNewScale * 96), 72))
                    Local $sName = ($g_aCtrlDPI[$i][6] <> "" ? $g_aCtrlDPI[$i][6] : "Arial")
                    $hFont = _WinAPI_CreateFont($iH, 0, 0, 0, $FW_NORMAL, False, False, False, _
                                                $DEFAULT_CHARSET, $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $PROOF_QUALITY, $DEFAULT_PITCH, $sName)
                    ; track for cleanup on next DPI change
                    ReDim $g_aCustomFonts[UBound($g_aCustomFonts) + 1]
                    $g_aCustomFonts[UBound($g_aCustomFonts) - 1] = $hFont
                EndIf
                _SendMessage($hCtrl, $WM_SETFONT, $hFont, True)
            EndIf
        EndIf
    Next

    ; UpDown buddy positioning is controlled by Windows - override manually after scaling
    If $g_idInput And $g_idUpDown Then
        Local $tPos = ControlGetPos($g_hGUI, "", $g_idInput)
        If IsArray($tPos) Then
            ; Place UpDown directly to the right of the Input, same height
            Local $iUpDownW = _WinAPI_GetSystemMetricsForDpi($SM_CXVSCROLL, Round($g_fScale * 96))
            _WinAPI_MoveWindow($g_hUpDown, $tPos[0] + $tPos[2], $tPos[1], $iUpDownW, $tPos[3], True)
        EndIf
    EndIf

    _WinAPI_LockWindowUpdate(0)
    _WinAPI_RedrawWindow($g_hGUI, 0, 0, BitOR($RDW_INVALIDATE, $RDW_UPDATENOW))

    ; Safe to delete old font now - all controls already hold the new handle
    If $hOldFont Then _WinAPI_DeleteObject($hOldFont)
EndFunc   ;==>_ApplyDPIScaling

Func _CreateMenuFont($fScale = 1.0, $sFontName = "Arial")
    ; Creates the owner-draw menu font at the correct pixel size for the current DPI.
    ; Uses MulDiv(8.5pt, DPI, 72) for accurate point-to-pixel conversion.
    ; Called once at startup; DPI changes recreate the font inline in _WM_DPICHANGED.
    If $g_hMenuFont Then _WinAPI_DeleteObject($g_hMenuFont)
    Local $iHeight = -Round(_WinAPI_MulDiv($fDefFontSize, $g_iDPI, 72))
    $g_hMenuFont = _WinAPI_CreateFont($iHeight, 0, 0, 0, $FW_NORMAL, False, False, False, $DEFAULT_CHARSET, $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $PROOF_QUALITY, $DEFAULT_PITCH, $sFontName)
EndFunc   ;==>_CreateMenuFont

Func _GDIPlus_DrawRoundRect($hGfx, $iX, $iY, $iW, $iH, $iDiameter, $iBrushARGB, $iPenARGB, $fPenWidth = 1.0)
    Local Const $hPath = _GDIPlus_PathCreate()

    ; Top-left arc
    _GDIPlus_PathAddArc($hPath, $iX, $iY, $iDiameter, $iDiameter, 180, 90)
    ; Top-right arc
    _GDIPlus_PathAddArc($hPath, $iX + $iW - $iDiameter, $iY, $iDiameter, $iDiameter, 270, 90)
    ; Bottom-right arc
    _GDIPlus_PathAddArc($hPath, $iX + $iW - $iDiameter, $iY + $iH - $iDiameter, $iDiameter, $iDiameter, 0, 90)
    ; Bottom-left arc
    _GDIPlus_PathAddArc($hPath, $iX, $iY + $iH - $iDiameter, $iDiameter, $iDiameter, 90, 90)

    _GDIPlus_PathCloseFigure($hPath)

    If $iBrushARGB <> 0 Then
        Local Const $hBrush = _GDIPlus_BrushCreateSolid($iBrushARGB)
        _GDIPlus_GraphicsFillPath($hGfx, $hPath, $hBrush)
        _GDIPlus_BrushDispose($hBrush)
    EndIf

    If $iPenARGB <> 0 Then
        Local Const $hPen = _GDIPlus_PenCreate($iPenARGB, $fPenWidth)
        _GDIPlus_GraphicsDrawPath($hGfx, $hPath, $hPen)
        _GDIPlus_PenDispose($hPen)
    EndIf

    _GDIPlus_PathDispose($hPath)
EndFunc   ;==>_GDIPlus_DrawRoundRect

Func _SetDarkTreeViewCheckboxesGDIp($hTreeView, $iW = 16, $iH = 16)
    Local $hImageList = _GUIImageList_Create($iW, $iH, 5, 3)

    Local $hBmp = _GDIPlus_BitmapCreateFromScan0($iW, $iH)
    Local $hGfx = _GDIPlus_ImageGetGraphicsContext($hBmp)
    _GDIPlus_GraphicsSetSmoothingMode($hGfx, $GDIP_SMOOTHINGMODE_HIGHQUALITY)

    ; --- Index 0: Unchecked ---
    _GDIPlus_GraphicsClear($hGfx, 0xFF000000 + $COLOR_EDIT_BG)
    _GDIPlus_DrawRoundRect($hGfx, 2 / 16 * $iW, 2 / 16 * $iH, 12 / 16 * $iW, 12 / 16 * $iH, 3, 0, 0xFF000000 + $COLOR_BORDER2, 1.5)

    Local $hBmp_GDI = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBmp, 0)
    _GUIImageList_Add($hImageList, $hBmp_GDI)
    _WinAPI_DeleteObject($hBmp_GDI)

    ; --- Index 1: Checked ---
    _GDIPlus_GraphicsClear($hGfx, 0xFF000000 + $COLOR_EDIT_BG)
    _GDIPlus_DrawRoundRect($hGfx, 2 / 16 * $iW, 2 / 16 * $iH, 12 / 16 * $iW, 12 / 16 * $iH, 3, 0xFF60CDFF, 0xFF60CDFF, 1.0)

    Local $hCheckPen = _GDIPlus_PenCreate(0xFF0F2028, 1.5)
    _GDIPlus_GraphicsDrawLine($hGfx, 5 / 16 * $iW, 8 / 16 * $iH, 7 / 16 * $iW, 10 / 16 * $iH, $hCheckPen)
    _GDIPlus_GraphicsDrawLine($hGfx, 7 / 16 * $iW, 10 / 16 * $iH, 11 / 16 * $iW, 6 / 16 * $iH, $hCheckPen)

    $hBmp_GDI = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBmp, 0)
    _GUIImageList_Add($hImageList, $hBmp_GDI)
    _WinAPI_DeleteObject($hBmp_GDI)

    ; --- Cleanup ---
    _GDIPlus_PenDispose($hCheckPen)
    _GDIPlus_GraphicsDispose($hGfx)
    _GDIPlus_ImageDispose($hBmp)
    _GUICtrlTreeView_SetStateImageList($hTreeView, $hImageList)

    Return True
EndFunc   ;==>_SetDarkTreeViewCheckboxesGDIp

Func _SetDarkTreeViewCheckboxes($hTreeView, $iW = 16, $iH = 16)
    _GUICtrlTreeView_SetStateImageList($hTreeView, 0)
    Local $hImageList = _GUIImageList_Create($iW, $iH, 5, 3)

    Local $hBmp_GDI = _WinAPI_ExtractThemeBackground($g_hGUI, 2) ;thanks to WildByDesign for the idea!
    _GUIImageList_Add($hImageList, $hBmp_GDI)
    _WinAPI_DeleteObject($hBmp_GDI)

    $hBmp_GDI = _WinAPI_ExtractThemeBackground($g_hGUI, 5)
    _GUIImageList_Add($hImageList, $hBmp_GDI)
    _WinAPI_DeleteObject($hBmp_GDI)

    _GUICtrlTreeView_SetStateImageList($hTreeView, $hImageList)

    Return True
EndFunc   ;==>_SetDarkTreeViewCheckboxes

Func _WinAPI_ExtractThemeBackground($hGUI, $iState, $iPart = 3, $iWidth = 16, $iHeight = 16)
    Local $hTheme = _WinAPI_OpenThemeData($hGUI, "DarkMode_DarkTheme::Button")
    If @error Then Return SetError(1, 0, 0)
    Local $hDC = _WinAPI_GetDC($hGUI)
    Local $hHBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iWidth, $iHeight)
    Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC)
    Local $hObjOld = _WinAPI_SelectObject($hMemDC, $hHBitmap)
    Local $tRECT = _WinAPI_CreateRectEx(0, 0, $iWidth, $iHeight)
    _WinAPI_DrawThemeBackground($hTheme, $iPart, $iState, $hMemDC, $tRECT)
    If @error Then
        _WinAPI_CloseThemeData($hTheme)
        Return SetError(2, 0, 0)
    EndIf
    _WinAPI_SelectObject($hMemDC, $hObjOld)
    _WinAPI_ReleaseDC($hGUI, $hDC)
    _WinAPI_DeleteDC($hMemDC)
    _WinAPI_CloseThemeData($hTheme)
    Return $hHBitmap
EndFunc   ;==>_WinAPI_ExtractThemeBackground

Func _EnableMenuHotTrack($hMenu)
    If Not $hMenu Then Return False

    Local $tagMENUINFO = "dword cbSize;dword fMask;dword dwStyle;uint cyMax;handle hbrBack;dword dwContextHelpID;ulong_ptr dwMenuData"

    Local Const $MIM_STYLE = 0x00000010
    Local Const $MNS_HOTTRACK = 0x08000000

    Local $tMI = DllStructCreate($tagMENUINFO)
    With $tMI
        .cbSize = DllStructGetSize($tMI)
        .fMask = $MIM_STYLE
        .dwStyle = $MNS_HOTTRACK
    EndWith

    _GUICtrlMenu_SetMenuInfo($hMenu, $tMI)

    ; redraw menus
    _GUICtrlMenu_DrawMenuBar($g_hGUI)
    Return True
EndFunc   ;==>_EnableMenuHotTrack

Func _OverpaintWhiteLine() ;original code by ahmet
    ; The bright artifact line sits exactly 1px above the client area top edge.
    ; Instead of computing caption+border+menu heights manually (DPI-fragile),
    ; we locate the client rect in window coordinates and paint 1px above it.

    ; Get client rect and convert from client to screen coordinates
    Local $rcClient = _WinAPI_GetClientRect($g_hGUI)
    DllCall("user32.dll", "int", "MapWindowPoints", _       ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapwindowpoints
                                 "hwnd", $g_hGUI, _      ; source: client coords
                                 "hwnd", 0, _            ; target: screen coords
                                 "ptr", DllStructGetPtr($rcClient), _
                                 "uint", 2)              ; 2 points = RECT
    If @error Then Return SetError(1, 0, 0)

    ; Make client rect window-relative (subtract window origin)
    Local Const $rcWindow = _WinAPI_GetWindowRect($g_hGUI)
    _WinAPI_OffsetRect($rcClient, -$rcWindow.left, -$rcWindow.top)

    ; Build a 1px-high rect just above the client area top - that's the artifact line
    Local $rcAnnoyingLine = DllStructCreate($tagRECT)
    With $rcAnnoyingLine
        .left   = $rcClient.left
        .right  = $rcClient.right
        .top    = $rcClient.top - 1  ; top = 1px above client
        .bottom = $rcClient.top      ; bottom = client top
    EndWith

    ; GetDCEx with DCX_WINDOW grants access to the non-client area
    ; DCX_INTERSECTRGN limits drawing to the provided region (full window here)
    Local Const $hRgn = _WinAPI_CreateRectRgn(-20000, -20000, 20000, 20000)
    Local $aDC = DllCall("user32.dll", "handle", "GetDCEx", _
                                       "hwnd", $g_hGUI, "handle", $hRgn, _
                                       "dword", BitOR($DCX_WINDOW, $DCX_INTERSECTRGN))
    
    If @error Or Not IsArray($aDC) Then Return SetError(2, 0, 0)
    Local Const $hBrush = _WinAPI_CreateSolidBrush(_ColorToCOLORREF($COLOR_BG_DARK))
    _WinAPI_FillRect($aDC[0], $rcAnnoyingLine, $hBrush)
    _WinAPI_ReleaseDC($g_hGUI, $aDC[0])
    _WinAPI_DeleteObject($hBrush)
    Return 1
EndFunc   ;==>_OverpaintWhiteLine

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

; Registers a control for DPI-aware repositioning.
; Base coordinates (x, y, w, h) are at 100% DPI - _ApplyDPIScaling multiplies them by $g_fScale.
; fontsize > 0 triggers WM_SETFONT with the shared $g_hCtrlFont on each DPI change.
Func _AddControlForDPI($iCtrlID, $x, $y, $w, $h, $fontsize = $fDefFontSize, $fontname = "Arial")
    If $iCtrlID Then
        $g_aCtrlDPI[$g_iCtrlCountDPI][0] = $iCtrlID
        $g_aCtrlDPI[$g_iCtrlCountDPI][1] = $x
        $g_aCtrlDPI[$g_iCtrlCountDPI][2] = $y
        $g_aCtrlDPI[$g_iCtrlCountDPI][3] = $w
        $g_aCtrlDPI[$g_iCtrlCountDPI][4] = $h
        $g_aCtrlDPI[$g_iCtrlCountDPI][5] = $fontsize
        $g_aCtrlDPI[$g_iCtrlCountDPI][6] = $fontname
        $g_iCtrlCountDPI += 1
    EndIf
EndFunc   ;==>_AddControlForDPI

; Registers a control (by AutoIt ControlID) for dark mode subclassing and theming.
Func _AddControlForSubclass($iCtrlID)
    Local $hCtrl = GUICtrlGetHandle($iCtrlID)
    If $hCtrl Then
        $g_aControls[$g_iControlCount][0] = $iCtrlID
        $g_aControls[$g_iControlCount][1] = $hCtrl
        $g_aControls[$g_iControlCount][2] = 0 ; reserved for old WndProc (not used with SetWindowSubclass)
        $g_iControlCount += 1
    EndIf
EndFunc   ;==>_AddControlForSubclass

; Registers a control (by HWND, e.g. native controls not created via GUICtrlCreate) for subclassing.
Func _AddControlHandleForSubclass($hCtrl)
    If $hCtrl Then
        $g_aControls[$g_iControlCount][0] = 0
        $g_aControls[$g_iControlCount][1] = $hCtrl
        $g_aControls[$g_iControlCount][2] = 0
        $g_iControlCount += 1
    EndIf
EndFunc   ;==>_AddControlHandleForSubclass

Func _ApplyDarkModeToAllControls()
    ; DWM Dark Mode for the main window
    _WinAPI_SetPreferredAppMode($APPMODE_FORCEDARK)

    ; Create subclass callback
    If Not $g_pSubclassProc Then $g_pSubclassProc = DllCallbackRegister("_SubclassProc", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr")

    ; Subclass all controls
    Local $hCtrl, $sClass, $hEdit, $hComboLBox, $hHeader, $hUpDown
    For $i = 0 To $g_iControlCount - 1
        $hCtrl = $g_aControls[$i][1]
        If $hCtrl Then
            $sClass = _WinAPI_GetClassName($hCtrl)
            ; Use SetWindowSubclass
            _WinAPI_SetWindowSubclass($hCtrl, DllCallbackGetPtr($g_pSubclassProc), $i, 0)

            ; Special themes for different control types
            Switch $sClass
                Case "edit", "richedit", "richedit20a", "richedit20w"
                    _WinAPI_SetWindowTheme($hCtrl, "DarkMode_CFD", 0)
                Case "button"
                    _WinAPI_SetWindowTheme($hCtrl, "DarkMode_Explorer", 0)
                Case "combobox"
                    _WinAPI_SetWindowTheme($hCtrl, "DarkMode_CFD", 0)
                    ; Handle ComboBox child-edit
                    $hEdit = _WinAPI_FindWindowEx($hCtrl, "Edit")
                    If $hEdit Then
                        _WinAPI_SetWindowTheme($hEdit, "DarkMode_CFD", 0)
                        _WinAPI_AllowDarkModeForWindow($hEdit, True)
                    EndIf
                    ; ComboBox dropdown list
                    $hComboLBox = _WinAPI_FindWindowEx($hCtrl, "ComboLBox")
                    If $hComboLBox Then
                        _WinAPI_SetWindowTheme($hComboLBox, "DarkMode_Explorer", 0)
                        _WinAPI_AllowDarkModeForWindow($hComboLBox, True)
                    EndIf
                Case "syslistview32"
                    _WinAPI_SetWindowTheme($hCtrl, "DarkMode_Explorer", 0)
                    ; Enable double-buffering to prevent flicker during owner-draw
                    _SendMessage($hCtrl, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_DOUBLEBUFFER, $LVS_EX_DOUBLEBUFFER)
                    ; Apply dark theme to the ListView header control
                    $hHeader = _SendMessage($hCtrl, $LVM_GETHEADER, 0, 0)
                    If $hHeader Then
                        _WinAPI_SetWindowTheme($hHeader, "DarkMode_ItemsView", 0)
                    EndIf
                Case "systreeview32"
                    _WinAPI_SetWindowTheme($hCtrl, "DarkMode_Explorer", 0)
                Case "msctls_trackbar32" ; Slider
                    _WinAPI_SetWindowTheme($hCtrl, "DarkMode_Explorer", 0)
                Case "systabcontrol32"
                    _WinAPI_SetWindowTheme($hCtrl, "DarkMode_Explorer", "") ;must be ""
                    ; tab-Control background
                    _SendMessage($hCtrl, $TCM_SETBKCOLOR, 0, $COLOR_BG_DARK)
                    ; Try to make the UpDown (spinner for too many tabs) dark as well
                    $hUpDown = _WinAPI_FindWindowEx($hCtrl, "msctls_updown32")
                    If $hUpDown Then _WinAPI_SetWindowTheme($hUpDown, "DarkMode_Explorer", 0)
                Case "listbox"
                    _WinAPI_SetWindowTheme($hCtrl, "DarkMode_Explorer", 0)
                Case "msctls_progress32"
                    _WinAPI_SetWindowTheme($hCtrl, "DarkMode_CopyEngine", 0)
                Case "scrollbar"
                    _WinAPI_SetWindowTheme($hCtrl, "DarkMode_Explorer", 0)
                Case "sysdatetimepick32"
;~                  ConsoleWrite(_WinAPI_SetWindowTheme($hCtrl, "Explorer", 0) & @CRLF)
;~                  _WinAPI_AllowDarkModeForWindow($hCtrl, True)
                Case "msctls_statusbar32"
                    _WinAPI_SetWindowTheme($hCtrl, "DarkMode_DarkTheme", 0)
                Case Else
                    _WinAPI_SetWindowTheme($hCtrl, "DarkMode_Explorer", 0)
            EndSwitch

            _WinAPI_AllowDarkModeForWindow($hCtrl, True)
        EndIf
    Next

    ; Update theme system
    _WinAPI_RefreshImmersiveColorPolicyState()
    _WinAPI_FlushMenuThemes()
    _WinAPI_DwmSetWindowAttribute($g_hGUI, $DWMWA_USE_IMMERSIVE_DARK_MODE, True)

    ; Redraw GUI
    _WinAPI_RedrawWindow($g_hGUI, 0, 0, $RDW_UPDATENOW)
EndFunc   ;==>_ApplyDarkModeToAllControls

Func _CleanupSubclassing()
    ; Remove all subclasses
    If $g_pSubclassProc Then
        Local $hCtrl
        For $i = 0 To $g_iControlCount - 1
            $hCtrl = $g_aControls[$i][1]
            If $hCtrl Then
                _WinAPI_RemoveWindowSubclass($hCtrl, DllCallbackGetPtr($g_pSubclassProc), $i)
            EndIf
        Next
        DllCallbackFree($g_pSubclassProc)
        $g_pSubclassProc = 0
    EndIf
EndFunc   ;==>_CleanupSubclassing

Func _IsBorderedControl($sClass)
    Return ($sClass = "edit" Or $sClass = "listbox" Or $sClass = "syslistview32" Or $sClass = "systreeview32" Or $sClass = "combobox")
EndFunc   ;==>_IsBorderedControl

Func _PaintSizeBox($hWnd, $hDC)
    Local $iWinStyle = _WinAPI_GetWindowLong($hWnd, $GWL_STYLE)
    
    ; Only proceed if both horizontal and vertical scrollbars are active
    If Not (BitAND($iWinStyle, $WS_HSCROLL) And BitAND($iWinStyle, $WS_VSCROLL)) Then Return False

    ; 1. Retrieve exact Window and Client dimensions
    Local $tRW = _WinAPI_GetWindowRect($hWnd)
    Local $tRC = _WinAPI_GetClientRect($hWnd)
    
    ; 2. Map Client coordinates to Window-DC space
    Local $tPoint = DllStructCreate($tagPOINT)
    $tPoint.X = 0
    $tPoint.Y = 0
    _WinAPI_ClientToScreen($hWnd, $tPoint)

    ; Calculate border offsets
    Local $iOffL = $tPoint.X - $tRW.Left
    Local $iOffT = $tPoint.Y - $tRW.Top
    
    ; Calculate total window dimensions
    Local $iWinW = $tRW.Right - $tRW.Left
    Local $iWinH = $tRW.Bottom - $tRW.Top

    ; 3. Define the SizeBox Rect
    Local $tCorner = DllStructCreate($tagRECT)
    
    ; LEFT/TOP: Start exactly where the client area ends (scrollbar junction)
    $tCorner.Left   = $iOffL + $tRC.Right
    $tCorner.Top    = $iOffT + $tRC.Bottom
    
    ; RIGHT/BOTTOM: Align with the inner edge of the window border.
    $tCorner.Right  = $iWinW - $iOffL
    $tCorner.Bottom = $iWinH - $iOffT
    
    ; Adjust for ListView the size of the box
    If _WinAPI_GetClassName($hWnd) = "SysListView32" Then
        $tCorner.Right  += 1
        $tCorner.Bottom += 1
    EndIf

    ; 4. Paint the box using the dark theme color
    Local $hBrush = _WinAPI_CreateSolidBrush(_ColorToCOLORREF($COLOR_TITLE_DARK))
    _WinAPI_FillRect($hDC, $tCorner, $hBrush)
    _WinAPI_DeleteObject($hBrush)

    Return True
EndFunc   ;==>_PaintSizeBox

Func _SubclassProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData)
    Switch $iMsg
        Case $WM_NOTIFY
            Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
            Local $hFrom = $tNMHDR.hWndFrom
            Local $iCode = $tNMHDR.Code
            If $iCode = $NM_CUSTOMDRAW Then
                Local $tNMCD = DllStructCreate($tagNMCUSTOMDRAW, $lParam)
                Local $dwStage = $tNMCD.dwDrawStage
                Local $hDC = $tNMCD.hdc
                Switch _WinAPI_GetClassName($hFrom)
                    Case "sysheader32"
                        Switch $dwStage
                            Case $CDDS_PREPAINT
                                Return $CDRF_NOTIFYITEMDRAW
                            Case $CDDS_ITEMPREPAINT
                                _WinAPI_SetTextColor($hDC, _ColorToCOLORREF($COLOR_TEXT_LIGHT))
                                _WinAPI_SetBkColor($hDC, _ColorToCOLORREF($COLOR_BG_DARK))
                                Return BitOR($CDRF_NEWFONT, $CDRF_NOTIFYPOSTPAINT)
                        EndSwitch
                EndSwitch
            EndIf

        Case $WM_PAINT
            Local $sClass = _WinAPI_GetClassName($hWnd)
            If $sClass = "syslistview32" Or $sClass = "systreeview32" Or $sClass = "edit" Then
                Local $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
                Local $iWinStyle = _WinAPI_GetWindowLong($hWnd, $GWL_STYLE)
                If BitAND($iWinStyle, $WS_HSCROLL) And BitAND($iWinStyle, $WS_VSCROLL) Then
                    Local $hDC = _WinAPI_GetWindowDC($hWnd)
                    _PaintSizeBox($hWnd, $hDC)
                    _WinAPI_ReleaseDC($hWnd, $hDC)
                EndIf
                Return $iRet
            Else
                Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
            EndIf

        Case $WM_NCPAINT
            ; WS_EX_CLIENTEDGE border is drawn in WM_NCPAINT (non-client area), not WM_CTLCOLOR.
            ; We let Windows draw the default frame first, then overdraw it with our dark border.
            Local $sClass = _WinAPI_GetClassName($hWnd)
            If _IsBorderedControl($sClass) Then
                Local $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
                Local $hDC = _WinAPI_GetWindowDC($hWnd)
                Local $tRECT = _WinAPI_GetWindowRect($hWnd)
                Local $iW = $tRECT.Right - $tRECT.Left
                Local $iH = $tRECT.Bottom - $tRECT.Top
                Local $iBorderColor = (_WinAPI_GetFocus() = $hWnd) ? $COLOR_BORDER_LIGHT : $COLOR_BORDER
                Local $hPen = _WinAPI_CreatePen(0, 1, _ColorToCOLORREF($iBorderColor))
                Local $hOldPen = _WinAPI_SelectObject($hDC, $hPen)
                Local $hNull = _WinAPI_GetStockObject(5)
                Local $hOldBr = _WinAPI_SelectObject($hDC, $hNull)
                DllCall("gdi32.dll", "bool", "Rectangle", "handle", $hDC, "int", 0, "int", 0, "int", $iW, "int", $iH)
                _WinAPI_SelectObject($hDC, $hOldPen)
                _WinAPI_SelectObject($hDC, $hOldBr)
                _WinAPI_DeleteObject($hPen)
                _PaintSizeBox($hWnd, $hDC)
                _WinAPI_ReleaseDC($hWnd, $hDC)
                Return $iRet
            EndIf

        Case $WM_NCMOUSEMOVE
            ; Scrollbar hot-tracking animates via WM_TIMER and paints the sizebox directly,
            ; bypassing both WM_PAINT and WM_NCPAINT.  Re-stamp the corner on every NC mouse
            ; move so the dark fill is never lost while the cursor is over the control.
            Local $sClass = _WinAPI_GetClassName($hWnd)
            If $sClass = "edit" Or $sClass = "listbox" Or $sClass = "syslistview32" Or $sClass = "systreeview32" Then
                Local $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
                Local $hDC = _WinAPI_GetWindowDC($hWnd)
                _PaintSizeBox($hWnd, $hDC)
                _WinAPI_ReleaseDC($hWnd, $hDC)
                Return $iRet
            EndIf
        
        Case $WM_SETFOCUS, $WM_KILLFOCUS
            Local $sClass = _WinAPI_GetClassName($hWnd)
            If _IsBorderedControl($sClass) Then
                ; Trigger WM_NCPAINT to redraw border with updated focus color
                ;_WinAPI_SetWindowPos($hWnd, 0, 0, 0, 0, 0, BitOR($SWP_NOMOVE, $SWP_NOSIZE, $SWP_NOZORDER, $SWP_FRAMECHANGED))
                _WinAPI_RedrawWindow($hWnd, 0, 0, BitOR($RDW_FRAME, $RDW_INVALIDATE, $RDW_NOERASE))
            EndIf
        Case $WM_NCCALCSIZE ;generate non-client area to ensure borders are not overpaint because no WS_EX_CLIENTEDGE
            Local $sClass = _WinAPI_GetClassName($hWnd)
            If _IsBorderedControl($sClass) And $wParam Then
                Local $iRet = _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
                Local $tRect = DllStructCreate($tagRECT, $lParam)
                $tRect.left   += 1
                $tRect.top    += 1
                $tRect.right  -= 1
                $tRect.bottom -= 1
                Return $iRet
            EndIf
    EndSwitch
    Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>_SubclassProc

Func _DateProc($hWnd, $iMsg, $wParam, $lParam)
    Switch $iMsg
        Case $WM_PAINT
            Local $tPaint = DllStructCreate($tagPAINTSTRUCT)
            Local $hDC = _WinAPI_BeginPaint($hWnd, $tPaint)

            Local $tClient = _WinAPI_GetClientRect($hWnd)
            Local $iW = $tClient.Right
            Local $iH = $tClient.Bottom

            ; --- Memory DC for flicker-free rendering ---
            Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC)
            Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH)
            Local $hOldBmp = _WinAPI_SelectObject($hMemDC, $hBitmap)

            ; 1. Let Windows draw the light-mode control into memory DC
            _WinAPI_CallWindowProc($g_hDateOldProc, $hWnd, $WM_PRINTCLIENT, $hMemDC, $PRF_CLIENT)

            ; 2. Invert all pixels (background becomes black, text white, selection orange)
            Local $tRECT = DllStructCreate($tagRECT)
            $tRECT.right = $iW
            $tRECT.bottom = $iH
            _WinAPI_InvertRect($hMemDC, $tRECT)

            ; --- 3. PIXEL HACK: destroy orange highlight & set background color ---
            ; Strategy: render the light-mode control via WM_PRINTCLIENT, invert all pixels,
            ; then scan the bitmap and replace near-black (inverted white background) with the
            ; exact GUI background color, and convert all remaining pixels to grayscale.
            ; This eliminates the orange selection highlight and unifies the background.
            Local $iSize = $iW * $iH
            Local $tPixels = DllStructCreate("dword c[" & $iSize & "]")
            ; Load pixel array directly from bitmap memory
            Local $iBytes = DllCall("gdi32.dll", "long", "GetBitmapBits", "handle", $hBitmap, "long", $iSize * 4, "ptr", DllStructGetPtr($tPixels))[0]

            If $iBytes = $iSize * 4 Then
                Local $iPixel, $r, $g, $b, $iGray
                For $i = 1 To $iSize
                    $iPixel = $tPixels.c(($i))

                    ; Split into color channels
                    $b = BitAND($iPixel, 0xFF)
                    $g = BitAND(BitShift($iPixel, 8), 0xFF)
                    $r = BitAND(BitShift($iPixel, 16), 0xFF)

                    ; Convert to grayscale (orange becomes mid-gray)
                    $iGray = Int(($r + $g + $b) / 3)

                    ; Very dark pixel = inverted white background
                    If $iGray < 15 Then
                        $iPixel = $COLOR_BG_DARK ; Replace with exact GUI background color
                    Else
                        ; Grayscale value for text (white) and selection (gray)
                        ; (negative BitShift shifts left in AutoIt)
                        $iPixel = BitOR(BitShift($iGray, -16), BitShift($iGray, -8), $iGray)
                    EndIf

                    $tPixels.c(($i)) = $iPixel
                Next
                ; Write cleaned pixels back into the bitmap
                DllCall("gdi32.dll", "long", "SetBitmapBits", "handle", $hBitmap, "long", $iSize * 4, "ptr", DllStructGetPtr($tPixels))
            EndIf
            ; --- END PIXEL HACK ---

            ; --- Border color (hover effect) ---
            Local $iBorderColor = $COLOR_BORDER
            If _WinAPI_GetFocus() = $hWnd Then $iBorderColor = $COLOR_BORDER
            Local $tCursorPos = DllStructCreate($tagPOINT)
            DllCall("user32.dll", "bool", "GetCursorPos", "struct*", $tCursorPos)
            DllCall("user32.dll", "bool", "ScreenToClient", "hwnd", $hWnd, "struct*", $tCursorPos)
            If $tCursorPos.X >= 0 And $tCursorPos.X <= $iW And $tCursorPos.Y >= 0 And $tCursorPos.Y <= $iH Then
                $iBorderColor = $COLOR_BORDER_LIGHT
            EndIf

            ; --- Draw border ---
            Local $hPen = _WinAPI_CreatePen(0, 1, _ColorToCOLORREF($iBorderColor))
            Local $hNullBr = _WinAPI_GetStockObject(5)
            Local $hOldPen = _WinAPI_SelectObject($hMemDC, $hPen)
            Local $hOldBr = _WinAPI_SelectObject($hMemDC, $hNullBr)
            DllCall("gdi32.dll", "bool", "Rectangle", "handle", $hMemDC, "int", 0, "int", 0, "int", $iW, "int", $iH)
            _WinAPI_SelectObject($hMemDC, $hOldPen)
            _WinAPI_SelectObject($hMemDC, $hOldBr)
            _WinAPI_DeleteObject($hPen)

            ; --- Copy finished result to screen in one step (no flicker) ---
            _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hMemDC, 0, 0, $SRCCOPY)

            ; --- Cleanup ---
            _WinAPI_SelectObject($hMemDC, $hOldBmp)
            _WinAPI_DeleteObject($hBitmap)
            _WinAPI_DeleteDC($hMemDC)
            _WinAPI_EndPaint($hWnd, $tPaint)
            Return 0

        Case $WM_ERASEBKGND
            Return 1

        Case $WM_SETFOCUS, $WM_KILLFOCUS
            Local $iRet = _WinAPI_CallWindowProc($g_hDateOldProc, $hWnd, $iMsg, $wParam, $lParam)
            _WinAPI_InvalidateRect($hWnd, 0, False)
            Return $iRet

        Case $WM_MOUSEMOVE
            Local $iRet = _WinAPI_CallWindowProc($g_hDateOldProc, $hWnd, $iMsg, $wParam, $lParam)
            If Not $g_bHover Then
                $g_bHover = True
                _WinAPI_InvalidateRect($hWnd, 0, False)
            EndIf
            Return $iRet

        Case $WM_MOUSELEAVE
            $g_bHover = False
            _WinAPI_InvalidateRect($hWnd, 0, False)

    EndSwitch

    Return _WinAPI_CallWindowProc($g_hDateOldProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>_DateProc

Func _MakeMenuOwnerDraw($hWnd)
    ; Converts all top-level menu items to MFT_OWNERDRAW so WM_MEASUREITEM / WM_DRAWITEM
    ; can render them with the dark color scheme. Must be called again after every DPI change
    ; to force Windows to re-send WM_MEASUREITEM with updated dimensions.
    $g_hMenu = _GUICtrlMenu_GetMenu($hWnd)
    If Not $g_hMenu Then Return False

    Local $iCount = _GUICtrlMenu_GetItemCount($g_hMenu)
    If $iCount <= 0 Then Return False

    ; Use SetMenuInfo to set permanent menu background (and avoid the occasional flicker)
    Local $hBrush = DllCall("gdi32.dll", "hwnd", "CreateSolidBrush", "int", $COLOR_BG_DARK)
    Local $tInfo = DllStructCreate("int Size;int Mask;int Style;int YMax;handle hBack;int ContextHelpID;ptr MenuData")
    DllStructSetData($tInfo, "Mask", 2)
    DllStructSetData($tInfo, "hBack", $hBrush[0])
    DllStructSetData($tInfo, "Size", DllStructGetSize($tInfo))
    DllCall("user32.dll", "int", "SetMenuInfo", "hwnd", $g_hMenu, "ptr", DllStructGetPtr($tInfo))
    _WinAPI_DeleteObject($hBrush)
    
    ReDim $g_aMenuText[$iCount]

    Local $tText, $iLen
    For $i = 0 To $iCount - 1
        ; GetMenuStringW is more reliable than _GUICtrlMenu_GetItemText for Unicode menu strings
        $tText = DllStructCreate("wchar s[256]")
        $iLen = DllCall("user32.dll", "int", "GetMenuStringW", "handle", $g_hMenu, "uint", $i, "struct*", $tText, "int", 255, "uint", $MF_BYPOSITION)

        If IsArray($iLen) And $iLen[0] > 0 Then
            $g_aMenuText[$i] = $tText.s
        Else
            $g_aMenuText[$i] = ""
        EndIf

        ; Flag item as owner-drawn - triggers WM_MEASUREITEM immediately
        _GUICtrlMenu_SetItemType($g_hMenu, $i, $MFT_OWNERDRAW, True)
    Next
    
    ; Force immediate repaint of the menu bar
    _GUICtrlMenu_DrawMenuBar($hWnd)
    _WinAPI_RedrawWindow($hWnd, 0, 0, BitOR($RDW_INVALIDATE, $RDW_UPDATENOW))

    Return True
EndFunc   ;==>_MakeMenuOwnerDraw

Func _WM_DPICHANGED($hWnd, $iMsg, $wParam, $lParam)
    #forceref $iMsg

    _WinAPI_LockWindowUpdate($hWnd) ; suppress painting during DPI transition
    ; LoWord(wParam) = new DPI value sent by Windows
    $g_fScale = _WinAPI_LoWord($wParam) / 96
    ; lParam = suggested window RECT already adjusted for new DPI - use it directly
    Local $tRECT = DllStructCreate($tagRECT, $lParam)
    Local $iX = $tRECT.left, $iY = $tRECT.top, $iW = $tRECT.right - $iX, $iH = $tRECT.bottom - $iY
    _WinAPI_SetWindowPos($hWnd, 0, $iX, $iY, $iW, $iH, BitOR($SWP_NOZORDER, $SWP_NOACTIVATE))

    ; Reposition/resize all registered controls and apply new font
    _ApplyDPIScaling($g_fScale)

    ; Recreate menu font for new DPI.
    ; Old font is kept alive until AFTER _MakeMenuOwnerDraw so WM_MEASUREITEM can still use it.
    Local $hOldMenuFont = $g_hMenuFont
    Local $iHeight = -Round(_WinAPI_MulDiv($fDefFontSize, _WinAPI_LoWord($wParam), 72))
    $g_hMenuFont = _WinAPI_CreateFont($iHeight, 0, 0, 0, $FW_NORMAL, False, False, False, _
                                      $DEFAULT_CHARSET, $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $PROOF_QUALITY, $DEFAULT_PITCH, "Arial")

    ; Re-register owner-draw -> forces WM_MEASUREITEM with the new font already active
    _MakeMenuOwnerDraw($g_hGUI)
    If $hOldMenuFont Then _WinAPI_DeleteObject($hOldMenuFont) ; safe to delete now

    _EnableMenuHotTrack($g_hMenu)

    ; Rescale statusbar part widths using the base (unscaled) values in $g_aStatusbarParts
    If $g_hStatusbar Then
        Local $aScaledParts[4]
        For $i = 0 To 3
            $aScaledParts[$i] = $g_aStatusbarParts[$i] * $g_fScale
        Next
        _GUICtrlStatusBar_SetParts($g_hStatusbar, $aScaledParts)
        _SendMessage($g_hStatusbar, $WM_SIZE, 0, 0)
    EndIf
    
    Local $aChildren = _WinAPI_EnumChildWindows($hWnd, False)
    If IsArray($aChildren) Then
        For $i = 1 To $aChildren[0][0]
            _WinAPI_SetWindowPos($aChildren[$i][0], 0, 0, 0, 0, 0, BitOR($SWP_NOMOVE, $SWP_NOSIZE, $SWP_NOZORDER, $SWP_FRAMECHANGED))
        Next
    EndIf
    
    _SetDarkTreeViewCheckboxes($g_hTreeView2)
    
    _WinAPI_LockWindowUpdate(0)

    Return 1
EndFunc   ;==>_WM_DPICHANGED

Func _WM_MEASUREITEM($hWnd, $iMsg, $wParam, $lParam)
    Local $tagMEASUREITEM = "uint CtlType;uint CtlID;uint itemID;uint itemWidth;uint itemHeight;ulong_ptr itemData"
    Local $t = DllStructCreate($tagMEASUREITEM, $lParam)
    If Not IsDllStruct($t) Then Return $GUI_RUNDEFMSG

    If $t.CtlType <> $ODT_MENU Then Return $GUI_RUNDEFMSG ; only handle menu items

    Local $itemID = $t.itemID

    ; itemID is the menu item command ID, not its position.
    ; AutoIt assigns IDs starting at 3 for the first top-level menu item.
    Local $iPos = -1
    For $i = 0 To UBound($g_aMenuText) - 1
        If $itemID = ($i + 3) Then ; offset 3 = AutoIt internal menu ID base
            $iPos = $i
            ExitLoop
        EndIf
    Next

    ; Fallback if ID mapping failed
    If $iPos < 0 Then $iPos = $itemID
    If $iPos < 0 Or $iPos >= UBound($g_aMenuText) Then $iPos = 0

    Local $sText = $g_aMenuText[$iPos]

    ; Measure text using DEFAULT_GUI_FONT - Windows keeps this stock object DPI-aware automatically.
    ; Using a window DC here is intentional: DEFAULT_GUI_FONT is a stock object not affected by DC caching.
    ; Multiply by $g_fScale because GetTextExtentPoint32 returns logical pixels at 96 DPI baseline.
    Local $hDC = _WinAPI_GetDC($hWnd)
    Local $hFont = _WinAPI_GetStockObject($DEFAULT_GUI_FONT)
    Local $hOldFont = _WinAPI_SelectObject($hDC, $hFont)

    Local $tSize = _WinAPI_GetTextExtentPoint32($hDC, $sText)
    Local $iTextWidth = $tSize.X * $g_fScale
    Local $iTextHeight = $tSize.Y * $g_fScale

    _WinAPI_SelectObject($hDC, $hOldFont)
    _WinAPI_ReleaseDC($hWnd, $hDC)


    ; Pass measured size back to Windows (no padding needed - DrawText uses exact rect)
    $t.itemWidth = $iTextWidth
    $t.itemHeight = $iTextHeight

    Return 1
EndFunc   ;==>_WM_MEASUREITEM

Func _WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam)
    Local $tagDRAWITEM = "uint CtlType;uint CtlID;uint itemID;uint itemAction;uint itemState;ptr hwndItem;handle hDC;" & _
                         "long left;long top;long right;long bottom;ulong_ptr itemData"
    Local $t = DllStructCreate($tagDRAWITEM, $lParam)
    If Not IsDllStruct($t) Then Return $GUI_RUNDEFMSG

    If $t.CtlType <> $ODT_MENU Then Return $GUI_RUNDEFMSG

    Local $hDC = $t.hDC
    Local $left = $t.left
    Local $top = $t.top
    Local $right = $t.right
    Local $bottom = $t.bottom
    Local $state = $t.itemState
    Local $itemID = $t.itemID

    ; convert itemID to position
    Local $iPos = -1
    For $i = 0 To UBound($g_aMenuText) - 1
        If $itemID = ($i + 3) Then
            $iPos = $i
            ExitLoop
        EndIf
    Next

    If $iPos < 0 Then $iPos = $itemID
    If $iPos < 0 Or $iPos >= UBound($g_aMenuText) Then $iPos = 0

    Local $sText = $g_aMenuText[$iPos]
    $sText = StringReplace($sText, "&", "")

    ; Colors
    Local $clrBG = _ColorToCOLORREF($COLOR_BG_DARK)
    Local $clrSel = _ColorToCOLORREF($COLOR_MENU_SELECT)
    Local $clrText = _ColorToCOLORREF($COLOR_TEXT_LIGHT)

    ; Draw item background (selected = lighter)
    Local $bSelected = BitAND($state, $ODS_SELECTED)
    Local $bHot = BitAND($state, $ODS_HOTLIGHT)
    Local $hBrush

    If $bSelected Then
        $hBrush = _WinAPI_CreateSolidBrush($clrSel)
    ElseIf $bHot Then
        $hBrush = _WinAPI_CreateSolidBrush(_ColorToCOLORREF($COLOR_HOTTRACK_MENU))
    Else
        $hBrush = _WinAPI_CreateSolidBrush($clrBG)
    EndIf

    Local $tItemRect = DllStructCreate($tagRECT)
    With $tItemRect
        .left = $left
        .top = $top
        .right = $right
        .bottom = $bottom
    EndWith

    _WinAPI_FillRect($hDC, $tItemRect, $hBrush)
    _WinAPI_DeleteObject($hBrush)

    ; Setup font
    Local $hFont = ($g_hMenuFont ? $g_hMenuFont : _WinAPI_GetStockObject($DEFAULT_GUI_FONT))
    Local $hOldFont = _WinAPI_SelectObject($hDC, $hFont)

    _WinAPI_SetBkMode($hDC, $TRANSPARENT)
    If _WinAPI_GetForegroundWindow() <> $g_hGUI Then $clrText = _WinAPI_ColorAdjustLuma($clrText, -30) ;dim menu text when GUI is not active
    _WinAPI_SetTextColor($hDC, $clrText)

    ; Draw text
    Local $tTextRect = DllStructCreate($tagRECT)
    With $tTextRect
        .left = $left + 10
        .top = $top + 4
        .right = $right - 10
        .bottom = $bottom - 4
    EndWith

    DllCall("user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sText, "int", -1, "ptr", DllStructGetPtr($tTextRect), "uint", BitOR($DT_SINGLELINE, $DT_VCENTER, $DT_LEFT, $DT_NOCLIP))

    If $hOldFont Then _WinAPI_SelectObject($hDC, $hOldFont)

    Return 1
EndFunc   ;==>_WM_DRAWITEM

Func _WM_CTLCOLOR($hWnd, $iMsg, $wParam, $lParam)
    Local $hDC = $wParam
    Local $hCtrl = $lParam

    ; Testing area for Static (label) control ==========================================================================================
    ;
    ; Not Working: _WinAPI_GetTextColor, _WinAPI_GetBkColor and _WinAPI_GetBkMode giving incorrect return values?
    ; IDEA:
    ;   - If TextColor = 0x000000 or 0xFFFFFF, invert and set inverted color
    ;   - If TextColor <> 0x000000 or 0xFFFFFF, leave color as is since it is likely customized for a reason
    ;   - If BkColor = 0x000000 or 0xFFFFFF, invert and set inverted color
    ;   - If BkColor <> 0x000000 or 0xFFFFFF, leave color as is since it is likely customized for a reason
    ;   - Can we detect fill (brush) color currently in use? Pixel color? Can we get pixel color if window is not yet visible?
    ;   - If fill (brush) color <> 0x000000 or 0xFFFFFF, leave brush color since it is likely custom (eg. green background of $g_hLabelGreen)
    ;   - Possibly use NULL_BRUSH for transparent background if fill (brush) color = 0x000000 or 0xFFFFFF
    If _WinAPI_GetClassName($hCtrl) = "Static" Then
        ConsoleWrite("TextColor: " & "0x" & Hex(_WinAPI_GetTextColor($hDC), 6) & @CRLF)
        ConsoleWrite("BkColor:   " & "0x" & Hex(_WinAPI_GetBkColor($hDC), 6) & @CRLF)
        ConsoleWrite("BkMode:    " & _WinAPI_GetBkMode($hDC) & @CRLF)
        ConsoleWrite(" " & @CRLF)
    EndIf
    ;
    ; Testing area for Static (label) control ==========================================================================================


    ; If the control is the special green label -> return green background
    If $hCtrl = $g_hLabelGreen Then
        ; black text on a green background
        _WinAPI_SetTextColor($hDC, _ColorToCOLORREF(0x000000))
        _WinAPI_SetBkColor($hDC, _ColorToCOLORREF(0x00FF00))
        _WinAPI_SetBkMode($hDC, $OPAQUE) ; important, otherwise it remains transparent and you cannot see the background
        If $g_hBrushGreen Then Return $g_hBrushGreen
    EndIf

    ; --- Special case: Make "Sample Pic" label transparent ---
    If $hCtrl = $g_hLabelPic Then
        ; set transparent background
        _WinAPI_SetBkMode($hDC, $TRANSPARENT)
        ; set text color (if necessary) - e.g., white
        _WinAPI_SetTextColor($hDC, _ColorToCOLORREF($COLOR_TEXT_LIGHT))
        ; return NULL_BRUSH (stock object), so Windows does NOT fill with your dark brush
        Local $hNull = _WinAPI_GetStockObject(5) ; 5 = NULL_BRUSH
        If $hNull Then Return $hNull
        ; Fallback if not available:
        Return $GUI_RUNDEFMSG
    EndIf

    ; --- Default behavior for all other statics / controls ---
    _WinAPI_SetTextColor($hDC, _ColorToCOLORREF($COLOR_TEXT_LIGHT))

    Local $hBrush = $g_hBrushEdit
    Local $iColor = $COLOR_EDIT_BG

    Switch $iMsg
        Case $WM_CTLCOLORBTN
            $hBrush = $g_hBrushButton
            $iColor = $COLOR_BUTTON_BG
        Case $WM_CTLCOLORSTATIC
            $hBrush = $g_hBrushBg
            $iColor = $COLOR_BG_DARK
    EndSwitch
    _WinAPI_SetBkColor($hDC, _ColorToCOLORREF($iColor))
    _WinAPI_SetBkMode($hDC, $TRANSPARENT)

    Return $hBrush
EndFunc   ;==>_WM_CTLCOLOR

Func _WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $tInfo, $tBuffer, $tBuffer2, $iCtrl
    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    $hWndFrom = HWnd($tNMHDR.hWndFrom)
    $iIDFrom = $tNMHDR.IDFrom
    $iCode = $tNMHDR.Code

    ; --- Slider (msctls_trackbar32) custom drawing ---
    If $iCode = $NM_CUSTOMDRAW And (_WinAPI_GetClassName($hWndFrom) = "msctls_trackbar32") Then
        Local $tNMCD = DllStructCreate($tagNMCUSTOMDRAW, $lParam)
        Local $dwStage = $tNMCD.dwDrawStage
        Local $hDC = $tNMCD.hdc
        Local $dwItemSpec = $tNMCD.dwItemSpec
        
        Switch $dwStage
            Case $CDDS_PREPAINT
                $tNMCD.ItemState = BitXOR($tNMCD.ItemState, $CDIS_FOCUS)
                Return $CDRF_NOTIFYSUBITEMDRAW

            Case $CDDS_ITEMPREPAINT
                Switch $dwItemSpec
                    Case $TBCD_THUMB
                        ; Determine thumb style from control style flags
                        Local $iStyle       = _WinAPI_GetWindowLong($hWndFrom, $GWL_STYLE)
                        Local $bNoThumb     = BitAND($iStyle, $TBS_NOTHUMB) <> 0        ; no thumb visible
                        Local $bTop         = BitAND($iStyle, $TBS_TOP) <> 0            ; tip points up (horizontal)
                        Local $bBoth        = BitAND($iStyle, $TBS_BOTH) <> 0           ; rectangular thumb
                        Local $bVert        = BitAND($iStyle, $TBS_VERT) <> 0           ; vertical slider
                        Local $bDownIsLeft  = BitAND($iStyle, $TBS_DOWNISLEFT) <> 0     ; vert: tip points left
                        Local $bBottom      = Not $bTop And Not $bBoth And Not $bVert   ; default: tip points down              
                        
                        ; No thumb style - skip custom drawing, let Windows handle (= invisible)
                        If $bNoThumb Then Return $CDRF_SKIPDEFAULT

                        Local $iL = $tNMCD.left
                        Local $iT = $tNMCD.top
                        Local $iR = $tNMCD.right - 1
                        Local $iB = $tNMCD.bottom
                        Local $iMid   = $bVert ? ($iT + $iB) / 2 : ($iL + $iR) / 2
                        Local $iSplit = $bVert ? $iR - ($iB - $iT) / 2 : $iB - ($iR - $iL) / 2

                        Local $tPt = DllStructCreate($tagPOINT)
                        DllCall("user32.dll", "bool", "GetCursorPos", "struct*", $tPt)
                        _WinAPI_ScreenToClient($hWndFrom, $tPt)
                        Local $bHot = ($tPt.X >= $iL And $tPt.X <= $iR And $tPt.Y >= $iT And $tPt.Y <= $iB - 1)
                    
                        Local $iColor = _ColorToCOLORREF($bHot ? 0x60CDFF : 0x0078D4)

                        Local $hBrush = _WinAPI_CreateSolidBrush($iColor)
                        Local $hPen   = _WinAPI_CreatePen(0, 1, _ColorToCOLORREF($COLOR_CONTROL_BG))
                        Local $hOldBrush = _WinAPI_SelectObject($hDC, $hBrush)
                        Local $hOldPen   = _WinAPI_SelectObject($hDC, $hPen)

                        If $bBoth Then
                            ; rectangular thumb
                            DllCall("gdi32.dll", "bool", "Rectangle", "handle", $hDC, "int", $iL, "int", $iT, "int", $iR + 1, "int", $iB)
                        ElseIf $bVert Then
                            ; vertical slider - pentagon tip points right (default) or left (TBS_DOWNISLEFT)
                            Local $iMidV   = ($iT + $iB) / 2
                            Local $iSplitV = $bDownIsLeft ? $iL + ($iB - $iT) / 2 : $iR - ($iB - $iT) / 2
                            Local $tPoints = DllStructCreate("int p[10]")
                            If $bDownIsLeft Then
                                ; tip points LEFT
                                $tPoints.p((1)) = $iL
                                $tPoints.p((2)) = $iMidV
                                $tPoints.p((3)) = $iSplitV
                                $tPoints.p((4)) = $iT
                                $tPoints.p((5)) = $iR
                                $tPoints.p((6)) = $iT
                                $tPoints.p((7)) = $iR
                                $tPoints.p((8)) = $iB
                                $tPoints.p((9)) = $iSplitV
                                $tPoints.p((10)) = $iB
                            Else
                                ; tip points RIGHT
                                $tPoints.p((1)) = $iR
                                $tPoints.p((2)) = $iMidV
                                $tPoints.p((3)) = $iSplitV
                                $tPoints.p((4)) = $iB
                                $tPoints.p((5)) = $iL
                                $tPoints.p((6)) = $iB
                                $tPoints.p((7)) = $iL
                                $tPoints.p((8)) = $iT
                                $tPoints.p((9)) = $iSplitV
                                $tPoints.p((10)) = $iT
                            EndIf
                            DllCall("gdi32.dll", "bool", "Polygon", "handle", $hDC, "struct*", $tPoints, "int", 5)
                        ElseIf $bTop Then
                            ; TBS_TOP - pentagon tip points UP
                            Local $iSplitTop = $iT + ($iR - $iL) / 2
                            Local $tPoints = DllStructCreate("int p[10]")
                            $tPoints.p((1)) = $iMid
                            $tPoints.p((2)) = $iT
                            $tPoints.p((3)) = $iR
                            $tPoints.p((4)) = $iSplitTop
                            $tPoints.p((5)) = $iR
                            $tPoints.p((6)) = $iB
                            $tPoints.p((7)) = $iL
                            $tPoints.p((8)) = $iB
                            $tPoints.p((9)) = $iL
                            $tPoints.p((10)) = $iSplitTop
                            DllCall("gdi32.dll", "bool", "Polygon", "handle", $hDC, "struct*", $tPoints, "int", 5)
                        Else
                            ; TBS_BOTTOM (default) - pentagon tip points DOWN
                            Local $tPoints = DllStructCreate("int p[10]")
                            $tPoints.p((1)) = $iL
                            $tPoints.p((2)) = $iT
                            $tPoints.p((3)) = $iR
                            $tPoints.p((4)) = $iT
                            $tPoints.p((5)) = $iR
                            $tPoints.p((6)) = $iSplit
                            $tPoints.p((7)) = $iMid
                            $tPoints.p((8)) = $iB
                            $tPoints.p((9)) = $iL
                            $tPoints.p((10)) = $iSplit
                            DllCall("gdi32.dll", "bool", "Polygon", "handle", $hDC, "struct*", $tPoints, "int", 5)
                        EndIf

                        _WinAPI_SelectObject($hDC, $hOldBrush)
                        _WinAPI_SelectObject($hDC, $hOldPen)
                        _WinAPI_DeleteObject($hBrush)
                        _WinAPI_DeleteObject($hPen)
                        Return $CDRF_SKIPDEFAULT

                    Case $TBCD_CHANNEL  ; line behind thumb
                        Local $hBrush = _WinAPI_CreateSolidBrush(_ColorToCOLORREF($COLOR_MENU_SELECT))
                        Local $tRECT2 = DllStructCreate($tagRECT)
                        $tRECT2.Left = $tNMCD.left
                        $tRECT2.Top    = $tNMCD.top
                        $tRECT2.Right = $tNMCD.right
                        $tRECT2.Bottom = $tNMCD.bottom
                        _WinAPI_FillRect($hDC, $tRECT2, $hBrush)
                        _WinAPI_DeleteObject($hBrush)
                        Return $CDRF_SKIPDEFAULT

                    Case Else
                        Return $CDRF_DODEFAULT ; ticks drawn by Windows
                EndSwitch
        EndSwitch
    EndIf

    ; --- Per-control notification handling ---
    Local Static $iTheme
    Switch $hWndFrom
        Case $g_hDate ; thanks to argumentum for the code :-)
            Switch $iCode
                Case $NM_SETFOCUS
                    ; Disable visual theme when DateTime control receives focus
                    _WinAPI_SetThemeAppProperties(0)

                Case $NM_KILLFOCUS
                    _WinAPI_SetThemeAppProperties($iTheme)  ; cudos to argumentum

                Case $DTN_DROPDOWN
                    ; Apply dark colors when the calendar dropdown opens
                    Local $iCtrl = _GUICtrlDTP_GetMonthCal($hWndFrom) ; get the MonthCal child handle
                    _WinAPI_SetWindowTheme($iCtrl, "", "")              ; remove theme for manual color control
                    _GUICtrlMonthCal_SetColor($iCtrl, $MCSC_TEXT, $COLOR_TEXT_LIGHT)
                    _GUICtrlMonthCal_SetColor($iCtrl, $MCSC_TITLEBK, $COLOR_BG_DARK)
                    _GUICtrlMonthCal_SetColor($iCtrl, $MCSC_TITLETEXT, $COLOR_TEXT_LIGHT)
                    _GUICtrlMonthCal_SetColor($iCtrl, $MCSC_MONTHBK, $COLOR_BG_DARK)
                    _GUICtrlMonthCal_SetColor($iCtrl, $MCSC_TRAILINGTEXT, $COLOR_TEXT_LIGHT)

                Case $DTN_CLOSEUP
                    ; Calendar dropdown closed - no action needed

            EndSwitch
    EndSwitch

    Return $GUI_RUNDEFMSG
EndFunc   ;==>_WM_NOTIFY

Func _WM_ACTIVATE($hWnd, $iMsg, $wParam, $lParam)
    If $hWnd <> $g_hGUI Then Return $GUI_RUNDEFMSG
    _OverpaintWhiteLine()
    Return $GUI_RUNDEFMSG
EndFunc   ;==>_WM_ACTIVATE

Func _WM_WINDOWPOSCHANGED($hWnd, $iMsg, $wParam, $lParam)
    If $hWnd <> $g_hGUI Then Return $GUI_RUNDEFMSG
    _OverpaintWhiteLine()
    Return $GUI_RUNDEFMSG
EndFunc   ;==>_WM_WINDOWPOSCHANGED

Func _WM_MENUCOMMAND($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg
    Local $iPos = $wParam ;Menu Item Position (0-based index)
    Local $hMenu = $lParam ;Menu Handle
    Switch $hMenu
        Case $g_hMenu1
            ConsoleWrite("From Menu One" & @CRLF)
            Switch $iPos
                Case 0  ; SubMenu One A
                    ConsoleWrite("SubMenu One A clicked" & @CRLF)
                Case 1  ; SubMenu One B
                    ConsoleWrite("SubMenu One B clicked" & @CRLF)
                Case 2  ; About
                    ConsoleWrite("About clicked!" & @CRLF)
                    GUICtrlSendToDummy($g_AboutDummy)
                    Return 0
            EndSwitch
    EndSwitch

    Return $GUI_RUNDEFMSG
EndFunc   ;==>_WM_MENUCOMMAND

Func _WM_SYSCOMMAND($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $lParam
    Switch BitAND($wParam, 0x0000FFFF)
        Case $idAbout
            GUICtrlSendToDummy($g_AboutDummy)
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>_WM_SYSCOMMAND

Func _CleanupBrushes()
    ; Release all GDI objects created at startup. Called on GUI close.
    If $g_hBrushEdit Then _WinAPI_DeleteObject($g_hBrushEdit)
    If $g_hBrushButton Then _WinAPI_DeleteObject($g_hBrushButton)
    If $g_hBrushBg Then _WinAPI_DeleteObject($g_hBrushBg)
    If $g_hBrushGreen Then _WinAPI_DeleteObject($g_hBrushGreen)
    If $g_hMenuFont Then _WinAPI_DeleteObject($g_hMenuFont)
    If $g_hCtrlFont Then _WinAPI_DeleteObject($g_hCtrlFont) ; control font created by _ApplyDPIScaling
    Local $j
    For $j = 0 To UBound($g_aCustomFonts) - 1
        If $g_aCustomFonts[$j] Then _WinAPI_DeleteObject($g_aCustomFonts[$j])
    Next
    If $g_hMsgBoxBrush Then
        _WinAPI_DeleteObject($g_hMsgBoxBrush)
        $g_hMsgBoxBrush = 0
    EndIf
EndFunc   ;==>_CleanupBrushes

Func _EnableDarkScrollBars()
    ; Apply DarkMode_Explorer theme to all controls that have scrollbars.
    ; Also handles TreeView with $TVS_CHECKBOXES which creates explicit ScrollBar child windows.
    Local $tScrollInfo, $sClass, $hCtrl, $hChild
    For $i = 0 To $g_iControlCount - 1
        $hCtrl = $g_aControls[$i][1]
        If Not $hCtrl Then ContinueLoop

        ; 1 Normal attempt (works for most controls)
        $tScrollInfo = _GUIScrollBars_GetScrollInfoEx($hCtrl, 1)
        If IsDllStruct($tScrollInfo) Then _WinAPI_SetWindowTheme($hCtrl, "DarkMode_Explorer", 0)

        ; 2 Extension: If the control has its own scrollbar child windows (e.g., TreeView with $TVS_CHECKBOXES)
        $hChild = _WinAPI_GetWindow($hCtrl, $GW_CHILD)
        While $hChild
            $sClass = _WinAPI_GetClassName($hChild)
            If StringCompare($sClass, "ScrollBar") = 0 Then
                ; Set DarkMode on the ScrollBar itself
                _WinAPI_SetWindowTheme($hChild, "DarkMode_Explorer", 0)
                _WinAPI_AllowDarkModeForWindow($hChild, True)
            EndIf
            $hChild = _WinAPI_GetWindow($hChild, $GW_HWNDNEXT)
        WEnd
    Next
EndFunc   ;==>_EnableDarkScrollBars

Func _WinProc($hWnd, $iMsg, $wParam, $lParam) ; Custom window procedure for tab control with Dark Mode

    Switch $iMsg

        Case $WM_LBUTTONDOWN
            ; Force focus to tab control on any click
            _WinAPI_SetFocus($hWnd)
            _WinAPI_InvalidateRect($hWnd, 0, True)
            Return _WinAPI_CallWindowProc($g_hProc, $hWnd, $iMsg, $wParam, $lParam)
    
        Case $WM_SETFOCUS
            _WinAPI_InvalidateRect($hWnd, 0, True)
            Return _WinAPI_CallWindowProc($g_hProc, $hWnd, $iMsg, $wParam, $lParam)

        Case $WM_KILLFOCUS
            _WinAPI_InvalidateRect($hWnd, 0, True)
            Return _WinAPI_CallWindowProc($g_hProc, $hWnd, $iMsg, $wParam, $lParam)
            
        Case $WM_ERASEBKGND
            Return 1 ; Prevent background erase to avoid flicker

        Case $WM_PAINT
            Local $tPaint = DllStructCreate($tagPAINTSTRUCT)
            Local $hDC = DllCall("user32.dll", "handle", "BeginPaint", "hwnd", $hWnd, "struct*", $tPaint)
            If @error Or Not $hDC[0] Then Return _WinAPI_CallWindowProc($g_hProc, $hWnd, $iMsg, $wParam, $lParam)
            $hDC = $hDC[0]

            ; Get client rectangle
            Local $tClient = _WinAPI_GetClientRect($hWnd)
            If Not IsDllStruct($tClient) Then
                _WinAPI_EndPaint($hWnd, $tPaint)
                Return 0
            EndIf

            Local $iWidth = $tClient.Right
            Local $iHeight = $tClient.Bottom

            ; Create memory DC for double buffering
            Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC)
            Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iWidth, $iHeight)
            Local $hOldBmp = _WinAPI_SelectObject($hMemDC, $hBitmap)

            ; Fill background but exclude overlapping GUI controls from painting
            Local $hParent = _WinAPI_GetParent($hWnd)
            Local $hChild = _WinAPI_GetWindow($hParent, $GW_CHILD)
            Local $tCR, $tPR = _WinAPI_GetWindowRect($hWnd)
            Local $left, $top, $right, $bottom

            ; Fill background but exclude overlapping GUI controls from painting
            While $hChild
                If $hChild <> $hWnd And _WinAPI_IsWindowVisible($hChild) Then
                    $tCR = _WinAPI_GetWindowRect($hChild)

                    ; Schnittmenge statt "vollständig enthalten"
                    If Not ($tCR.right < $tPR.left Or $tCR.left > $tPR.right Or _
                            $tCR.bottom < $tPR.top Or $tCR.top > $tPR.bottom) Then

                        $left = Max($tCR.left, $tPR.left) - $tPR.left
                        $top = Max($tCR.top, $tPR.top) - $tPR.top
                        $right = Min($tCR.right, $tPR.right) - $tPR.left
                        $bottom = Min($tCR.bottom, $tPR.bottom) - $tPR.top

                        DllCall("gdi32.dll", "int", "ExcludeClipRect", "handle", $hMemDC, "int", $left, "int", $top, "int", $right, "int", $bottom)
                        DllCall("gdi32.dll", "int", "ExcludeClipRect", "handle", $hDC, "int", $left, "int", $top, "int", $right, "int", $bottom)
                    EndIf
                EndIf
                $hChild = _WinAPI_GetWindow($hChild, $GW_HWNDNEXT)
            WEnd

            ; also exclude the system Up/Down of the TabControl itself
            Local $hTabUpDown = _WinAPI_FindWindowEx($hWnd, "msctls_updown32")
            If $hTabUpDown And _WinAPI_IsWindowVisible($hTabUpDown) Then
                $tCR = _WinAPI_GetWindowRect($hTabUpDown)

                If Not ($tCR.right < $tPR.left Or $tCR.left > $tPR.right Or _
                        $tCR.bottom < $tPR.top Or $tCR.top > $tPR.bottom) Then

                    $left = Max($tCR.left, $tPR.left) - $tPR.left
                    $top = Max($tCR.top, $tPR.top) - $tPR.top
                    $right = Min($tCR.right, $tPR.right) - $tPR.left
                    $bottom = Min($tCR.bottom, $tPR.bottom) - $tPR.top

                    DllCall("gdi32.dll", "int", "ExcludeClipRect", "handle", $hMemDC, "int", $left, "int", $top, "int", $right, "int", $bottom)
                    DllCall("gdi32.dll", "int", "ExcludeClipRect", "handle", $hDC, "int", $left, "int", $top, "int", $right, "int", $bottom)
                EndIf
            EndIf

            ; Fill background
            Local $hBrush = _WinAPI_CreateSolidBrush(_ColorToCOLORREF($COLOR_BG_DARK))
            _WinAPI_FillRect($hMemDC, $tClient, $hBrush)
            _WinAPI_DeleteObject($hBrush)

            ; Get tab info
            Local $iTabCount = _SendMessage($hWnd, $TCM_GETITEMCOUNT, 0, 0)
            Local $iCurSel = _SendMessage($hWnd, $TCM_GETCURSEL, 0, 0)

            ; Setup font
            Local $hFont = _SendMessage($hWnd, $WM_GETFONT, 0, 0)
            If Not $hFont Then $hFont = _WinAPI_GetStockObject($DEFAULT_GUI_FONT)
            Local $hOldFont = _WinAPI_SelectObject($hMemDC, $hFont)

            _WinAPI_SetBkMode($hMemDC, $TRANSPARENT)
            _WinAPI_SetTextColor($hMemDC, _ColorToCOLORREF($COLOR_TEXT_LIGHT))

            ; Draw each tab
            Local $tRECT, $iLeft, $iTop, $iRight, $iBottom, $tItem, $tText, $bSelected, $iTabColor, $hTabBrush, $tTabRect, _
                    $sText, $hPen, $hOldPen, $hPenSep, $hOldPenSep, $tTextRect, $hBorderPen, $hOldBorderPen, $hNullBrush, $hOldBorderBrush

            For $i = 0 To $iTabCount - 1
                ; Get tab rectangle using TCM_GETITEMRECT
                $tRECT = DllStructCreate($tagRECT)
                $aResult = DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", $TCM_GETITEMRECT, "wparam", $i, "struct*", $tRECT)
                If @error Or Not $aResult[0] Then ContinueLoop

                $iLeft = $tRECT.Left
                $iTop = $tRECT.Top
                $iRight = $tRECT.Right
                $iBottom = $tRECT.Bottom

                ; Skip if rectangle is invalid
                If $iLeft >= $iRight Or $iTop >= $iBottom Then ContinueLoop

                ; Get tab text
                $tItem = DllStructCreate("uint Mask;dword dwState;dword dwStateMask;ptr pszText;int cchTextMax;int iImage;lparam lParam")
                $tText = DllStructCreate("wchar Text[256]")
                With $tItem
                    .Mask = $TCIF_TEXT
                    .pszText = DllStructGetPtr($tText)
                    .cchTextMax = 256
                EndWith

                DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", $TCM_GETITEMW, "wparam", $i, "struct*", $tItem)

                $sText = DllStructGetData($tText, "Text")

                ; Draw tab background
                $bSelected = ($i = $iCurSel)
                $iTabColor = $bSelected ? $COLOR_BUTTON_BG : $COLOR_BG_DARK
                $hTabBrush = _WinAPI_CreateSolidBrush(_ColorToCOLORREF($iTabColor))

                $tTabRect = DllStructCreate($tagRECT)
                With $tTabRect
                    .Left = $iLeft
                    .Top = $iTop
                    .Right = $iRight
                    .Bottom = $iBottom
                EndWith

                _WinAPI_FillRect($hMemDC, $tTabRect, $hTabBrush)
                _WinAPI_DeleteObject($hTabBrush)
                
                ; Draw selection indicator (top border for selected tab)
                If $bSelected Then
                    $hPen = _WinAPI_CreatePen(0, 2, _ColorToCOLORREF($COLOR_TAB_ACCENT)) ; Blue accent
                    $hOldPen = _WinAPI_SelectObject($hMemDC, $hPen)
                    _WinAPI_MoveTo($hMemDC, $iLeft, $iTop)
                    _WinAPI_LineTo($hMemDC, $iRight - 2, $iTop)
                    _WinAPI_SelectObject($hMemDC, $hOldPen)
                    _WinAPI_DeleteObject($hPen)
                EndIf

                ; Draw separator between tabs
                If $i < $iTabCount - 1 Then
                    $hPenSep = _WinAPI_CreatePen(0, 1, _ColorToCOLORREF($COLOR_BORDER))
                    $hOldPenSep = _WinAPI_SelectObject($hMemDC, $hPenSep)
                    _WinAPI_MoveTo($hMemDC, $iRight - 1, $iTop + 4)
                    _WinAPI_LineTo($hMemDC, $iRight - 1, $iBottom - 4)
                    _WinAPI_SelectObject($hMemDC, $hOldPenSep)
                    _WinAPI_DeleteObject($hPenSep)
                EndIf

                ; Draw text centered in tab
                $tTextRect = DllStructCreate($tagRECT)
                With $tTextRect
                    .Left = $iLeft + 6
                    .Top = $iTop + 3
                    .Right = $iRight - 6
                    .Bottom = $iBottom - 3
                EndWith

                DllCall("user32.dll", "int", "DrawTextW", _
                        "handle", $hMemDC, _
                        "wstr", $sText, _
                        "int", -1, _
                        "struct*", $tTextRect, _
                        "uint", BitOR($DT_CENTER, $DT_VCENTER, $DT_SINGLELINE, $DT_NOCLIP))
            Next

            ; Draw border around entire control
            Local $bTabFocused = (_WinAPI_GetFocus() = $hWnd)
            $hBorderPen = _WinAPI_CreatePen(0, 1, _ColorToCOLORREF($bTabFocused ? $COLOR_BORDER_LIGHT : $COLOR_BORDER)) ;works only when Tab is clicked
            $hOldBorderPen = _WinAPI_SelectObject($hMemDC, $hBorderPen)
            $hNullBrush = _WinAPI_GetStockObject(5) ; NULL_BRUSH
            $hOldBorderBrush = _WinAPI_SelectObject($hMemDC, $hNullBrush)

            DllCall("gdi32.dll", "bool", "Rectangle", "handle", $hMemDC, "int", 0, "int", 0, "int", $iWidth, "int", $iHeight)

            _WinAPI_SelectObject($hMemDC, $hOldBorderPen)
            _WinAPI_SelectObject($hMemDC, $hOldBorderBrush)
            _WinAPI_DeleteObject($hBorderPen)

            ; Copy to screen
            _WinAPI_BitBlt($hDC, 0, 0, $iWidth, $iHeight, $hMemDC, 0, 0, $SRCCOPY)

            ; Cleanup
            _WinAPI_SelectObject($hMemDC, $hOldFont)
            _WinAPI_SelectObject($hMemDC, $hOldBmp)
            _WinAPI_DeleteObject($hBitmap)
            _WinAPI_DeleteDC($hMemDC)

            _WinAPI_EndPaint($hWnd, $tPaint)
            Return 0
            
        Case $WM_PARENTNOTIFY
            ; Fired when a child window is created inside the tab control.
            ; The tab spinner (msctls_updown32) is created lazily by Windows when tabs overflow -
            ; it doesn't exist at init time, so we theme it here the moment it appears.
            If _WinAPI_LoWord($wParam) = $WM_CREATE Then
                Local $hNewChild = HWnd($lParam) ; lParam carries the new child's HWND as integer - must cast!
                If _WinAPI_GetClassName($hNewChild) = "msctls_updown32" Then
                    _WinAPI_AllowDarkModeForWindow($hNewChild, True)
                    _WinAPI_SetWindowTheme($hNewChild, "DarkMode_Explorer", 0)
                    _WinAPI_SetWindowPos($hNewChild, $HWND_TOPMOST, 0, 0, 0, 0, BitOR($SWP_NOMOVE, $SWP_NOSIZE, $SWP_NOACTIVATE))
                    _WinAPI_InvalidateRect($hWnd, 0, True)
                    _SendMessage($hNewChild, $WM_THEMECHANGED, 0, 0)
                EndIf
            EndIf
            Return _WinAPI_CallWindowProc($g_hProc, $hWnd, $iMsg, $wParam, $lParam)
    EndSwitch

    Return _WinAPI_CallWindowProc($g_hProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>_WinProc

Func _WinAPI_FindWindowEx($hParent, $sClass, $sTitle = "", $hAfter = 0)
    Local $ret = DllCall("user32.dll", "hwnd", "FindWindowExW", "hwnd", $hParent, "hwnd", $hAfter, "wstr", $sClass, "wstr", $sTitle)
    If @error Or Not IsArray($ret) Then Return 0
    Return $ret[0]
EndFunc   ;==>_WinAPI_FindWindowEx

Func _WinAPI_SetDlgItemText($hDlg, $nIDDlgItem, $lpString) ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setdlgitemtextw
    Local $aRet = DllCall("user32.dll", "int", "SetDlgItemText", "hwnd", $hDlg, "int", $nIDDlgItem, "str", $lpString)
    If @error Then Return SetError(@error, @extended, 0)
    Return $aRet[0]
EndFunc   ;==>_WinAPI_SetDlgItemText

Func Min($a, $b)
    Return ($a < $b ? $a : $b)
EndFunc

Func Max($a, $b)
    Return ($a > $b ? $a : $b)
EndFunc

#Region MsgBoxEx
Func _MsgBoxProc($hWnd, $iMsg, $wParam, $lParam)
    If Not $g_hMsgBoxOldProc Then Return _WinAPI_DefWindowProc($hWnd, $iMsg, $wParam, $lParam)
    If $g_Timeout < 0 Or Not _WinAPI_IsWindow($hWnd) Then Return _WinAPI_DefWindowProc($hWnd, $iMsg, $wParam, $lParam)
    
    Switch $iMsg
        Case $WM_CTLCOLORSTATIC, $WM_CTLCOLORDLG, $WM_CTLCOLORBTN
            If Not $g_hMsgBoxBrush Then Return _WinAPI_CallWindowProc($g_hMsgBoxOldProc, $hWnd, $iMsg, $wParam, $lParam)
            
            _WinAPI_SetTextColor($wParam, _ColorToCOLORREF($COLOR_TEXT_LIGHT))
            _WinAPI_SetBkColor($wParam, _ColorToCOLORREF($COLOR_BG_DARK))
            Return $g_hMsgBoxBrush

        Case $WM_ERASEBKGND
            If Not $g_hMsgBoxBrush Then Return _WinAPI_CallWindowProc($g_hMsgBoxOldProc, $hWnd, $iMsg, $wParam, $lParam)

            Local $tRECT = _WinAPI_GetClientRect($hWnd)     
            _WinAPI_FillRect($wParam, $tRECT, $g_hMsgBoxBrush)
            Return 1
            
        Case $WM_PAINT      
            Local $iRet = _WinAPI_CallWindowProc($g_hMsgBoxOldProc, $hWnd, $iMsg, $wParam, $lParam)
            Local $hDC = _WinAPI_GetDC($hWnd)
            Local $tRECT = _WinAPI_GetClientRect($hWnd)
            
            If $g_hMsgBoxBtn Then
                Local $tBtnRect = _WinAPI_GetWindowRect($g_hMsgBoxBtn)
                Local $tPoint = DllStructCreate($tagPOINT)
                $tPoint.x = $tBtnRect.left
                $tPoint.y = $tBtnRect.top
                _WinAPI_ScreenToClient($hWnd, $tPoint)
                $tRECT.top  = $tPoint.y - 10
            EndIf
        
            Local $hBrushFooter = _WinAPI_CreateSolidBrush(_ColorToCOLORREF($COLOR_HOTTRACK_MENU))
            _WinAPI_FillRect($hDC, $tRECT, $hBrushFooter)
            _WinAPI_ReleaseDC($hWnd, $hDC)
            _WinAPI_DeleteObject($hBrushFooter)
            Return $iRet
    
        Case $WM_COMMAND
            If $g_bNCLButtonDown And (BitAND($wParam, 0xFFFF) = $IDOK) Then
                $g_bMsgBoxClosing = True
                Return 0
            EndIf
            Return _WinAPI_CallWindowProc($g_hMsgBoxOldProc, $hWnd, $iMsg, $wParam, $lParam)
    
        Case $WM_NCLBUTTONDOWN
            $g_bNCLButtonDown = True
            Local $iRet = _WinAPI_CallWindowProc($g_hMsgBoxOldProc, $hWnd, $iMsg, $wParam, $lParam)
            $g_bNCLButtonDown = False
            If $g_bMsgBoxClosing Then _WinAPI_PostMessage($hWnd, $WM_COMMAND, $IDOK + 1, 0)
            Return $iRet
    
        Case $WM_CLOSE
            If $g_idTImer Then
                _Timer_KillTimer($hWnd, $g_idTImer)
                $g_idTImer = 0
            EndIf
        
        Case $WM_NCDESTROY
            _WinAPI_SetWindowLong($hWnd, $GWL_WNDPROC, $g_hMsgBoxOldProc)
            Local $hBrush = $g_hMsgBoxBrush
            $g_hMsgBoxBrush = 0

            If $hBrush Then
                _WinAPI_DeleteObject($hBrush)
            EndIf
            
        Case $WM_DESTROY
            If $g_idTImer Then
                _Timer_KillTimer($hWnd, $g_idTImer)
                $g_idTImer = 0
            EndIf
        
            Return _WinAPI_CallWindowProc($g_hMsgBoxOldProc, $hWnd, $iMsg, $wParam, $lParam)
    EndSwitch

    Return _WinAPI_CallWindowProc($g_hMsgBoxOldProc, $hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>_MsgBoxProc

Func _TimerProc($hWnd, $iMsg, $wParam, $lParam)
    If Not _WinAPI_IsWindow($hWnd) Or $g_bMsgBoxClosing Then Return
    If $g_Timeout <= 1 Then
        $g_bMsgBoxClosing = True
        _Timer_KillTimer($hWnd, $g_idTImer)
        $g_idTImer = 0        
        If Not $g_bNCLButtonDown Then _WinAPI_PostMessage($hWnd, $WM_COMMAND, $IDOK + 1, 0)
        Return
    EndIf
    $g_Timeout -= 1
    _WinAPI_SetDlgItemText($hWnd, $IDOK + 1, $g_sBtn1_Txt & " [" & $g_Timeout & "]")
EndFunc   ;==>_TimerProc

Func _CBTHookProc($nCode, $wParam, $lParam)
    If $nCode < 0 Then Return _WinAPI_CallNextHookEx($g_hMsgBoxHook, $nCode, $wParam, $lParam)
    Local Const $hHWND = HWnd($wParam)
    Switch $nCode
        Case $HCBT_ACTIVATE
            If _WinAPI_GetClassName($hHWND) = "#32770" Then
                If $g_bMsgBoxInitialized Then Return _WinAPI_CallNextHookEx($g_hMsgBoxHook, $nCode, $wParam, $lParam)
                $g_bMsgBoxInitialized = True
                
                If $g_Timeout Then $g_idTImer = _Timer_SetTimer($hHWND, 1000, "_TimerProc")
                _WinAPI_SetDlgItemText($wParam, $IDOK, $g_Timeout ? $g_sBtn1_Txt & " [" & $g_Timeout & "]" : $g_sBtn1_Txt)

                ; Dark title + caption colors
                _WinAPI_DwmSetWindowAttribute($hHWND, $DWMWA_USE_IMMERSIVE_DARK_MODE, True) ; immersive dark

                ; optional: remove bright border
                _WinAPI_DwmSetWindowAttribute($hHWND, $DWMWA_BORDER_COLOR, _ColorToCOLORREF(0x303030))
                
                ; caption color
                _WinAPI_DwmSetWindowAttribute($hHWND, $DWMWA_CAPTION_COLOR, _ColorToCOLORREF($COLOR_TITLE_DARK))
                
                ; caption text
                _WinAPI_DwmSetWindowAttribute($hHWND, $DWMWA_TEXT_COLOR, _ColorToCOLORREF($COLOR_TEXT_LIGHT))

                Local $i, $iStyle
                For $i = 0 To 7
                    $hBtn = _WinAPI_GetDlgItem($hHWND, $i)
                    If $hBtn Then
                        $g_hMsgBoxBtn = $hBtn                   
                        _WinAPI_SetWindowTheme($hBtn, "DarkMode_Explorer", 0)
                        _WinAPI_AllowDarkModeForWindow($hBtn, True)
                    EndIf
                Next
                
                ; Dark theme for static controls (text + icon)
                Local $hStatic = _WinAPI_FindWindowEx($hHWND, "Static")
                While $hStatic
                    _WinAPI_AllowDarkModeForWindow($hStatic, True)
                    $hStatic = _WinAPI_FindWindowEx($hHWND, "Static", "", $hStatic)
                WEnd

                $g_hMsgBoxBrush = _WinAPI_CreateSolidBrush(_ColorToCOLORREF($COLOR_BG_DARK))
                $g_hMsgBoxOldProc = _WinAPI_SetWindowLong($hHWND, $GWL_WNDPROC, DllCallbackGetPtr($g_hMsgBoxSubProc))

                _WinAPI_RedrawWindow($hHWND, 0, 0, BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_ALLCHILDREN))
            EndIf
        Case $HCBT_DESTROYWND
            If _WinAPI_GetClassName($hHWND) = "#32770" Then 
                $g_bMsgBoxInitialized = False
                _Timer_KillTimer($hHWND, $g_idTImer)
            EndIf
    EndSwitch
    Return _WinAPI_CallNextHookEx($g_hMsgBoxHook, $nCode, $wParam, $lParam)
EndFunc   ;==>_CBTHookProc

Func MsgBoxEx($sText, $sTitle = Default, $iTimeout = 0, $iFlag = Default, $sBtn_Txt = Default, $hParentHWND = "")
    $g_hMsgBoxBtn = 0
    $g_bMsgBoxClosing = False
    $g_bNCLButtonDown = False
    $g_bMsgBoxInitialized = False
    If $sBtn_Txt <> Default Then $g_sBtn1_Txt = $sBtn_Txt
    If $iFlag = Default Then $iFlag = $g_iFlagDefault
    $g_Timeout = $iTimeout
    Local $hMsgProc = DllCallbackRegister("_CBTHookProc", "int", "uint;wparam;lparam")
    Local Const $hThreadID = _WinAPI_GetCurrentThreadId()
    $g_hMsgBoxHook = _WinAPI_SetWindowsHookEx($WH_CBT, DllCallbackGetPtr($hMsgProc), Null, $hThreadID)
    If $sTitle = Default Then $sTitle = "Information"
    Local Const $iReturn = MsgBox($iFlag, $sTitle, $sText, 0, $hParentHWND)
    If $g_hMsgBoxHook Then _WinAPI_UnhookWindowsHookEx($g_hMsgBoxHook)
    DllCallbackFree($hMsgProc)
    Return $iReturn
EndFunc   ;==>MsgBoxEx
#EndRegion

#Region DarkMode API
Func _WinAPI_ShouldAppsUseDarkMode()
    Local $aResult = DllCall("UxTheme.dll", "bool", 132)
    If @error Then Return SetError(1, 0, False)
    Return ($aResult[0] <> 0)
EndFunc   ;==>_WinAPI_ShouldAppsUseDarkMode

Func _WinAPI_AllowDarkModeForWindow($hWND, $bAllow = True)
    Local $aResult = DllCall("UxTheme.dll", "bool", 133, "hwnd", $hWND, "bool", $bAllow)
    If @error Then Return SetError(1, 0, False)
    Return ($aResult[0] <> 0)
EndFunc   ;==>_WinAPI_AllowDarkModeForWindow

Func _WinAPI_FlushMenuThemes()
    Local $aResult = DllCall("UxTheme.dll", "none", 136)
    If @error Then Return SetError(1, 0, False)
    Return True
EndFunc   ;==>_WinAPI_FlushMenuThemes

Func _WinAPI_RefreshImmersiveColorPolicyState()
    Local $aResult = DllCall("UxTheme.dll", "none", 104)
    If @error Then Return SetError(1, 0, False)
    Return True
EndFunc   ;==>_WinAPI_RefreshImmersiveColorPolicyState

Func _WinAPI_IsDarkModeAllowedForWindow($hWND)
    Local $aResult = DllCall("UxTheme.dll", "bool", 137, "hwnd", $hWND)
    If @error Then Return SetError(1, 0, False)
    Return ($aResult[0] <> 0)
EndFunc   ;==>_WinAPI_IsDarkModeAllowedForWindow

Func _WinAPI_GetIsImmersiveColorUsingHighContrast($iIMMERSIVE_HC_CACHE_MODE)
    Local $aResult = DllCall("UxTheme.dll", "bool", 106, "long", $iIMMERSIVE_HC_CACHE_MODE)
    If @error Then Return SetError(1, 0, False)
    Return ($aResult[0] <> 0)
EndFunc   ;==>_WinAPI_GetIsImmersiveColorUsingHighContrast

Func _WinAPI_OpenNcThemeData($hWND, $tClassList)
    Local $aResult = DllCall("UxTheme.dll", "hwnd", 49, "hwnd", $hWND, "struct*", $tClassList)
    If @error Then Return SetError(1, 0, False)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_OpenNcThemeData

Func _WinAPI_ShouldSystemUseDarkMode()
    Local $aResult = DllCall("UxTheme.dll", "bool", 138)
    If @error Then Return SetError(1, 0, False)
    Return ($aResult[0] <> 0)
EndFunc   ;==>_WinAPI_ShouldSystemUseDarkMode

Func _WinAPI_IsDarkModeAllowedForApp()
    Local $aResult = DllCall("UxTheme.dll", "bool", 139)
    If @error Then Return SetError(1, 0, False)
    Return ($aResult[0] <> 0)
EndFunc   ;==>_WinAPI_IsDarkModeAllowedForApp

Func _WinAPI_AllowDarkModeForApp($bAllow = True) ;Windows 10 Build 17763
    Return _WinAPI_SetPreferredAppMode($bAllow ? 1 : 0) ; 1 = AllowDark, 0 = Default
EndFunc   ;==>_WinAPI_AllowDarkModeForApp

Func _WinAPI_SetPreferredAppMode($iPreferredAppMode) ;Windows 10 Build 18362+
    Local $aResult = DllCall("UxTheme.dll", "long", 135, "long", $iPreferredAppMode)
    If @error Then Return SetError(1, 0, False)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_SetPreferredAppMode
#EndRegion DarkMode API

#Region WinAPI DPI
;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-aredpiawarenesscontextsequal
Func _WinAPI_AreDpiAwarenessContextsEqual($dpiContextA, $dpiContextB)
    Local $aResult = DllCall("user32.dll", "bool", "AreDpiAwarenessContextsEqual", _    ;Win10 1607+
            @AutoItX64 ? "int64" : "int", $dpiContextA, _
            @AutoItX64 ? "int64" : "int", $dpiContextB)
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, False)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_AreDpiAwarenessContextsEqual

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enablenonclientdpiscaling
Func _WinAPI_EnableNonClientDpiScaling($hWnd)
    Local $aResult = DllCall("user32.dll", "bool", "EnableNonClientDpiScaling", "hwnd", $hWnd)    ;Win10 1607+
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_EnableNonClientDpiScaling

;https://learn.microsoft.com/en-us/windows/win32/api/uxtheme/nf-uxtheme-openthemedatafordpi
Func _WinAPI_OpenThemeDataForDpi($hWnd, $pszClassList, $dpi)
    Local $aResult = DllCall("uxtheme.dll", "handle", "OpenThemeDataForDpi", "hwnd", $hWnd, "wstr", $pszClassList, "uint", $dpi)    ;Win10 1703+
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_OpenThemeDataForDpi

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-adjustwindowrectexfordpi
Func _WinAPI_AdjustWindowRectExForDpi($dpi, $dwStyle, $dwExStyle, $bMenu = False)
    Local $tRECT = DllStructCreate($tagRECT)
    Local $aResult = DllCall("user32.dll", "bool", "AdjustWindowRectExForDpi", "struct*", $tRECT, "dword", $dwStyle, "bool", $bMenu, "dword", $dwExStyle, "int", $dpi) ;requires Win10 v1607+ / no server support
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $tRECT
EndFunc   ;==>_WinAPI_AdjustWindowRectExForDpi

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfofordpi
Func _WinAPI_SystemParametersInfoForDpi($uiAction, $uiParam, $pvParam, $fWinIni, $dpi)
    Local $aResult = DllCall("user32.dll", "bool", "SystemParametersInfoForDpi", "uint", $uiAction, "uint", $uiParam, "struct*", $pvParam, "uint", $fWinIni, "uint", $dpi) ;requires Win10 v1607+ / no server support
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_SystemParametersInfoForDpi

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-inheritwindowmonitor
Func _WinAPI_InheritWindowMonitor($hWnd, $hWndInherit)
    Local $aResult = DllCall("user32.dll", "bool", "InheritWindowMonitor", "hwnd", $hWnd, "hwnd", $hWndInherit) ;requires Win10 v1803+ / Windows Server 2016+
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_InheritWindowMonitor

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-isvaliddpiawarenesscontext
Func _WinAPI_IsValidDpiAwarenessContext($DPI_AWARENESS_CONTEXT_value)
    Local $aResult = DllCall("user32.dll", "bool", "IsValidDpiAwarenessContext", @AutoItX64 ? "int64" : "int", $DPI_AWARENESS_CONTEXT_value) ;requires Win10 v1607+ / no server support
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_IsValidDpiAwarenessContext

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-logicaltophysicalpointforpermonitordpi
Func _WinAPI_LogicalToPhysicalPointForPerMonitorDPI($hWnd, $iX, $iY)
    Local $tPOINT = DllStructCreate($tagPOINT)
    $tPOINT.x = $iX
    $tPOINT.y = $iY
    Local $aResult = DllCall("user32.dll", "bool", "LogicalToPhysicalPointForPerMonitorDPI", "hwnd", $hWnd, "struct*", $tPOINT) ;requires Win 8.1+ / no server support
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $tPOINT
EndFunc   ;==>_WinAPI_LogicalToPhysicalPointForPerMonitorDPI

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-physicaltologicalpointforpermonitordpi
Func _WinAPI_PhysicalToLogicalPointForPerMonitorDPI($hWnd, $iX, $iY)
    Local $tPOINT = DllStructCreate($tagPOINT)
    $tPOINT.X = $iX
    $tPOINT.Y = $iY
    Local $aResult = DllCall("user32.dll", "bool", "PhysicalToLogicalPointForPerMonitorDPI", "hwnd", $hWnd, "struct*", $tPOINT) ;requires Win 8.1+ / no server support
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $tPOINT
EndFunc   ;==>_WinAPI_PhysicalToLogicalPointForPerMonitorDPI

Func _GDIPlus_GetDPI($hGUI = 0)
    Local $hGfx = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    If @error Then Return SetError(1, @extended, 0)
    Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipGetDpiX", "handle", $hGfx, "float*", 0)
    If @error Then Return SetError(2, @extended, 0)
    _GDIPlus_GraphicsDispose($hGfx)
    Return $aResult[2]
EndFunc   ;==>_GDIPlus_GetDPI

Func _WinAPI_GetDPI($hWnd = 0)
    $hWnd = (Not $hWnd ? _WinAPI_GetDesktopWindow() : $hWnd)
    Local Const $hDC = _WinAPI_GetDC($hWnd)
    If @error Then Return SetError(1, 0, 0)
    Local Const $iDPI = _WinAPI_GetDeviceCaps($hDC, $LOGPIXELSX)
    If @error Or Not $iDPI Then
        _WinAPI_ReleaseDC($hWnd, $hDC)
        Return SetError(2, 0, 0)
    EndIf
    _WinAPI_ReleaseDC($hWnd, $hDC)
    Return $iDPI
EndFunc   ;==>_WinAPI_GetDPI 

;https://learn.microsoft.com/en-us/windows/win32/api/shellscalingapi/nf-shellscalingapi-getdpiformonitor
Func _WinAPI_GetDpiForMonitor($hMonitor = 0, $dpiType = $MDT_DEFAULT)
    If $hMonitor = 0 Then
        Local $aMonitors = _WinAPI_EnumDisplayMonitors()
        If @error Or Not IsArray($aMonitors) Then Return SetError(1, 0, 0)
        Local $i
        For $i = 1 To $aMonitors[0][0]
            If _WinAPI_GetMonitorInfo($aMonitors[$i][0])[2] = 1 Then
                $hMonitor = $aMonitors[$i][0]
                ExitLoop
            EndIf
        Next
    EndIf
    Local $tx = DllStructCreate("uint dpiX"), $tY = DllStructCreate("uint dpiY")
    Local $aResult = DllCall("Shcore.dll", "long", "GetDpiForMonitor", "handle", $hMonitor, "long", $dpiType, "struct*", $tx, "struct*", $tY)
    If @error Or Not IsArray($aResult) Then Return SetError(2, 0, 0)
    If $aResult[0] <> 0 Then Return SetError(3, $aResult[0], 0)
    Return $tx.dpiX
EndFunc   ;==>_WinAPI_GetDpiForMonitor

;https://learn.microsoft.com/en-us/windows/win32/api/shellscalingapi/nf-shellscalingapi-getdpiformonitor
Func _WinAPI_GetDpiForMonitor2($hMonitor, $dpiType = $MDT_EFFECTIVE_DPI)
    Local $tDpiX = DllStructCreate("uint dpiX")
    Local $tDpiY = DllStructCreate("uint dpiY")
    Local $aResult = DllCall("Shcore.dll", "long", "GetDpiForMonitor", _                ;Win8.1+
            "handle", $hMonitor, _
            "int", $dpiType, _
            "struct*", $tDpiX, _
            "struct*", $tDpiY)
    If @error Or Not IsArray($aResult) Then Return SetError(1, @error, 0)
    If $aResult[0] <> 0 Then Return SetError(2, $aResult[0], 0) ; HRESULT check

    Local $aReturn[2] = [DllStructGetData($tDpiX, "dpiX"), DllStructGetData($tDpiY, "dpiY")]
    Return $aReturn ; Returns both X and Y DPI
EndFunc   ;==>_WinAPI_GetDpiForMonitor2

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpiforwindow
Func _WinAPI_GetDpiForWindow($hWnd)
    Local $aResult = DllCall("user32.dll", "uint", "GetDpiForWindow", "hwnd", $hWnd) ;requires Win10 v1607+ / no server support
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_GetDpiForWindow

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpiforsystem
Func _WinAPI_GetDpiForSystem()
    Local $aResult = DllCall("user32.dll", "uint", "GetDpiForSystem") ;requires Win10 v1607+ / no server support
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_GetDpiForSystem

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getthreaddpiawarenesscontext
Func _WinAPI_GetThreadDpiAwarenessContext()
    Local $aResult = DllCall("user32.dll", (@AutoItX64 ? "int64" : "int"), "GetThreadDpiAwarenessContext") ;requires Win10 v1607+ / no server support
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_GetThreadDpiAwarenessContext

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpifromdpiawarenesscontext
Func _WinAPI_GetDpiFromDpiAwarenessContext($DPI_AWARENESS_CONTEXT_value)
    Local $aResult = DllCall("user32.dll", "uint", "GetDpiFromDpiAwarenessContext", @AutoItX64 ? "int64" : "int", $DPI_AWARENESS_CONTEXT_value) ;requires Win10 v1803+ / Windows Server 2016+
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_GetDpiFromDpiAwarenessContext

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getawarenessfromdpiawarenesscontext
Func _WinAPI_GetAwarenessFromDpiAwarenessContext($DPI_AWARENESS_CONTEXT_value)
    Local $aResult = DllCall("user32.dll", "uint", "GetAwarenessFromDpiAwarenessContext", @AutoItX64 ? "int64" : "int", $DPI_AWARENESS_CONTEXT_value) ;requires Win10 v1607+ / no server support
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_GetAwarenessFromDpiAwarenessContext

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpiawarenesscontextforprocess
Func _WinAPI_GetDpiAwarenessContextForProcess($hProcess)
    Local $aResult = DllCall("user32.dll", (@AutoItX64 ? "int64" : "int"), "GetDpiAwarenessContextForProcess", "handle", $hProcess) ;requires Win10 v1803+ / Windows Server 2016+
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_GetDpiAwarenessContextForProcess

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemdpiforprocess
Func _WinAPI_GetSystemDpiForProcess($hProcess)
    Local $aResult = DllCall("user32.dll", "uint", "GetSystemDpiForProcess", "handle", $hProcess) ;requires Win10 v1803+ / Windows Server 2016+
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_GetSystemDpiForProcess

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowdpiawarenesscontext
Func _WinAPI_GetWindowDpiAwarenessContext($hWnd)
    Local $aResult = DllCall("user32.dll", (@AutoItX64 ? "int64" : "int"), "GetWindowDpiAwarenessContext", "hwnd", $hWnd) ;requires Win10 v1607+ / no server support
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_GetWindowDpiAwarenessContext

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemmetricsfordpi
Func _WinAPI_GetSystemMetricsForDpi($nIndex, $dpi)
    Local $aResult = DllCall("user32.dll", "int", "GetSystemMetricsForDpi", "int", $nIndex, "uint", $dpi)    ;Win10 1607+
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_GetSystemMetricsForDpi

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setdialogdpichangebehavior
Func _WinAPI_GetDialogDpiChangeBehavior($hWnd)
    Local $aResult = DllCall("user32.dll", "int", "GetDialogDpiChangeBehavior", "hwnd", $hWnd)    ;Win10 1703+
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_GetDialogDpiChangeBehavior

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setdialogcontroldpichangebehavior
Func _WinAPI_GetDialogControlDpiChangeBehavior($hWnd)
    Local $aResult = DllCall("user32.dll", "int", "GetDialogControlDpiChangeBehavior", "hwnd", $hWnd)    ;Win10 1703+
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_GetDialogControlDpiChangeBehavior

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setprocessdpiawarenesscontext
Func _WinAPI_SetProcessDpiAwarenessContext($DPI_AWARENESS_CONTEXT_value)
    Local $aResult = DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", $DPI_AWARENESS_CONTEXT_value) ;requires Win10 v1703+ / Windows Server 2016+
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_SetProcessDpiAwarenessContext

;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setthreaddpiawarenesscontext
Func _WinAPI_SetThreadDpiAwarenessContext($DPI_AWARENESS_CONTEXT_value)
    Local $aResult = DllCall("user32.dll", (@AutoItX64 ? "int64" : "int"), "SetThreadDpiAwarenessContext", @AutoItX64 ? "int64" : "int", $DPI_AWARENESS_CONTEXT_value) ;requires Win10 v1703+ / Windows Server 2016+
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_SetThreadDpiAwarenessContext

;https://learn.microsoft.com/en-us/windows/win32/api/shellscalingapi/nf-shellscalingapi-setprocessdpiawareness
Func _WinAPI_SetProcessDpiAwareness($PROCESS_DPI_AWARENESS = $DPI_AWARENESS_PER_MONITOR_AWARE)
    Local $aResult = DllCall("Shcore.dll", "long", "SetProcessDpiAwareness", "int", $PROCESS_DPI_AWARENESS) ;requires Win 8.1+ / Server 2012 R2+
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If $aResult[0] Then Return SetError(2, $aResult[0], 0)
    Return 1
EndFunc   ;==>_WinAPI_SetProcessDpiAwareness

Func _WinAPI_SetDPIAwareness($iAwarenessLevel = $DPI_AWARENESS_PER_MONITOR_AWARE, $iMode = 1)
    If @OSBuild < 6000 Then Return SetError(100, 0, 0)

    ; $iAwarenessLevel unified for all Windows versions:
    ; 0 = UNAWARE
    ; 1 = SYSTEM_AWARE
    ; 2 = PER_MONITOR_AWARE (default)
    ; 3 = PER_MONITOR_AWARE_V2 (Win10 1703+ only)
    ; 4 = UNAWARE_GDISCALED (Win10 1803+ only)

    $iAwarenessLevel = ($iAwarenessLevel < 0) ? (-$iAwarenessLevel - 1) : ($iAwarenessLevel > 4) ? 4 : $iAwarenessLevel
    Switch @OSBuild
        Case 6000 To 9199  ; Vista - Windows 8
            Local $aResult = DllCall("user32.dll", "bool", "SetProcessDPIAware")
            If Not IsArray($aResult) Or Not $aResult[0] Then Return SetError(1, 0, 0)

        Case 9200 To 13999  ; Windows 8.1 - Windows 10 Build 14393
            ; Limit to 0-2 for this version
            Local $iLegacyLevel = ($iAwarenessLevel > 2) ? 2 : $iAwarenessLevel
            If _WinAPI_SetProcessDpiAwareness($iLegacyLevel) = 0 Then Return SetError(2, @error, 0)

        Case Else  ; Windows 10 Build 14393+
            ; Convert to DPI_AWARENESS_CONTEXT values
            Local $aContextMap[5] = [$DPI_AWARENESS_CONTEXT_UNAWARE, _               ; -1
                    $DPI_AWARENESS_CONTEXT_SYSTEM_AWARE, _                           ; -2
                    $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE, _                      ; -3
                    $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, _                   ; -4
                    $DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED _                       ; -5
                    ]

            ; Limit V2 and GDISCALED to compatible Windows versions
            If $iAwarenessLevel = 3 And @OSBuild < 15063 Then $iAwarenessLevel = 2  ; V2 requires 1703+
            If $iAwarenessLevel = 4 And @OSBuild < 17134 Then $iAwarenessLevel = 2  ; GDISCALED requires 1803+

            Local $iDpiContext = $aContextMap[$iAwarenessLevel]
            $iMode = ($iMode < 1) ? 1 : ($iMode > 2) ? 2 : $iMode

            Local $iResult
            Switch $iMode
                Case 1  ; Process-wide setting
                    $iResult = _WinAPI_SetProcessDpiAwarenessContext($iDpiContext)
                    If Not $iResult Or @error Then Return SetError(3, @error, 0)
                Case 2  ; Thread-specific setting
                    $iResult = _WinAPI_SetThreadDpiAwarenessContext($iDpiContext)
                    If Not $iResult Or @error Then Return SetError(4, @error, 0)
            EndSwitch
    EndSwitch

    ; Retrieve DPI value
    Local $iDPI
    If @OSBuild < 9200 Then
        $iDPI = _WinAPI_GetDPI()
        If @error Or Not $iDPI Then Return SetError(5, 0, 0)
    Else
        $iDPI = _WinAPI_GetDpiForMonitor()
        If @error Or Not $iDPI Then Return SetError(6, 0, 0)
    EndIf

    Return $iDPI
EndFunc   ;==>_WinAPI_SetDPIAwareness

Func _WinAPI_SetDialogDpiChangeBehavior($hWnd, $mask, $values)
    Local $aResult = DllCall("user32.dll", "bool", "SetDialogDpiChangeBehavior", "hwnd", $hWnd, "int", $mask, "int", $values)    ;Win10 1703+
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_SetDialogDpiChangeBehavior

Func _WinAPI_SetDialogControlDpiChangeBehavior($hWnd, $mask, $values)
    Local $aResult = DllCall("user32.dll", "bool", "SetDialogControlDpiChangeBehavior", "hwnd", $hWnd, "int", $mask, "int", $values)    ;Win10 1703+
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_SetDialogControlDpiChangeBehavior

#EndRegion WinAPI DPI

 

Edited by WildByDesign
Posted

I created a function so that we can get the colors from the Static (label) controls before the GUI is shown so that other decisions can be made based on colors. This is my first time making a function with ByRef. But it works. It returns TextColor, BkColor and BkMode.

Func __GUIDarkTheme_GetCtrlColors($hWnd, ByRef $iTextColor, ByRef $iBkColor, ByRef $iBkMode)
    Local $hDC = _WinAPI_GetDC($hWnd)
    Local $hBrushTemp = _SendMessage(_WinAPI_GetParent($hWnd), $WM_CTLCOLORSTATIC, $hDC, $hWnd)
    Local $iColor = _WinAPI_GetBkColor($hDC)
    $iTextColor = "0x" & Hex(_WinAPI_GetTextColor($hDC), 6)
    $iBkColor = "0x" & Hex(_WinAPI_GetBkColor($hDC), 6)
    $iBkMode = _WinAPI_GetBkMode($hDC)
    $hBrushTemp = _WinAPI_SelectObject($hDC, $hBrushTemp)
    _WinAPI_ReleaseDC($hWnd, $hDC)
EndFunc   ;==>__GUIDarkTheme_GetCtrlColors

Now I just have to figure out more logic stuff of what to do with colors (if it should be inverted and when).

Posted

So example, in the _GUIDarkTheme_GUICtrlSetDarkTheme() function I have:

Case 'Static'
    Local $iTextColor, $iBkColor, $iBkMode
    __GUIDarkTheme_GetCtrlColors($vCtrl, $iTextColor, $iBkColor, $iBkMode)
    ConsoleWrite("TextColor: " & $iTextColor & @CRLF)
    ConsoleWrite("BkColor:   " & $iBkColor & @CRLF)
    ConsoleWrite("BkMode:    " & $iBkMode & @CRLF)

This gives me insight into colors as early as possible.

Posted

I am kind of shocked but I did it. I got the Static controls under control and working perfectly with theme changes and material changes. I had to dig into the Static styles as well just to make it happen. So having all control styles available for Static controls (and some other stuff with buttons) has been extremely useful for fine tuning everything.

Anyway, I've just got to clean up the code from my many (many, many) failed attempts before finally getting it right. So I should be able to do a new release in a few hours.

Posted

GUIDarkTheme 2.1.0:

  • Automatic theme changes to follow system color theme
    • Added __GUIDarkTheme_WM_SETTINGCHANGE function to monitor system theme changes (thanks to @argumentum)
    • Added _GUIDarkTheme_ApplyAuto function for users who want to follow system theme from GUI init
    • Added _GUIDarkTheme_AutoTheme function to pass boolean to enable/disable auto-theme (if user has menu option or similar)
  • Significant work on the behavior of Static (label) controls during theme and material changes
    • Added __GUIDarkTheme_IsCtrlInTab internal function to know if control is within tab control (thanks to @ioa747
    • Added __GUIDarkTheme_GetCtrlColors function to obtain TextColor, BkColor and BkMode from Static controls (therefore brush colors)
    • Added __GUIDarkTheme_WM_CTLCOLOR where all of the Static control magic happens
    • Standard black or white text colors invert during theme changes while custom user colors remain the same
    • Standard background brush colors invert during theme changes while custom user colors remain the same (eg. 0x00FF00)
    • Removed all manual fixes from SampleControls-Demo that fixed custom colors after each theme change

There are probably more changes and fixes that went into this release that I have simply forgotten. I was intending to do one feature for this release and I just could not stop the ideas from flowing. So it's a pretty nice release.

Theme changes and material changes are smooth. Automatic theme changes following system theme work very well. Thanks to @mLipok for requesting/suggesting this feature.

Time for another coffee. I'm exhausted. 

For once, I think I may be out of ideas at the moment.

Posted (edited)

@WildByDesign you UDF is for _GUIDarkTheme_* .... ahhhh... wondering why not for Theme at all ?
EDIT:

rewordering:

you UDF is for _GUIDarkTheme_* .... ahhhh... wondering why not for all possible Theme cases?

Edited by mLipok

Signature beginning:
Please remember: "AutoIt"..... *  Wondering who uses AutoIt and what it can be used for ? * Forum Rules *
ADO.au3 UDF * POP3.au3 UDF * XML.au3 UDF * IE on Windows 11 * How to ask ChatGPT for AutoIt Codefor other useful stuff click the following button:

Spoiler

Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind. 

My contribution (my own projects): * Debenu Quick PDF Library - UDF * Debenu PDF Viewer SDK - UDF * Acrobat Reader - ActiveX Viewer * UDF for PDFCreator v1.x.x * XZip - UDF * AppCompatFlags UDF * CrowdinAPI UDF * _WinMergeCompare2Files() * _JavaExceptionAdd() * _IsBeta() * Writing DPI Awareness App - workaround * _AutoIt_RequiredVersion() * Chilkatsoft.au3 UDF * TeamViewer.au3 UDF * JavaManagement UDF * VIES over SOAP * WinSCP UDF * GHAPI UDF - modest begining - comunication with GitHub REST APIErrorLog.au3 UDF - A logging Library * Include Dependency Tree (Tool for analyzing script relations) * Show_Macro_Values.au3 *

 

My contribution to others projects or UDF based on  others projects: * _sql.au3 UDF  * POP3.au3 UDF *  RTF Printer - UDF * XML.au3 UDF * ADO.au3 UDF SMTP Mailer UDF * Dual Monitor resolution detection * * 2GUI on Dual Monitor System * _SciLexer.au3 UDF * SciTE - Lexer for console pane

Useful links: * Forum Rules * Forum etiquette *  Forum Information and FAQs * How to post code on the forum * AutoIt Online Documentation * AutoIt Online Beta Documentation * SciTE4AutoIt3 getting started * Convert text blocks to AutoIt code * Games made in Autoit * Programming related sites * Polish AutoIt Tutorial * DllCall Code Generator * 

Wiki: Expand your knowledge - AutoIt Wiki * Collection of User Defined Functions * How to use HelpFile * Good coding practices in AutoIt * 

OpenOffice/LibreOffice/XLS Related: WriterDemo.au3 * XLS/MDB from scratch with ADOX

IE Related:  * How to use IE.au3  UDF with  AutoIt v3.3.14.x * Why isn't Autoit able to click a Javascript Dialog? * Clicking javascript button with no ID * IE document >> save as MHT file * IETab Switcher (by LarsJ ) * HTML Entities * _IEquerySelectorAll() (by uncommon) * IE in TaskSchedulerIE Embedded Control Versioning (use IE9+ and HTML5 in a GUI) * PDF Related:How to get reference to PDF object embeded in IE * IE on Windows 11

I encourage you to read: * Global Vars * Best Coding Practices * Please explain code used in Help file for several File functions * OOP-like approach in AutoIt * UDF-Spec Questions *  EXAMPLE: How To Catch ConsoleWrite() output to a file or to CMD *

I also encourage you to check awesome @trancexx code:  * Create COM objects from modules without any demand on user to register anything. * Another COM object registering stuffOnHungApp handlerAvoid "AutoIt Error" message box in unknown errors  * HTML editor

winhttp.au3 related : * https://www.autoitscript.com/forum/topic/206771-winhttpau3-download-problem-youre-speaking-plain-http-to-an-ssl-enabled-server-port/

"Homo sum; humani nil a me alienum puto" - Publius Terentius Afer
"Program are meant to be read by humans and only incidentally for computers and execute" - Donald Knuth, "The Art of Computer Programming"
:naughty:  :ranting:, be  :) and       \\//_.

Anticipating Errors :  "Any program that accepts data from a user must include code to validate that data before sending it to the data store. You cannot rely on the data store, ...., or even your programming language to notify you of problems. You must check every byte entered by your users, making sure that data is the correct type for its field and that required fields are not empty."

Signature last update: 2023-04-24

Posted
16 minutes ago, mLipok said:

you UDF is for _GUIDarkTheme_* .... ahhhh... wondering why not for all possible Theme cases?

You have a very good point. :)

Even though I don't personally use light mode myself, I realize that the light mode GUI and controls are much more modern compared to default AutoIt GUI and controls since this UDF enforced the theming.

So you are probably right. Maybe it should be something like GUIModernTheme?

I just don't know if that will make it harder for people seeking dark mode to find it.

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...