WildByDesign Posted May 28 Posted May 28 (edited) I have made some success so far with subclassing a checkbox control but I need some help, please. This is intended for Windows 11 (24H2 and earlier) builds where there is a nice checkbox but the text is black. Unfortunately I've got to go out for most of the day but I've tried to comment the code as best as I can and there is some good success going on. If anyone can help improve the positioning and alignment and things like that to extend or improve, please feel free to help. Thank you so much. And by the way, if this becomes successful (when it becomes successful), we should very easily be able to extend this to radio controls as well. expandcollapse popup#include <WinAPITheme.au3> #include <WinAPIGdi.au3> #include <APIGdiConstants.au3> #include <StructureConstants.au3> #include <WindowsNotifsConstants.au3> #include <WinAPISysInternals.au3> #include <WinAPIShellEx.au3> #include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> ; Initialize System DPI awareness DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2) Example() Func Example() ; Create a GUI with various controls. Local $hGUI = GUICreate("Example", 300, 200) GUISetBkColor("0x202020") ; Create a checkbox control. Local $idCheckbox = GUICtrlCreateCheckbox("Standard Checkbox", 69, 60, 185, 25) Local $idButton_Close = GUICtrlCreateButton("Close", 210, 170, 85, 25) Local $hCheckbox = GUICtrlGetHandle($idCheckbox) ; Register Subclassing / Window Procedure Local $pAddress = _WinAPI_GetWindowLong($hCheckbox, $GWL_WNDPROC) Local $hSubclass = DllCallbackRegister(_CheckboxProc, "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr") _WinAPI_SetWindowSubclass($hCheckbox, DllCallbackGetPtr($hSubclass), $idCheckbox, $pAddress) ; Display the GUI. GUISetState(@SW_SHOW, $hGUI) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idButton_Close ExitLoop Case $idCheckbox If _IsChecked($idCheckbox) Then MsgBox($MB_SYSTEMMODAL, "", "The checkbox is checked.", 0, $hGUI) Else MsgBox($MB_SYSTEMMODAL, "", "The checkbox is not checked.", 0, $hGUI) EndIf EndSwitch WEnd ; Cleanup: Restore original Window Procedure _WinAPI_RemoveWindowSubclass($hCheckbox, DllCallbackGetPtr($hSubclass), $idCheckbox) DllCallbackFree($hSubclass) ; Delete the previous GUI and all controls. GUIDelete($hGUI) EndFunc ;==>Example Func _IsChecked($idControlID) Return BitAND(GUICtrlRead($idControlID), $GUI_CHECKED) = $GUI_CHECKED EndFunc ;==>_IsChecked Func _CheckboxProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) Local Static $bHover, $tPoint Switch $iMsg Case $WM_ERASEBKGND Return 1 ; Prevent background erasing to avoid flickering ;Case $WM_PRINTCLIENT Case $WM_PAINT Local Const $BP_CHECKBOX = 3 ; checkbox StateID Local Const $CBS_UNCHECKEDNORMAL = 1 Local Const $CBS_UNCHECKEDHOT = 2 Local Const $CBS_UNCHECKEDPRESSED = 3 Local Const $CBS_UNCHECKEDDISABLED = 4 Local Const $CBS_CHECKEDNORMAL = 5 Local Const $CBS_CHECKEDHOT = 6 Local Const $CBS_CHECKEDPRESSED = 7 Local Const $CBS_CHECKEDDISABLED = 8 Local Const $CBS_MIXEDNORMAL = 9 Local Const $CBS_MIXEDHOT = 10 Local Const $CBS_MIXEDPRESSED = 11 Local Const $CBS_MIXEDDISABLED = 12 Local $hTheme = _WinAPI_OpenThemeData($hWnd, "DarkMode_Explorer::Button") Local $tPaint = DllStructCreate($tagPAINTSTRUCT) Local $hDC = _WinAPI_BeginPaint($hWnd, $tPaint) ; need to get PartID and StateID ; https://learn.microsoft.com/en-us/windows/win32/controls/parts-and-states ; GetThemeBackgroundContentRect ; _WinAPI_GetThemeBackgroundContentRect (not done yet) Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $BP_CHECKBOX, 0, Null, Null, $TS_TRUE) ConsoleWrite("checkbox size: " & $tSIZE.X & @CRLF) ; DrawThemeParentBackground ; _WinAPI_DrawThemeParentBackground (not done yet) ; DrawThemeBackground Local $tRect = _WinAPI_CreateRectEx(0, 0, $tSIZE.X, $tSIZE.Y) _WinAPI_DrawThemeBackground($hTheme, $BP_CHECKBOX, $CBS_CHECKEDNORMAL, $hDC, $tRect) Local $sText = _WinAPI_GetWindowText($hWnd) ConsoleWrite("button text: " & $sText & @CRLF) ; Setup font Local $hFont = _SendMessage($hWnd, $WM_GETFONT, 0, 0) If Not $hFont Then $hFont = _WinAPI_GetStockObject($DEFAULT_GUI_FONT) Local $hOldFont = _WinAPI_SelectObject($hDC, $hFont) _WinAPI_SetBkMode($hDC, $TRANSPARENT) _WinAPI_SetTextColor($hDC, _WinAPI_SwitchColor(0xFFFFFF)) Local $tTextRect = DllStructCreate($tagRECT) DllCall("user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sText, "int", -1, "struct*", $tTextRect, "uint", BitOR($DT_CENTER, $DT_VCENTER, $DT_SINGLELINE, $DT_NOPREFIX, $DT_NOCLIP)) ; cleanup _WinAPI_SelectObject($hDC, $hOldFont) _WinAPI_CloseThemeData($hTheme) _WinAPI_EndPaint($hWnd, $tPaint) Return 0 EndSwitch Return __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>_CheckboxProc Func __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) Return DllCall('comctl32.dll', 'lresult', 'DefSubclassProc', 'hwnd', $hWnd, 'uint', $iMsg, 'wparam', $wParam, _ 'lparam', $lParam)[0] EndFunc ;==>__WinAPI_DefSubclassProc Edited May 28 by WildByDesign updated example
WildByDesign Posted May 28 Author Posted May 28 Not at my PC right now, but I was thinking that we should probably have the theme handle as Static because otherwise it is opening and closing the theme file hundreds of times. We should be able to close the theme in a WM_DESTROY message. The theme part measurements likely should be Static as well except for text.
WildByDesign Posted May 28 Author Posted May 28 @argumentum I need your help if you have a moment. Particularly, if you can test the following script on 24H2. Please keep in mind that the code is a messy while I'm figuring it out. The text alignment is way off. But the main question is, does it work? Do you get white text on 24H2? If yes, then I can start to clean it up. I got the checkbox states working as far as I can tell. expandcollapse popup#include <GuiButton.au3> #include <APIThemeConstants.au3> #include <WinAPITheme.au3> #include <WinAPIGdi.au3> #include <APIGdiConstants.au3> #include <StructureConstants.au3> #include <WindowsNotifsConstants.au3> #include <WinAPISysInternals.au3> #include <WinAPIShellEx.au3> #include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> ; Initialize System DPI awareness DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2) Example() Func Example() ; Create a GUI with various controls. Local $hGUI = GUICreate("Example", 300, 200) GUISetBkColor("0x202020") ; Create a checkbox control. Local $idCheckbox = GUICtrlCreateCheckbox("Standard Checkbox", 69, 60, 185, 25) Local $idButton_Close = GUICtrlCreateButton("Close", 210, 170, 85, 25) Local $hCheckbox = GUICtrlGetHandle($idCheckbox) ; Register Subclassing / Window Procedure Local $pAddress = _WinAPI_GetWindowLong($hCheckbox, $GWL_WNDPROC) Local $hSubclass = DllCallbackRegister(_CheckboxProc, "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr") _WinAPI_SetWindowSubclass($hCheckbox, DllCallbackGetPtr($hSubclass), $idCheckbox, $pAddress) ; Display the GUI. GUISetState(@SW_SHOW, $hGUI) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idButton_Close ExitLoop Case $idCheckbox If _IsChecked($idCheckbox) Then ;MsgBox($MB_SYSTEMMODAL, "", "The checkbox is checked.", 0, $hGUI) ConsoleWrite("The checkbox is checked." & @CRLF) Else ;MsgBox($MB_SYSTEMMODAL, "", "The checkbox is not checked.", 0, $hGUI) ConsoleWrite("The checkbox is not checked." & @CRLF) EndIf EndSwitch WEnd ; Cleanup: Restore original Window Procedure _WinAPI_RemoveWindowSubclass($hCheckbox, DllCallbackGetPtr($hSubclass), $idCheckbox) DllCallbackFree($hSubclass) ; Delete the previous GUI and all controls. GUIDelete($hGUI) EndFunc ;==>Example Func _IsChecked($idControlID) Return BitAND(GUICtrlRead($idControlID), $GUI_CHECKED) = $GUI_CHECKED EndFunc ;==>_IsChecked Func _CheckboxProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) Local Static $bHover, $tPoint Switch $iMsg Case $WM_ERASEBKGND Return 1 ; Prevent background erasing to avoid flickering ;Case $WM_PRINTCLIENT Case $WM_PAINT Local $iStateID = 0 Local Const $BP_CHECKBOX = 3 Local Const $BST_HOT = 0x0200 ; checkbox StateID Local Const $CBS_UNCHECKEDNORMAL = 1 Local Const $CBS_UNCHECKEDHOT = 2 Local Const $CBS_UNCHECKEDPRESSED = 3 Local Const $CBS_UNCHECKEDDISABLED = 4 Local Const $CBS_CHECKEDNORMAL = 5 Local Const $CBS_CHECKEDHOT = 6 Local Const $CBS_CHECKEDPRESSED = 7 Local Const $CBS_CHECKEDDISABLED = 8 Local Const $CBS_MIXEDNORMAL = 9 Local Const $CBS_MIXEDHOT = 10 Local Const $CBS_MIXEDPRESSED = 11 Local Const $CBS_MIXEDDISABLED = 12 Local $hTheme = _WinAPI_OpenThemeData($hWnd, "DarkMode_Explorer::Button") Local $tPaint = DllStructCreate($tagPAINTSTRUCT) Local $hDC = _WinAPI_BeginPaint($hWnd, $tPaint) ; need to get PartID and StateID ; https://learn.microsoft.com/en-us/windows/win32/controls/parts-and-states ; GetThemeBackgroundContentRect ; _WinAPI_GetThemeBackgroundContentRect (not done yet) Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $BP_CHECKBOX, 0, Null, Null, $TS_TRUE) Local $tRectClient = _WinAPI_GetClientRect($hWnd) Local $sText = _WinAPI_GetWindowText($hWnd) Local $iState = _GUICtrlButton_GetState($hWnd) ;ConsoleWrite("checkbox state: " & $iState & @CRLF) ;ConsoleWrite("$BST_FOCUS: " & $BST_FOCUS & @CRLF) #cs If BitAND($iState, $BST_HOT) Then ConsoleWrite("BST_HOT" & @CRLF) If BitAND($iState, $BST_INDETERMINATE) Then ConsoleWrite("BST_INDETERMINATE" & @CRLF) If BitAND($iState, $BST_UNCHECKED) Then ConsoleWrite("BST_UNCHECKED" & @CRLF) If BitAND($iState, $BST_PUSHED) Then ConsoleWrite("BST_PUSHED" & @CRLF) $iStateID = $CBS_UNCHECKEDPRESSED EndIf If BitAND($iState, $BST_DONTCLICK) Then ConsoleWrite("BST_DONTCLICK" & @CRLF) #ce If Not _WinAPI_IsWindowEnabled($hWnd) Then $iStateID = $CBS_UNCHECKEDDISABLED ElseIf BitAND($iState, $BST_PUSHED) Then ConsoleWrite("BST_PUSHED" & @CRLF) $iStateID = $CBS_UNCHECKEDPRESSED ElseIf BitAND($iState, $BST_HOT) Then ConsoleWrite("BST_HOT" & @CRLF) $iStateID = $CBS_UNCHECKEDHOT Else ConsoleWrite("CBS_UNCHECKEDNORMAL" & @CRLF) $iStateID = $CBS_UNCHECKEDNORMAL EndIf If BitAND($iState, $BST_CHECKED) Then ConsoleWrite("BST_CHECKED" & @CRLF) $iStateID = $CBS_CHECKEDNORMAL ElseIf BitAND($iState, $BST_INDETERMINATE) Then ConsoleWrite("BST_INDETERMINATE" & @CRLF) $iStateID = $CBS_MIXEDNORMAL EndIf ; DrawThemeBackground Local $tRect = _WinAPI_CreateRectEx(0, 0, $tSIZE.X, $tSIZE.Y) _WinAPI_DrawThemeParentBackground($hWnd, $hDC, $tRectClient) _WinAPI_DrawThemeBackground($hTheme, $BP_CHECKBOX, $iStateID, $hDC, $tRect) ; Setup theme font ;Local $tLOGFONT = _WinAPI_GetThemeFont($hTheme, $BP_CHECKBOX, $CBS_CHECKEDNORMAL, $TMT_FONT) ;Local $hFont = _WinAPI_CreateFontIndirect($tLOGFONT) ;Local $hOldFont = _WinAPI_SelectObject($hDC, $hFont) Local $tDTTOPTS = DllStructCreate($tagDTTOPTS) DllStructSetData($tDTTOPTS, 'Size', DllStructGetSize($tDTTOPTS)) DllStructSetData($tDTTOPTS, 'Flags', BitOR($DTT_TEXTCOLOR, $DTT_COMPOSITED)) DllStructSetData($tDTTOPTS, 'clrText', 0xFFFFFF) ; Setup font Local $hFont = _SendMessage($hWnd, $WM_GETFONT, 0, 0) If Not $hFont Then $hFont = _WinAPI_GetStockObject($DEFAULT_GUI_FONT) Local $hOldFont = _WinAPI_SelectObject($hDC, $hFont) ;_WinAPI_SetBkMode($hDC, $TRANSPARENT) ;_WinAPI_SetTextColor($hDC, _WinAPI_SwitchColor(0xFFFFFF)) ;Local $tTextRect = DllStructCreate($tagRECT) _WinAPI_DrawThemeTextEx($hTheme, $BP_CHECKBOX, $CBS_CHECKEDNORMAL, $hDC, $sText, $tRectClient, BitOR($DT_CENTER, $DT_SINGLELINE, $DT_VCENTER), $tDTTOPTS) ;DllCall("user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sText, "int", -1, "struct*", $tTextRect, "uint", BitOR($DT_CENTER, $DT_VCENTER, $DT_SINGLELINE, $DT_NOPREFIX, $DT_NOCLIP)) ; cleanup _WinAPI_SelectObject($hDC, $hOldFont) _WinAPI_CloseThemeData($hTheme) _WinAPI_EndPaint($hWnd, $tPaint) Return 0 EndSwitch Return __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>_CheckboxProc Func __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) Return DllCall('comctl32.dll', 'lresult', 'DefSubclassProc', 'hwnd', $hWnd, 'uint', $iMsg, 'wparam', $wParam, _ 'lparam', $lParam)[0] EndFunc ;==>__WinAPI_DefSubclassProc argumentum 1
argumentum Posted May 28 Posted May 28 (edited) <Removed pics. Running out of space 🤷♂️ > Edited May 30 by argumentum WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
WildByDesign Posted May 28 Author Posted May 28 5 minutes ago, argumentum said: ..not the same PC but same OS version ( in the other am running AutoIt 3.3.16.1 ) Thanks for confirming. I appreciate it. So that is really good that it's working. Now I have to figure out the text rectangle / alignment math to ensure that everything is aligned better. That is not my best skill but I will figure it out. argumentum 1
WildByDesign Posted May 28 Author Posted May 28 54 minutes ago, argumentum said: ..not the same PC but same OS version ( in the other am running AutoIt 3.3.16.1 ) Can you please test the checkbox and text alignment with this one? It looks correct on mine with or without DPI. But every system is different, so I am crossing my fingers on this one. expandcollapse popup#include <GuiButton.au3> #include <APIThemeConstants.au3> #include <WinAPITheme.au3> #include <WinAPIGdi.au3> #include <APIGdiConstants.au3> #include <StructureConstants.au3> #include <WindowsNotifsConstants.au3> #include <WinAPISysInternals.au3> #include <WinAPIShellEx.au3> #include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> ; Initialize System DPI awareness DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2) Example() Func Example() ; Create a GUI with various controls. Local $hGUI = GUICreate("Example", 300, 200) GUISetBkColor("0x202020") ; Create a checkbox control. Local $idCheckbox = GUICtrlCreateCheckbox("Standard Checkbox", 69, 60, 185, 25) Local $idButton_Close = GUICtrlCreateButton("Close", 210, 170, 85, 25) Local $hCheckbox = GUICtrlGetHandle($idCheckbox) ; Register Subclassing / Window Procedure Local $pAddress = _WinAPI_GetWindowLong($hCheckbox, $GWL_WNDPROC) Local $hSubclass = DllCallbackRegister(_CheckboxProc, "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr") _WinAPI_SetWindowSubclass($hCheckbox, DllCallbackGetPtr($hSubclass), $idCheckbox, $pAddress) ; Display the GUI. GUISetState(@SW_SHOW, $hGUI) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idButton_Close ExitLoop Case $idCheckbox If _IsChecked($idCheckbox) Then ;MsgBox($MB_SYSTEMMODAL, "", "The checkbox is checked.", 0, $hGUI) ConsoleWrite("The checkbox is checked." & @CRLF) Else ;MsgBox($MB_SYSTEMMODAL, "", "The checkbox is not checked.", 0, $hGUI) ConsoleWrite("The checkbox is not checked." & @CRLF) EndIf EndSwitch WEnd ; Cleanup: Restore original Window Procedure _WinAPI_RemoveWindowSubclass($hCheckbox, DllCallbackGetPtr($hSubclass), $idCheckbox) DllCallbackFree($hSubclass) ; Delete the previous GUI and all controls. GUIDelete($hGUI) EndFunc ;==>Example Func _IsChecked($idControlID) Return BitAND(GUICtrlRead($idControlID), $GUI_CHECKED) = $GUI_CHECKED EndFunc ;==>_IsChecked Func _CheckboxProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) Local Static $bHover, $tPoint Switch $iMsg Case $WM_ERASEBKGND Return 1 ; Prevent background erasing to avoid flickering ;Case $WM_PRINTCLIENT Case $WM_PAINT Local $iStateID = 0 Local Const $BP_CHECKBOX = 3 Local Const $BST_HOT = 0x0200 ; checkbox StateID Local Const $CBS_UNCHECKEDNORMAL = 1 Local Const $CBS_UNCHECKEDHOT = 2 Local Const $CBS_UNCHECKEDPRESSED = 3 Local Const $CBS_UNCHECKEDDISABLED = 4 Local Const $CBS_CHECKEDNORMAL = 5 Local Const $CBS_CHECKEDHOT = 6 Local Const $CBS_CHECKEDPRESSED = 7 Local Const $CBS_CHECKEDDISABLED = 8 Local Const $CBS_MIXEDNORMAL = 9 Local Const $CBS_MIXEDHOT = 10 Local Const $CBS_MIXEDPRESSED = 11 Local Const $CBS_MIXEDDISABLED = 12 Local $hTheme = _WinAPI_OpenThemeData($hWnd, "DarkMode_Explorer::Button") Local $tPaint = DllStructCreate($tagPAINTSTRUCT) Local $hDC = _WinAPI_BeginPaint($hWnd, $tPaint) Local $tClient = _WinAPI_GetClientRect($hWnd) Local $iW = $tClient.Right Local $iH = $tClient.Bottom ; Initiate double buffering Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC) Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH) Local $hOldBmp = _WinAPI_SelectObject($hMemDC, $hBitmap) Local $iState = _GUICtrlButton_GetState($hWnd) ;ConsoleWrite("checkbox state: " & $iState & @CRLF) ;ConsoleWrite("$BST_FOCUS: " & $BST_FOCUS & @CRLF) #cs If BitAND($iState, $BST_HOT) Then ConsoleWrite("BST_HOT" & @CRLF) If BitAND($iState, $BST_INDETERMINATE) Then ConsoleWrite("BST_INDETERMINATE" & @CRLF) If BitAND($iState, $BST_UNCHECKED) Then ConsoleWrite("BST_UNCHECKED" & @CRLF) If BitAND($iState, $BST_PUSHED) Then ConsoleWrite("BST_PUSHED" & @CRLF) $iStateID = $CBS_UNCHECKEDPRESSED EndIf If BitAND($iState, $BST_DONTCLICK) Then ConsoleWrite("BST_DONTCLICK" & @CRLF) #ce If Not _WinAPI_IsWindowEnabled($hWnd) Then $iStateID = $CBS_UNCHECKEDDISABLED ElseIf BitAND($iState, $BST_PUSHED) Then ConsoleWrite("BST_PUSHED" & @CRLF) $iStateID = $CBS_UNCHECKEDPRESSED ElseIf BitAND($iState, $BST_HOT) Then ConsoleWrite("BST_HOT" & @CRLF) $iStateID = $CBS_UNCHECKEDHOT Else ConsoleWrite("CBS_UNCHECKEDNORMAL" & @CRLF) $iStateID = $CBS_UNCHECKEDNORMAL EndIf If BitAND($iState, $BST_CHECKED) Then ConsoleWrite("BST_CHECKED" & @CRLF) $iStateID = $CBS_CHECKEDNORMAL ElseIf BitAND($iState, $BST_INDETERMINATE) Then ConsoleWrite("BST_INDETERMINATE" & @CRLF) $iStateID = $CBS_MIXEDNORMAL EndIf ; GetThemeBackgroundContentRect Local $tTextRect = _WinAPI_GetThemeBackgroundContentRect($hTheme, $BP_CHECKBOX, $iStateID, $hMemDC, $tClient) Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $BP_CHECKBOX, 0, Null, Null, $TS_TRUE) ;Local $tRectClient = _WinAPI_GetClientRect($hWnd) Local $sText = _WinAPI_GetWindowText($hWnd) ; DrawThemeBackground Local $tRect = _WinAPI_CreateRectEx(0, 0, $tSIZE.X, $tSIZE.Y) _WinAPI_DrawThemeParentBackground($hWnd, $hMemDC, $tClient) _WinAPI_DrawThemeBackground($hTheme, $BP_CHECKBOX, $iStateID, $hMemDC, $tRect) ; Setup theme font ;Local $tLOGFONT = _WinAPI_GetThemeFont($hTheme, $BP_CHECKBOX, $CBS_CHECKEDNORMAL, $TMT_FONT) ;Local $hFont = _WinAPI_CreateFontIndirect($tLOGFONT) ;Local $hOldFont = _WinAPI_SelectObject($hDC, $hFont) Local $tDTTOPTS = DllStructCreate($tagDTTOPTS) DllStructSetData($tDTTOPTS, 'Size', DllStructGetSize($tDTTOPTS)) DllStructSetData($tDTTOPTS, 'Flags', BitOR($DTT_TEXTCOLOR, $DTT_COMPOSITED)) DllStructSetData($tDTTOPTS, 'clrText', 0xFFFFFF) ; 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($hDC, $TRANSPARENT) ;_WinAPI_SetTextColor($hDC, _WinAPI_SwitchColor(0xFFFFFF)) ;Local $tTextRect = DllStructCreate($tagRECT) $tTextRect.Left = $tTextRect.Left + $tSIZE.X + 3 ;$tTextRect.Top = $tTextRect.Top ;$tTextRect.Right = $tTextRect.Right ;$tTextRect.Bottom = $tTextRect.Bottom _WinAPI_DrawThemeTextEx($hTheme, $BP_CHECKBOX, $iStateID, $hMemDC, $sText, $tTextRect, $DT_SINGLELINE, $tDTTOPTS) ;DllCall("user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $sText, "int", -1, "struct*", $tTextRect, "uint", BitOR($DT_CENTER, $DT_VCENTER, $DT_SINGLELINE, $DT_NOPREFIX, $DT_NOCLIP)) _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hMemDC, 0, 0, $SRCCOPY) ; cleanup _WinAPI_SelectObject($hDC, $hOldFont) _WinAPI_CloseThemeData($hTheme) _WinAPI_SelectObject($hMemDC, $hOldBmp) _WinAPI_DeleteObject($hBitmap) _WinAPI_DeleteDC($hMemDC) _WinAPI_EndPaint($hWnd, $tPaint) Return 0 EndSwitch Return __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>_CheckboxProc Func __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) Return DllCall('comctl32.dll', 'lresult', 'DefSubclassProc', 'hwnd', $hWnd, 'uint', $iMsg, 'wparam', $wParam, _ 'lparam', $lParam)[0] EndFunc ;==>__WinAPI_DefSubclassProc argumentum 1
argumentum Posted May 28 Posted May 28 (edited) <Removed pics. Running out of space 🤷♂️ > Edited May 30 by argumentum WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
WildByDesign Posted May 28 Author Posted May 28 Since I move the text over based on the size of the checkbox, it looks like I also need to extend the text rect itself by that same amount since some is getting cut off. The good thing is I can extend this for dark mode radio buttons on 24H2 and earlier OS builds as well. argumentum 1
WildByDesign Posted May 29 Author Posted May 29 (edited) Here is some progress with subclassing for both checkbox and radio buttons. EDIT: I have WS_BORDER set on the checkbox control because I'm trying to get an idea on the sizing still. Lots of ConsoleWrite stuff going on. W.I.P. expandcollapse popup#include <ButtonConstants.au3> #include <WindowsStylesConstants.au3> #include <GuiButton.au3> #include <APIThemeConstants.au3> #include <WinAPITheme.au3> #include <WinAPIGdi.au3> #include <APIGdiConstants.au3> #include <StructureConstants.au3> #include <WindowsNotifsConstants.au3> #include <WinAPISysInternals.au3> #include <WinAPIShellEx.au3> #include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> ; Initialize System DPI awareness DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2) Global Const $BP_RADIOBUTTON = 2 Global Const $BP_CHECKBOX = 3 Example() Func Example() Local $sStyles ; Create a GUI with various controls. Local $hGUI = GUICreate("Example", 300, 200) GUISetBkColor("0x202020") ; Register Subclassing / Window Procedure Local $hSubclass = DllCallbackRegister(_CheckboxProc, "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr") ; Create a checkbox control. Local $idCheckbox = GUICtrlCreateCheckbox("Standard Checkbox", 40, 40, 185, 25, $WS_BORDER) Local $idRadio1 = GUICtrlCreateRadio("Radio 1", 40, 80, 120, 20) Local $idRadio2 = GUICtrlCreateRadio("Radio 2", 40, 120, 120, 20) Local $idButton_Close = GUICtrlCreateButton("Close", 210, 170, 85, 25) Local $hCheckbox = GUICtrlGetHandle($idCheckbox) $sStyles = "CHECKBOX" _WinAPI_SetWindowSubclass($hCheckbox, DllCallbackGetPtr($hSubclass), $idCheckbox, $BP_CHECKBOX) Local $hRadio1= GUICtrlGetHandle($idRadio1) $sStyles = "BS_AUTORADIOBUTTON" _WinAPI_SetWindowSubclass($hRadio1, DllCallbackGetPtr($hSubclass), $idRadio1, $BP_RADIOBUTTON) Local $hRadio2 = GUICtrlGetHandle($idRadio2) $sStyles = "BS_AUTORADIOBUTTON" _WinAPI_SetWindowSubclass($hRadio2, DllCallbackGetPtr($hSubclass), $idRadio2, $BP_RADIOBUTTON) ; Display the GUI. GUISetState(@SW_SHOW, $hGUI) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idButton_Close ExitLoop Case $idCheckbox If _IsChecked($idCheckbox) Then ;MsgBox($MB_SYSTEMMODAL, "", "The checkbox is checked.", 0, $hGUI) ConsoleWrite("The checkbox is checked." & @CRLF) Else ;MsgBox($MB_SYSTEMMODAL, "", "The checkbox is not checked.", 0, $hGUI) ConsoleWrite("The checkbox is not checked." & @CRLF) EndIf EndSwitch WEnd ; Cleanup: Restore original Window Procedure _WinAPI_RemoveWindowSubclass($hCheckbox, DllCallbackGetPtr($hSubclass), $idCheckbox) _WinAPI_RemoveWindowSubclass($hRadio1, DllCallbackGetPtr($hSubclass), $idRadio1) _WinAPI_RemoveWindowSubclass($hRadio2, DllCallbackGetPtr($hSubclass), $idRadio2) DllCallbackFree($hSubclass) ; Delete the previous GUI and all controls. GUIDelete($hGUI) EndFunc ;==>Example Func _IsChecked($idControlID) Return BitAND(GUICtrlRead($idControlID), $GUI_CHECKED) = $GUI_CHECKED EndFunc ;==>_IsChecked Func _CheckboxProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) Local Static $bHover, $tPoint Switch $iMsg Case $WM_ERASEBKGND Return 1 ; Prevent background erasing to avoid flickering ;Case $WM_PRINTCLIENT Case $WM_PAINT ConsoleWrite("pData: " & $pData & @CRLF) Local $iStateID = 0 Local $iPartID = $pData Local Const $BST_HOT = 0x0200 ; checkbox StateID Local Const $CBS_UNCHECKEDNORMAL = 1 Local Const $CBS_UNCHECKEDHOT = 2 Local Const $CBS_UNCHECKEDPRESSED = 3 Local Const $CBS_UNCHECKEDDISABLED = 4 Local Const $CBS_CHECKEDNORMAL = 5 Local Const $CBS_CHECKEDHOT = 6 Local Const $CBS_CHECKEDPRESSED = 7 Local Const $CBS_CHECKEDDISABLED = 8 Local Const $CBS_MIXEDNORMAL = 9 Local Const $CBS_MIXEDHOT = 10 Local Const $CBS_MIXEDPRESSED = 11 Local Const $CBS_MIXEDDISABLED = 12 ; radio StateID Local Const $RBS_UNCHECKEDNORMAL = 1 Local Const $RBS_UNCHECKEDHOT = 2 Local Const $RBS_UNCHECKEDPRESSED = 3 Local Const $RBS_UNCHECKEDDISABLED = 4 Local Const $RBS_CHECKEDNORMAL = 5 Local Const $RBS_CHECKEDHOT = 6 Local Const $RBS_CHECKEDPRESSED = 7 Local Const $RBS_CHECKEDDISABLED = 8 Local $hTheme = _WinAPI_OpenThemeData($hWnd, "DarkMode_Explorer::Button") Local $tPaint = DllStructCreate($tagPAINTSTRUCT) Local $hDC = _WinAPI_BeginPaint($hWnd, $tPaint) Local $tClient = _WinAPI_GetClientRect($hWnd) Local $iW = $tClient.Right Local $iH = $tClient.Bottom ; Initiate double buffering Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC) Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH) Local $hOldBmp = _WinAPI_SelectObject($hMemDC, $hBitmap) Local $iState = _GUICtrlButton_GetState($hWnd) ;ConsoleWrite("checkbox state: " & $iState & @CRLF) ;ConsoleWrite("$BST_FOCUS: " & $BST_FOCUS & @CRLF) #cs If BitAND($iState, $BST_HOT) Then ConsoleWrite("BST_HOT" & @CRLF) If BitAND($iState, $BST_INDETERMINATE) Then ConsoleWrite("BST_INDETERMINATE" & @CRLF) If BitAND($iState, $BST_UNCHECKED) Then ConsoleWrite("BST_UNCHECKED" & @CRLF) If BitAND($iState, $BST_PUSHED) Then ConsoleWrite("BST_PUSHED" & @CRLF) $iStateID = $CBS_UNCHECKEDPRESSED EndIf If BitAND($iState, $BST_DONTCLICK) Then ConsoleWrite("BST_DONTCLICK" & @CRLF) #ce If Not _WinAPI_IsWindowEnabled($hWnd) Then $iStateID = $CBS_UNCHECKEDDISABLED ElseIf BitAND($iState, $BST_PUSHED) Then ConsoleWrite("BST_PUSHED" & @CRLF) $iStateID = $CBS_UNCHECKEDPRESSED ElseIf BitAND($iState, $BST_HOT) Then ConsoleWrite("BST_HOT" & @CRLF) $iStateID = $CBS_UNCHECKEDHOT Else ConsoleWrite("CBS_UNCHECKEDNORMAL" & @CRLF) $iStateID = $CBS_UNCHECKEDNORMAL EndIf If BitAND($iState, $BST_CHECKED) Then ConsoleWrite("BST_CHECKED" & @CRLF) $iStateID = $CBS_CHECKEDNORMAL ElseIf BitAND($iState, $BST_INDETERMINATE) Then ConsoleWrite("BST_INDETERMINATE" & @CRLF) $iStateID = $CBS_MIXEDNORMAL EndIf ; GetThemeBackgroundContentRect Local $tTextRect = _WinAPI_GetThemeBackgroundContentRect($hTheme, $iPartID, $iStateID, $hMemDC, $tClient) Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $iPartID, 0, Null, Null, $TS_TRUE) ;Local $tRectClient = _WinAPI_GetClientRect($hWnd) Local $sText = _WinAPI_GetWindowText($hWnd) ; DrawThemeBackground Local $tRect = _WinAPI_CreateRectEx(0, 0, $tSIZE.X, $tSIZE.Y) _WinAPI_DrawThemeParentBackground($hWnd, $hMemDC, $tClient) _WinAPI_DrawThemeBackground($hTheme, $iPartID, $iStateID, $hMemDC, $tRect) ; Setup theme font ;Local $tLOGFONT = _WinAPI_GetThemeFont($hTheme, $BP_CHECKBOX, $CBS_CHECKEDNORMAL, $TMT_FONT) ;Local $hFont = _WinAPI_CreateFontIndirect($tLOGFONT) ;Local $hOldFont = _WinAPI_SelectObject($hDC, $hFont) Local $tDTTOPTS = DllStructCreate($tagDTTOPTS) DllStructSetData($tDTTOPTS, 'Size', DllStructGetSize($tDTTOPTS)) DllStructSetData($tDTTOPTS, 'Flags', BitOR($DTT_TEXTCOLOR, $DTT_COMPOSITED)) DllStructSetData($tDTTOPTS, 'clrText', 0xFFFFFF) ; 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, _WinAPI_SwitchColor(0xFFFFFF)) ;Local $tTextRect = DllStructCreate($tagRECT) $tTextRect.Left = $tTextRect.Left + $tSIZE.X + 3 ;$tTextRect.Top = $tTextRect.Top $tTextRect.Right = $tTextRect.Right + $tSIZE.X + 3 ;$tTextRect.Bottom = $tTextRect.Bottom ;_WinAPI_DrawThemeTextEx($hTheme, $BP_CHECKBOX, $iStateID, $hMemDC, $sText, $tTextRect, BitOR($DT_SINGLELINE, $DT_NOCLIP), $tDTTOPTS) DllCall("user32.dll", "int", "DrawTextW", "handle", $hMemDC, "wstr", $sText, "int", -1, "struct*", $tTextRect, "uint", BitOR($DT_SINGLELINE, $DT_NOCLIP)) _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hMemDC, 0, 0, $SRCCOPY) ; cleanup _WinAPI_SelectObject($hDC, $hOldFont) _WinAPI_CloseThemeData($hTheme) _WinAPI_SelectObject($hMemDC, $hOldBmp) _WinAPI_DeleteObject($hBitmap) _WinAPI_DeleteDC($hMemDC) _WinAPI_EndPaint($hWnd, $tPaint) Return 0 EndSwitch Return __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>_CheckboxProc Func __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) Return DllCall('comctl32.dll', 'lresult', 'DefSubclassProc', 'hwnd', $hWnd, 'uint', $iMsg, 'wparam', $wParam, _ 'lparam', $lParam)[0] EndFunc ;==>__WinAPI_DefSubclassProc Edited May 29 by WildByDesign
argumentum Posted May 29 Posted May 29 (edited) <Removed pics. Running out of space 🤷♂️ > Edited May 30 by argumentum WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
WildByDesign Posted May 29 Author Posted May 29 @argumentum Thanks, that visual feedback from other systems is very helpful. I still need to figure out how to resize it by the size of the checkbox/radio button. And I have to make sure I only do it once otherwise we'll have growing controls. 🙃 argumentum 1
WildByDesign Posted May 29 Author Posted May 29 Can anyone please test this latest script for alignment? expandcollapse popup#include <ButtonConstants.au3> #include <WindowsStylesConstants.au3> #include <GuiButton.au3> #include <APIThemeConstants.au3> #include <WinAPITheme.au3> #include <WinAPIGdi.au3> #include <APIGdiConstants.au3> #include <StructureConstants.au3> #include <WindowsNotifsConstants.au3> #include <WinAPISysInternals.au3> #include <WinAPIShellEx.au3> #include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> ; Initialize System DPI awareness DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2) Global Const $BP_RADIOBUTTON = 2 Global Const $BP_CHECKBOX = 3 Example() Func Example() ; Create a GUI with various controls. Local $hGUI = GUICreate("Example", 300, 200) GUISetBkColor("0x202020") ; Register Subclassing / Window Procedure Local $hSubclass = DllCallbackRegister(_CheckboxProc, "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr") ; Create a checkbox control. Local $idCheckbox = GUICtrlCreateCheckbox("Standard Checkbox", 40, 40) Local $hCheckbox = GUICtrlGetHandle(-1) Local $idRadio1 = GUICtrlCreateRadio("Radio 1", 40, 80) Local $hRadio1= GUICtrlGetHandle(-1) Local $idRadio2 = GUICtrlCreateRadio("Radio 2", 40, 120) Local $hRadio2 = GUICtrlGetHandle(-1) Local $idButton_Close = GUICtrlCreateButton("Close", 210, 160) _WinAPI_SetWindowTheme(GUICtrlGetHandle(-1), "DarkMode_Explorer") ; Get checkbox/radio button part size to increase width of controls plus padding Local $hTheme = _WinAPI_OpenThemeData($hGUI, "DarkMode_Explorer::Button") Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $BP_CHECKBOX, 0, Null, Null, $TS_TRUE) Local $iResize = $tSIZE.X + 3 ; Increase the width of controls based on part size plus padding Local $aPos = WinGetPos($hCheckbox) If Not @error Then _WinAPI_SetWindowPos($hCheckbox, 0, $aPos[0], $aPos[1], $aPos[2] + $iResize, $aPos[3], $SWP_NOMOVE) Local $aPos = WinGetPos($hRadio1) If Not @error Then _WinAPI_SetWindowPos($hRadio1, 0, $aPos[0], $aPos[1], $aPos[2] + $iResize, $aPos[3], $SWP_NOMOVE) Local $aPos = WinGetPos($hRadio2) If Not @error Then _WinAPI_SetWindowPos($hRadio2, 0, $aPos[0], $aPos[1], $aPos[2] + $iResize, $aPos[3], $SWP_NOMOVE) ; Subclass controls _WinAPI_SetWindowSubclass($hCheckbox, DllCallbackGetPtr($hSubclass), $idCheckbox, $BP_CHECKBOX) _WinAPI_SetWindowSubclass($hRadio1, DllCallbackGetPtr($hSubclass), $idRadio1, $BP_RADIOBUTTON) _WinAPI_SetWindowSubclass($hRadio2, DllCallbackGetPtr($hSubclass), $idRadio2, $BP_RADIOBUTTON) ; Display the GUI GUISetState(@SW_SHOW, $hGUI) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idButton_Close ExitLoop EndSwitch WEnd ; Cleanup: Restore original Window Procedure _WinAPI_RemoveWindowSubclass($hCheckbox, DllCallbackGetPtr($hSubclass), $idCheckbox) _WinAPI_RemoveWindowSubclass($hRadio1, DllCallbackGetPtr($hSubclass), $idRadio1) _WinAPI_RemoveWindowSubclass($hRadio2, DllCallbackGetPtr($hSubclass), $idRadio2) DllCallbackFree($hSubclass) ; Close theme data If $hTheme Then _WinAPI_CloseThemeData($hTheme) ; Delete the previous GUI and all controls. GUIDelete($hGUI) EndFunc ;==>Example Func _CheckboxProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) Local Static $bHover, $tPoint Switch $iMsg Case $WM_ERASEBKGND Return 1 ; Prevent background erasing to avoid flickering Case $WM_PAINT Local $iStateID = 0 Local $iPartID = $pData Local Const $BST_HOT = 0x0200 ; checkbox StateID Local Const $CBS_UNCHECKEDNORMAL = 1 Local Const $CBS_UNCHECKEDHOT = 2 Local Const $CBS_UNCHECKEDPRESSED = 3 Local Const $CBS_UNCHECKEDDISABLED = 4 Local Const $CBS_CHECKEDNORMAL = 5 Local Const $CBS_CHECKEDHOT = 6 Local Const $CBS_CHECKEDPRESSED = 7 Local Const $CBS_CHECKEDDISABLED = 8 Local Const $CBS_MIXEDNORMAL = 9 Local Const $CBS_MIXEDHOT = 10 Local Const $CBS_MIXEDPRESSED = 11 Local Const $CBS_MIXEDDISABLED = 12 ; radio StateID Local Const $RBS_UNCHECKEDNORMAL = 1 Local Const $RBS_UNCHECKEDHOT = 2 Local Const $RBS_UNCHECKEDPRESSED = 3 Local Const $RBS_UNCHECKEDDISABLED = 4 Local Const $RBS_CHECKEDNORMAL = 5 Local Const $RBS_CHECKEDHOT = 6 Local Const $RBS_CHECKEDPRESSED = 7 Local Const $RBS_CHECKEDDISABLED = 8 Local $hTheme = _WinAPI_OpenThemeData($hWnd, "DarkMode_Explorer::Button") Local $tPaint = DllStructCreate($tagPAINTSTRUCT) Local $hDC = _WinAPI_BeginPaint($hWnd, $tPaint) Local $tClient = _WinAPI_GetClientRect($hWnd) Local $iW = $tClient.Right Local $iH = $tClient.Bottom ; Initiate double buffering Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC) Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH) Local $hOldBmp = _WinAPI_SelectObject($hMemDC, $hBitmap) Local $iState = _GUICtrlButton_GetState($hWnd) Switch $iPartID Case $BP_CHECKBOX If Not _WinAPI_IsWindowEnabled($hWnd) Then $iStateID = $CBS_UNCHECKEDDISABLED ElseIf BitAND($iState, $BST_PUSHED) Then $iStateID = $CBS_UNCHECKEDPRESSED ElseIf BitAND($iState, $BST_HOT) Then $iStateID = $CBS_UNCHECKEDHOT Else $iStateID = $CBS_UNCHECKEDNORMAL EndIf If BitAND($iState, $BST_CHECKED) Then $iStateID = $CBS_CHECKEDNORMAL ElseIf BitAND($iState, $BST_INDETERMINATE) Then $iStateID = $CBS_MIXEDNORMAL EndIf Case $BP_RADIOBUTTON If Not _WinAPI_IsWindowEnabled($hWnd) Then $iStateID = $RBS_UNCHECKEDDISABLED ElseIf BitAND($iState, $BST_PUSHED) Then $iStateID = $RBS_UNCHECKEDPRESSED ElseIf BitAND($iState, $BST_HOT) Then $iStateID = $RBS_UNCHECKEDHOT Else $iStateID = $RBS_UNCHECKEDNORMAL EndIf If BitAND($iState, $BST_CHECKED) Then $iStateID = $RBS_CHECKEDNORMAL EndIf EndSwitch ; GetThemeBackgroundContentRect Local $tTextRect = _WinAPI_GetThemeBackgroundContentRect($hTheme, $iPartID, $iStateID, $hMemDC, $tClient) Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $iPartID, 0, Null, Null, $TS_TRUE) Local $sText = _WinAPI_GetWindowText($hWnd) ; DrawThemeBackground Local $tRect = _WinAPI_CreateRectEx(0, 0, $tSIZE.X, $tSIZE.Y) _WinAPI_DrawThemeParentBackground($hWnd, $hMemDC, $tClient) _WinAPI_DrawThemeBackground($hTheme, $iPartID, $iStateID, $hMemDC, $tRect) ; Setup theme font ;Local $tLOGFONT = _WinAPI_GetThemeFont($hTheme, $BP_CHECKBOX, $CBS_CHECKEDNORMAL, $TMT_FONT) ;Local $hFont = _WinAPI_CreateFontIndirect($tLOGFONT) ;Local $hOldFont = _WinAPI_SelectObject($hDC, $hFont) Local $tDTTOPTS = DllStructCreate($tagDTTOPTS) DllStructSetData($tDTTOPTS, 'Size', DllStructGetSize($tDTTOPTS)) DllStructSetData($tDTTOPTS, 'Flags', BitOR($DTT_TEXTCOLOR, $DTT_COMPOSITED)) DllStructSetData($tDTTOPTS, 'clrText', 0xFFFFFF) ; 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, _WinAPI_SwitchColor(0xFFFFFF)) ;Local $tTextRect = DllStructCreate($tagRECT) $tTextRect.Left = $tTextRect.Left + $tSIZE.X + 3 ;$tTextRect.Top = $tTextRect.Top $tTextRect.Right = $tTextRect.Right + $tSIZE.X + 3 ;$tTextRect.Bottom = $tTextRect.Bottom ;_WinAPI_DrawThemeTextEx($hTheme, $BP_CHECKBOX, $iStateID, $hMemDC, $sText, $tTextRect, BitOR($DT_SINGLELINE, $DT_NOCLIP), $tDTTOPTS) DllCall("user32.dll", "int", "DrawTextW", "handle", $hMemDC, "wstr", $sText, "int", -1, "struct*", $tTextRect, "uint", BitOR($DT_SINGLELINE, $DT_NOCLIP)) _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hMemDC, 0, 0, $SRCCOPY) ; cleanup _WinAPI_SelectObject($hDC, $hOldFont) _WinAPI_CloseThemeData($hTheme) _WinAPI_SelectObject($hMemDC, $hOldBmp) _WinAPI_DeleteObject($hBitmap) _WinAPI_DeleteDC($hMemDC) _WinAPI_EndPaint($hWnd, $tPaint) Return 0 EndSwitch Return __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>_CheckboxProc Func __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) Return DllCall('comctl32.dll', 'lresult', 'DefSubclassProc', 'hwnd', $hWnd, 'uint', $iMsg, 'wparam', $wParam, _ 'lparam', $lParam)[0] EndFunc ;==>__WinAPI_DefSubclassProc
argumentum Posted May 30 Posted May 30 WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
WildByDesign Posted May 30 Author Posted May 30 I did some math to make sure that the checkbox/radio button is vertically aligned within the control rectangle and same for the DrawThemeTextEx. I added WS_BORDER for all 3 controls just to get an idea on how well the alignment is working just for testing purposes. I increased the height of some of the controls just for testing purposes. I think I'm getting closer to this being usable in GUIDarkTheme UDF for Windows 10 to Windows 11 24H2 users. 25H2+ wont need the subclass, so I would only enable it on the affected systems in the UDF. But for testing purposes, we can still test it on 25H2. @argumentum Can you please test this? Also, you could even add in GUISetFont(10) or GUISetFont(12) before the controls are created to see how different font sizes behave. So far so good on my end. expandcollapse popup#include <ButtonConstants.au3> #include <WindowsStylesConstants.au3> #include <GuiButton.au3> #include <APIThemeConstants.au3> #include <WinAPITheme.au3> #include <WinAPIGdi.au3> #include <APIGdiConstants.au3> #include <StructureConstants.au3> #include <WindowsNotifsConstants.au3> #include <WinAPISysInternals.au3> #include <WinAPIShellEx.au3> #include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> ; Initialize System DPI awareness DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2) Global Const $BP_RADIOBUTTON = 2 Global Const $BP_CHECKBOX = 3 Example() Func Example() ; Create a GUI with various controls. Local $hGUI = GUICreate("Example", 300, 200) GUISetBkColor("0x202020") ; Register Subclassing / Window Procedure Local $hSubclass = DllCallbackRegister(_CheckboxProc, "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr") ; Create a checkbox control. Local $idCheckbox = GUICtrlCreateCheckbox("Standard Checkbox", 40, 20, -1, 50, $WS_BORDER) Local $hCheckbox = GUICtrlGetHandle(-1) Local $idRadio1 = GUICtrlCreateRadio("Radio 1", 40, 80, -1, -1, $WS_BORDER) Local $hRadio1= GUICtrlGetHandle(-1) Local $idRadio2 = GUICtrlCreateRadio("Radio 2", 40, 120, -1, 60, $WS_BORDER) Local $hRadio2 = GUICtrlGetHandle(-1) Local $idButton_Close = GUICtrlCreateButton("Close", 210, 160) _WinAPI_SetWindowTheme(GUICtrlGetHandle(-1), "DarkMode_Explorer") ; Get checkbox/radio button part size to increase width of controls plus padding Local $hTheme = _WinAPI_OpenThemeData($hGUI, "DarkMode_Explorer::Button") Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $BP_CHECKBOX, 0, Null, Null, $TS_TRUE) Local $iResize = $tSIZE.X + 3 ; Increase the width of controls based on part size plus padding Local $aPos = WinGetPos($hCheckbox) If Not @error Then _WinAPI_SetWindowPos($hCheckbox, 0, $aPos[0], $aPos[1], $aPos[2] + $iResize, $aPos[3], $SWP_NOMOVE) Local $aPos = WinGetPos($hRadio1) If Not @error Then _WinAPI_SetWindowPos($hRadio1, 0, $aPos[0], $aPos[1], $aPos[2] + $iResize, $aPos[3], $SWP_NOMOVE) Local $aPos = WinGetPos($hRadio2) If Not @error Then _WinAPI_SetWindowPos($hRadio2, 0, $aPos[0], $aPos[1], $aPos[2] + $iResize, $aPos[3], $SWP_NOMOVE) ; Subclass controls _WinAPI_SetWindowSubclass($hCheckbox, DllCallbackGetPtr($hSubclass), $idCheckbox, $BP_CHECKBOX) _WinAPI_SetWindowSubclass($hRadio1, DllCallbackGetPtr($hSubclass), $idRadio1, $BP_RADIOBUTTON) _WinAPI_SetWindowSubclass($hRadio2, DllCallbackGetPtr($hSubclass), $idRadio2, $BP_RADIOBUTTON) ; Display the GUI GUISetState(@SW_SHOW, $hGUI) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idButton_Close ExitLoop EndSwitch WEnd ; Cleanup: Restore original Window Procedure _WinAPI_RemoveWindowSubclass($hCheckbox, DllCallbackGetPtr($hSubclass), $idCheckbox) _WinAPI_RemoveWindowSubclass($hRadio1, DllCallbackGetPtr($hSubclass), $idRadio1) _WinAPI_RemoveWindowSubclass($hRadio2, DllCallbackGetPtr($hSubclass), $idRadio2) DllCallbackFree($hSubclass) ; Close theme data If $hTheme Then _WinAPI_CloseThemeData($hTheme) ; Delete the previous GUI and all controls. GUIDelete($hGUI) EndFunc ;==>Example Func _CheckboxProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) Local Static $bHover, $tPoint Switch $iMsg Case $WM_ERASEBKGND Return 1 ; Prevent background erasing to avoid flickering Case $WM_PAINT Local $hTheme = _WinAPI_OpenThemeData($hWnd, "DarkMode_Explorer::Button") Local $iStateID = 0 Local $iPartID = $pData Local Const $BST_HOT = 0x0200 ; checkbox StateID Local Const $CBS_UNCHECKEDNORMAL = 1 Local Const $CBS_UNCHECKEDHOT = 2 Local Const $CBS_UNCHECKEDPRESSED = 3 Local Const $CBS_UNCHECKEDDISABLED = 4 Local Const $CBS_CHECKEDNORMAL = 5 Local Const $CBS_CHECKEDHOT = 6 Local Const $CBS_CHECKEDPRESSED = 7 Local Const $CBS_CHECKEDDISABLED = 8 Local Const $CBS_MIXEDNORMAL = 9 Local Const $CBS_MIXEDHOT = 10 Local Const $CBS_MIXEDPRESSED = 11 Local Const $CBS_MIXEDDISABLED = 12 ; radio StateID Local Const $RBS_UNCHECKEDNORMAL = 1 Local Const $RBS_UNCHECKEDHOT = 2 Local Const $RBS_UNCHECKEDPRESSED = 3 Local Const $RBS_UNCHECKEDDISABLED = 4 Local Const $RBS_CHECKEDNORMAL = 5 Local Const $RBS_CHECKEDHOT = 6 Local Const $RBS_CHECKEDPRESSED = 7 Local Const $RBS_CHECKEDDISABLED = 8 Local $tPaint = DllStructCreate($tagPAINTSTRUCT) Local $hDC = _WinAPI_BeginPaint($hWnd, $tPaint) Local $tClient = _WinAPI_GetClientRect($hWnd) Local $iW = $tClient.Right Local $iH = $tClient.Bottom ; Initiate double buffering Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC) Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH) Local $hOldBmp = _WinAPI_SelectObject($hMemDC, $hBitmap) Local $iState = _GUICtrlButton_GetState($hWnd) Switch $iPartID Case $BP_CHECKBOX If Not _WinAPI_IsWindowEnabled($hWnd) Then $iStateID = $CBS_UNCHECKEDDISABLED ElseIf BitAND($iState, $BST_PUSHED) Then $iStateID = $CBS_UNCHECKEDPRESSED ElseIf BitAND($iState, $BST_HOT) Then $iStateID = $CBS_UNCHECKEDHOT Else $iStateID = $CBS_UNCHECKEDNORMAL EndIf If BitAND($iState, $BST_CHECKED) Then $iStateID = $CBS_CHECKEDNORMAL ElseIf BitAND($iState, $BST_INDETERMINATE) Then $iStateID = $CBS_MIXEDNORMAL EndIf Case $BP_RADIOBUTTON If Not _WinAPI_IsWindowEnabled($hWnd) Then $iStateID = $RBS_UNCHECKEDDISABLED ElseIf BitAND($iState, $BST_PUSHED) Then $iStateID = $RBS_UNCHECKEDPRESSED ElseIf BitAND($iState, $BST_HOT) Then $iStateID = $RBS_UNCHECKEDHOT Else $iStateID = $RBS_UNCHECKEDNORMAL EndIf If BitAND($iState, $BST_CHECKED) Then $iStateID = $RBS_CHECKEDNORMAL EndIf EndSwitch ; GetThemeBackgroundContentRect Local $tTextRect = _WinAPI_GetThemeBackgroundContentRect($hTheme, $iPartID, $iStateID, $hMemDC, $tClient) Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $iPartID, 0, Null, Null, $TS_TRUE) Local $sText = _WinAPI_GetWindowText($hWnd) ;DrawThemeParentBackground _WinAPI_DrawThemeParentBackground($hWnd, $hMemDC, $tClient) ; DrawThemeBackground Local $iWidth = $tSIZE.X Local $iHeight = $tSIZE.Y Local $iClientHeight = $tClient.Bottom - $tClient.Top Local $iHeightPad = ($iClientHeight - $iHeight) Local $tRect = _WinAPI_CreateRectEx(0, 0, $iWidth, $iHeight + $iHeightPad) _WinAPI_DrawThemeBackground($hTheme, $iPartID, $iStateID, $hMemDC, $tRect) ; Setup theme font ;Local $tLOGFONT = _WinAPI_GetThemeFont($hTheme, $BP_CHECKBOX, $CBS_CHECKEDNORMAL, $TMT_FONT) ;Local $hFont = _WinAPI_CreateFontIndirect($tLOGFONT) ;Local $hOldFont = _WinAPI_SelectObject($hDC, $hFont) Local $tDTTOPTS = DllStructCreate($tagDTTOPTS) DllStructSetData($tDTTOPTS, 'Size', DllStructGetSize($tDTTOPTS)) DllStructSetData($tDTTOPTS, 'Flags', BitOR($DTT_TEXTCOLOR, $DTT_COMPOSITED)) DllStructSetData($tDTTOPTS, 'clrText', 0xFFFFFF) ; 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, _WinAPI_SwitchColor(0xFFFFFF)) $tTextRect.Left = $tTextRect.Left + $tSIZE.X + 3 $tTextRect.Right = $tTextRect.Right + $tSIZE.X + 3 _WinAPI_DrawThemeTextEx($hTheme, $BP_CHECKBOX, $iStateID, $hMemDC, $sText, $tTextRect, BitOR($DT_SINGLELINE, $DT_NOCLIP, $DT_VCENTER), $tDTTOPTS) _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hMemDC, 0, 0, $SRCCOPY) ; cleanup _WinAPI_CloseThemeData($hTheme) _WinAPI_SelectObject($hDC, $hOldFont) _WinAPI_SelectObject($hMemDC, $hOldBmp) _WinAPI_DeleteObject($hBitmap) _WinAPI_DeleteDC($hMemDC) _WinAPI_EndPaint($hWnd, $tPaint) Return 0 EndSwitch Return __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>_CheckboxProc Func __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) Return DllCall('comctl32.dll', 'lresult', 'DefSubclassProc', 'hwnd', $hWnd, 'uint', $iMsg, 'wparam', $wParam, _ 'lparam', $lParam)[0] EndFunc ;==>__WinAPI_DefSubclassProc
Solution WildByDesign Posted Saturday at 02:20 PM Author Solution Posted Saturday at 02:20 PM Latest version of the script adds support for parsing the styles to determine DrawThemeTextEx flags (DT_*) needed to handle checkbox/radio button styles such as BS_RIGHT, BS_CENTER and more. I need to do more work on those styles though. But it's a step in the right direction. I've cleaned up the script quite a bit as well. expandcollapse popup#include <ButtonConstants.au3> #include <WindowsStylesConstants.au3> #include <GuiButton.au3> #include <APIThemeConstants.au3> #include <WinAPITheme.au3> #include <WinAPIGdi.au3> #include <APIGdiConstants.au3> #include <StructureConstants.au3> #include <WindowsNotifsConstants.au3> #include <WinAPISysInternals.au3> #include <WinAPIShellEx.au3> #include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> ; Initialize System DPI awareness DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2) Global Const $BP_RADIOBUTTON = 2 Global Const $BP_CHECKBOX = 3 Example() Func Example() ; Create a GUI with various controls. Local $hGUI = GUICreate("Example", 300, 200) GUISetBkColor("0x202020") ; Register Subclassing / Window Procedure Local $hSubclass = DllCallbackRegister(_ButtonProc, "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr") ; Create a checkbox control. Local $idCheckbox = GUICtrlCreateCheckbox("Standard Checkbox", 40, 40) Local $hCheckbox = GUICtrlGetHandle(-1) Local $idRadio1 = GUICtrlCreateRadio("Radio 1", 40, 80) Local $hRadio1= GUICtrlGetHandle(-1) Local $idRadio2 = GUICtrlCreateRadio("Radio 2", 40, 110) Local $hRadio2 = GUICtrlGetHandle(-1) Local $idButton_Close = GUICtrlCreateButton("Close", 210, 160) _WinAPI_SetWindowTheme(GUICtrlGetHandle(-1), "DarkMode_Explorer") ; Get checkbox/radio button part size to increase width of controls plus padding Local $hTheme = _WinAPI_OpenThemeData($hGUI, "DarkMode_Explorer::Button") Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $BP_CHECKBOX, 0, Null, Null, $TS_TRUE) Local $iResize = $tSIZE.X + 3 _WinAPI_CloseThemeData($hTheme) ; Increase the width of controls based on part size plus padding Local $aPos = WinGetPos($hCheckbox) If Not @error Then _WinAPI_SetWindowPos($hCheckbox, 0, $aPos[0], $aPos[1], $aPos[2] + $iResize, $aPos[3], $SWP_NOMOVE) Local $aPos = WinGetPos($hRadio1) If Not @error Then _WinAPI_SetWindowPos($hRadio1, 0, $aPos[0], $aPos[1], $aPos[2] + $iResize, $aPos[3], $SWP_NOMOVE) Local $aPos = WinGetPos($hRadio2) If Not @error Then _WinAPI_SetWindowPos($hRadio2, 0, $aPos[0], $aPos[1], $aPos[2] + $iResize, $aPos[3], $SWP_NOMOVE) ; Subclass controls Local $sStyles = "BS_AUTOCHECKBOX, WS_CHILD, WS_TABSTOP" Local $tStruct1 = DllStructCreate("struct;int;wchar[256];endstruct") DllStructSetData($tStruct1, 1, $BP_CHECKBOX) DllStructSetData($tStruct1, 2, $sStyles) _WinAPI_SetWindowSubclass($hCheckbox, DllCallbackGetPtr($hSubclass), $idCheckbox, DllStructGetPtr($tStruct1)) Local $sStyles = "BS_AUTORADIOBUTTON, WS_CHILD, WS_VISIBLE, WS_TABSTOP" Local $tStruct2 = DllStructCreate("struct;int;wchar[256];endstruct") DllStructSetData($tStruct2, 1, $BP_RADIOBUTTON) DllStructSetData($tStruct2, 2, $sStyles) _WinAPI_SetWindowSubclass($hRadio1, DllCallbackGetPtr($hSubclass), $idRadio1, DllStructGetPtr($tStruct2)) Local $sStyles = "BS_AUTORADIOBUTTON, WS_CHILD, WS_VISIBLE, WS_TABSTOP" Local $tStruct3 = DllStructCreate("struct;int;wchar[256];endstruct") DllStructSetData($tStruct3, 1, $BP_RADIOBUTTON) DllStructSetData($tStruct3, 2, $sStyles) _WinAPI_SetWindowSubclass($hRadio2, DllCallbackGetPtr($hSubclass), $idRadio2, DllStructGetPtr($tStruct3)) ; Display the GUI GUISetState(@SW_SHOW, $hGUI) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idButton_Close ExitLoop EndSwitch WEnd ; Cleanup: Restore original Window Procedure _WinAPI_RemoveWindowSubclass($hCheckbox, DllCallbackGetPtr($hSubclass), $idCheckbox) _WinAPI_RemoveWindowSubclass($hRadio1, DllCallbackGetPtr($hSubclass), $idRadio1) _WinAPI_RemoveWindowSubclass($hRadio2, DllCallbackGetPtr($hSubclass), $idRadio2) DllCallbackFree($hSubclass) ; Delete the previous GUI and all controls. GUIDelete($hGUI) EndFunc ;==>Example Func _ButtonProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData) Local Static $bHover, $tPoint Switch $iMsg Case $WM_ERASEBKGND Return 1 ; Prevent background erasing to avoid flickering Case $WM_PAINT Local $tStruct = DllStructCreate("struct;int;wchar[256];endstruct", $pData) Local $iPartID = DllStructGetData($tStruct, 1) Local $sStyles = DllStructGetData($tStruct, 2) Local $hTheme = _WinAPI_OpenThemeData($hWnd, "DarkMode_Explorer::Button") Local $iStateID = 0 Local Const $BST_HOT = 0x0200 ; checkbox StateID Local Const $CBS_UNCHECKEDNORMAL = 1 Local Const $CBS_UNCHECKEDHOT = 2 Local Const $CBS_UNCHECKEDPRESSED = 3 Local Const $CBS_UNCHECKEDDISABLED = 4 Local Const $CBS_CHECKEDNORMAL = 5 Local Const $CBS_CHECKEDHOT = 6 Local Const $CBS_CHECKEDPRESSED = 7 Local Const $CBS_CHECKEDDISABLED = 8 Local Const $CBS_MIXEDNORMAL = 9 Local Const $CBS_MIXEDHOT = 10 Local Const $CBS_MIXEDPRESSED = 11 Local Const $CBS_MIXEDDISABLED = 12 ; radio StateID Local Const $RBS_UNCHECKEDNORMAL = 1 Local Const $RBS_UNCHECKEDHOT = 2 Local Const $RBS_UNCHECKEDPRESSED = 3 Local Const $RBS_UNCHECKEDDISABLED = 4 Local Const $RBS_CHECKEDNORMAL = 5 Local Const $RBS_CHECKEDHOT = 6 Local Const $RBS_CHECKEDPRESSED = 7 Local Const $RBS_CHECKEDDISABLED = 8 Local $tPaint = DllStructCreate($tagPAINTSTRUCT) Local $hDC = _WinAPI_BeginPaint($hWnd, $tPaint) Local $tClient = _WinAPI_GetClientRect($hWnd) Local $iW = $tClient.Right Local $iH = $tClient.Bottom ; Initiate double buffering Local $hMemDC = _WinAPI_CreateCompatibleDC($hDC) Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH) Local $hOldBmp = _WinAPI_SelectObject($hMemDC, $hBitmap) Local $iState = _GUICtrlButton_GetState($hWnd) ; Determine StateID from current state Switch $iPartID Case $BP_CHECKBOX If Not _WinAPI_IsWindowEnabled($hWnd) Then $iStateID = $CBS_UNCHECKEDDISABLED ElseIf BitAND($iState, $BST_PUSHED) Then $iStateID = $CBS_UNCHECKEDPRESSED ElseIf BitAND($iState, $BST_HOT) Then $iStateID = $CBS_UNCHECKEDHOT Else $iStateID = $CBS_UNCHECKEDNORMAL EndIf If BitAND($iState, $BST_CHECKED) Then $iStateID = $CBS_CHECKEDNORMAL ElseIf BitAND($iState, $BST_INDETERMINATE) Then $iStateID = $CBS_MIXEDNORMAL EndIf Case $BP_RADIOBUTTON If Not _WinAPI_IsWindowEnabled($hWnd) Then $iStateID = $RBS_UNCHECKEDDISABLED ElseIf BitAND($iState, $BST_PUSHED) Then $iStateID = $RBS_UNCHECKEDPRESSED ElseIf BitAND($iState, $BST_HOT) Then $iStateID = $RBS_UNCHECKEDHOT Else $iStateID = $RBS_UNCHECKEDNORMAL EndIf If BitAND($iState, $BST_CHECKED) Then $iStateID = $RBS_CHECKEDNORMAL EndIf EndSwitch ; Determine DrawText $DT_* flags based on detected styles Local $iTextFlags Select Case StringInStr($sStyles, "BS_RIGHT") <> 0 $iTextFlags = BitOR($DT_SINGLELINE, $DT_NOCLIP, $DT_VCENTER, $DT_RIGHT) Case StringInStr($sStyles, "BS_CENTER") <> 0 $iTextFlags = BitOR($DT_SINGLELINE, $DT_NOCLIP, $DT_VCENTER, $DT_CENTER) Case Else $iTextFlags = BitOR($DT_SINGLELINE, $DT_NOCLIP, $DT_VCENTER, $DT_LEFT) EndSelect ; GetThemeBackgroundContentRect Local $tTextRect = _WinAPI_GetThemeBackgroundContentRect($hTheme, $iPartID, $iStateID, $hMemDC, $tClient) Local $tSIZE = _WinAPI_GetThemePartSize($hTheme, $iPartID, 0, Null, Null, $TS_TRUE) ; Get text from control Local $sText = _WinAPI_GetWindowText($hWnd) ; DrawThemeParentBackground _WinAPI_DrawThemeParentBackground($hWnd, $hMemDC, $tClient) ; DrawThemeBackground Local $iWidth = $tSIZE.X Local $iHeight = $tSIZE.Y Local $iClientHeight = $tClient.Bottom - $tClient.Top Local $iHeightPad = ($iClientHeight - $iHeight) Local $tRect = _WinAPI_CreateRectEx(0, 0, $iWidth, $iHeight + $iHeightPad) _WinAPI_DrawThemeBackground($hTheme, $iPartID, $iStateID, $hMemDC, $tRect) ; Set flags for DTTOPTS structure Local $tDTTOPTS = DllStructCreate($tagDTTOPTS) DllStructSetData($tDTTOPTS, 'Size', DllStructGetSize($tDTTOPTS)) DllStructSetData($tDTTOPTS, 'Flags', $DTT_TEXTCOLOR) DllStructSetData($tDTTOPTS, 'clrText', 0xFFFFFF) ; 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) $tTextRect.Left = $tTextRect.Left + $tSIZE.X + 3 $tTextRect.Right = $tTextRect.Right + $tSIZE.X + 3 _WinAPI_DrawThemeTextEx($hTheme, $BP_CHECKBOX, $iStateID, $hMemDC, $sText, $tTextRect, $iTextFlags, $tDTTOPTS) _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hMemDC, 0, 0, $SRCCOPY) ; Cleanup _WinAPI_CloseThemeData($hTheme) _WinAPI_SelectObject($hDC, $hOldFont) _WinAPI_SelectObject($hMemDC, $hOldBmp) _WinAPI_DeleteObject($hBitmap) _WinAPI_DeleteDC($hMemDC) _WinAPI_EndPaint($hWnd, $tPaint) Return 0 EndSwitch Return __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>_ButtonProc Func __WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) Return DllCall('comctl32.dll', 'lresult', 'DefSubclassProc', 'hwnd', $hWnd, 'uint', $iMsg, 'wparam', $wParam, _ 'lparam', $lParam)[0] EndFunc ;==>__WinAPI_DefSubclassProc
argumentum Posted Saturday at 03:38 PM Posted Saturday at 03:38 PM WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
WildByDesign Posted Saturday at 03:39 PM Author Posted Saturday at 03:39 PM Looks like we are ready now! 🤩 argumentum 1
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now