WildByDesign Posted 3 hours ago Posted 3 hours ago (edited) I wasn't able to find a ChooseColor hook example in the forum, so I went ahead and made one. It's dark mode, but realistically you could color it however you want. I do need some help, however. Please. While everything seems to work quite well, color returns and so on, I need some help to ensure that I have done things properly. So here is a working example of a custom hook for the ChooseColor dialog box (in dark mode). If anyone is able to help improve it, please feel free. It is for the community, as always. And if the community wants to help improve upon it, I am always open to that. expandcollapse popup#include <GUIConstantsEx.au3> #include <APIGdiConstants.au3> #include <SendMessage.au3> #include <WinAPISysWin.au3> #include <WinAPITheme.au3> #include <WindowsStylesConstants.au3> #include <WinAPIGdiInternals.au3> #include <WinAPIGdiDC.au3> #include <AutoItConstants.au3> #include <WindowsNotifsConstants.au3> #include <WinAPIGdi.au3> #include <Misc.au3> ; Initialize System DPI awareness DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2) Global Const $CC_ENABLEHOOK = 0x00000010 Global Const $COLOROKSTRING = "commdlg_ColorOK" Global $g_hColorProc = 0 _WinAPI_RegisterWindowMessage($COLOROKSTRING) ConsoleWrite(_ChooseColorHooked(2, 0x0080C0, 2) & @CRLF) Func _ChooseColorHooked($vReturnType = 0, $iColorRef = 0, $iRefType = 0, $hWndOwnder = 0) Local $tagCustcolors = "dword[16]" Local $tChoose = DllStructCreate($tagCHOOSECOLOR) Local Static $tCc = DllStructCreate($tagCustcolors) ; keep the colors Local $iReturnType, $vReturn If $vReturnType = -9 Or $vReturnType = -10 Then ; get $tagCustcolors as array Local $a_tCc = __ChooseColor_StructToArray($tCc) $a_tCc[0] = -1 If $vReturnType = -10 Then $tCc = DllStructCreate($tagCustcolors) Return $a_tCc ElseIf $vReturnType > 9 Then ; re-init./clear $tCc, and continue on a clean slate, just "10 + ReturnType" $tCc = DllStructCreate($tagCustcolors) ; ( maybe unnecessary but the user may want to ) $iReturnType = $vReturnType - 10 ElseIf IsArray($vReturnType) Then ; user declared Custcolors array If UBound($vReturnType, $UBOUND_ROWS) = 17 And UBound($vReturnType, $UBOUND_DIMENSIONS) = 1 Then For $n = 1 To 16 DllStructSetData($tCc, 1, $vReturnType[$n], $n) Next If $vReturnType[0] = -9 Then ; ..consistent with "-9 = return $tagCustcolors as array" $vReturnType[0] = 0 ; set back to default "ReturnType" Return $vReturnType EndIf If $vReturnType[0] > 9 Then $vReturnType[0] -= 10 ; just in case the user mistakenly think it needs to $iReturnType = $vReturnType[0] Else ; unexpected array format Return SetError(-5, 0, -1) EndIf Else $iReturnType = $vReturnType EndIf If $iReturnType < 0 Or $iReturnType > 2 Then ; unexpected ReturnType If IsArray($vReturnType) Then $vReturnType[0] = -1 Return SetError(-4, 0, $vReturnType) EndIf Return SetError(-4, 0, -1) EndIf If $iRefType = 1 Then ; BGR hex color to colorref $iColorRef = Int($iColorRef) ElseIf $iRefType = 2 Then ; RGB hex color to colorref $iColorRef = Hex(String($iColorRef), 6) $iColorRef = '0x' & StringMid($iColorRef, 5, 2) & StringMid($iColorRef, 3, 2) & StringMid($iColorRef, 1, 2) EndIf DllStructSetData($tChoose, "Size", DllStructGetSize($tChoose)) DllStructSetData($tChoose, "hWndOwnder", $hWndOwnder) DllStructSetData($tChoose, "rgbResult", $iColorRef) DllStructSetData($tChoose, "CustColors", DllStructGetPtr($tCc)) $g_hColorProc = DllCallbackRegister(_ColorChooseProc, "int", "hwnd;uint;wparam;lparam") DllStructSetData($tChoose, 'lpfnHook', DllCallbackGetPtr($g_hColorProc)) DllStructSetData($tChoose, "Flags", BitOR($__MISCCONSTANT_CC_ANYCOLOR, $__MISCCONSTANT_CC_FULLOPEN, $__MISCCONSTANT_CC_RGBINIT, $CC_ENABLEHOOK)) Local $aResult = DllCall("comdlg32.dll", "bool", "ChooseColor", "struct*", $tChoose) DllCallbackFree($g_hColorProc) Local $iError = @error If @error Then Local $iExtended = @extended If IsArray($vReturnType) Then $vReturnType[0] = -1 Return SetError($iError, $iExtended, $vReturnType) EndIf Return SetError($iError, $iExtended, -1) EndIf If $aResult[0] = 0 Then ; user selected cancel or struct settings incorrect If IsArray($vReturnType) Then $vReturnType[0] = -1 Return SetError(-3, 0, $vReturnType) EndIf Return SetError(-3, 0, -1) EndIf Local $sColor_picked = DllStructGetData($tChoose, "rgbResult") If $iReturnType = 1 Then ; return Hex BGR Color $vReturn = '0x' & Hex(String($sColor_picked), 6) ElseIf $iReturnType = 2 Then ; return Hex RGB Color $sColor_picked = Hex(String($sColor_picked), 6) $vReturn = '0x' & StringMid($sColor_picked, 5, 2) & StringMid($sColor_picked, 3, 2) & StringMid($sColor_picked, 1, 2) Else ; return RGB COLORREF $vReturn = $sColor_picked EndIf If IsArray($vReturnType) Then $vReturnType = __ChooseColor_StructToArray($tCc) $vReturnType[0] = $vReturn Return $vReturnType EndIf Return $vReturn EndFunc ;==>_ChooseColorHooked Func _ColorChooseProc($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam Local Static $hBrush Switch $iMsg Case $WM_INITDIALOG _WinAPI_DwmSetWindowAttribute($hWnd, $DWMWA_USE_IMMERSIVE_DARK_MODE, True) $hBrush = _WinAPI_CreateSolidBrush(0x202020) ; Find all controls to apply dark theme Local $aCtrls = _WinAPI_EnumChildWindows($hWnd, False) If @error = 0 Then For $i = 1 To $aCtrls[0][0] If $aCtrls[$i][1] = "Button" Then _WinAPI_SetWindowTheme($aCtrls[$i][0], "DarkMode_Explorer") _SendMessage($aCtrls[$i][0], $WM_THEMECHANGED, 0, 0) EndIf If $aCtrls[$i][1] = "Edit" Then _WinAPI_SetWindowTheme($aCtrls[$i][0], "DarkMode_Explorer") _SendMessage($aCtrls[$i][0], $WM_THEMECHANGED, 0, 0) _WinAPI_SetWindowLong($aCtrls[$i][0], $GWL_EXSTYLE, BitAND(_WinAPI_GetWindowLong($aCtrls[$i][0], $GWL_EXSTYLE), BitNOT($WS_EX_CLIENTEDGE))) _WinAPI_SetWindowLong($aCtrls[$i][0], $GWL_EXSTYLE, BitOR(_WinAPI_GetWindowLong($aCtrls[$i][0], $GWL_EXSTYLE), $WS_EX_STATICEDGE)) _WinAPI_SetWindowPos($aCtrls[$i][0], 0, 0, 0, 0, 0, BitOR($SWP_NOMOVE, $SWP_NOSIZE, $SWP_NOZORDER, $SWP_FRAMECHANGED)) EndIf Next EndIf Case $WM_CTLCOLORSTATIC, $WM_CTLCOLORDLG _WinAPI_SetBkMode($wParam, $TRANSPARENT) _WinAPI_SetTextColor($wParam, 0xFFFFFF) Return $hBrush Case $WM_CTLCOLOREDIT _WinAPI_SetBkMode($wParam, $TRANSPARENT) _WinAPI_SetTextColor($wParam, 0xFFFFFF) Return $hBrush Case $WM_CTLCOLORBTN Return $hBrush Case $WM_DESTROY _WinAPI_DeleteObject($hBrush) EndSwitch EndFunc Edited 2 hours ago by WildByDesign
WildByDesign Posted 3 hours ago Author Posted 3 hours ago I am following the MSDN info for: To enable a hook procedure for the Color dialog box I still have to figure out the RegisterWindowMessage stuff: Quote The dialog box sends the COLOROKSTRING registered message to the hook procedure when the user clicks the OK button. The hook procedure can reject the selected color and force the dialog box to remain open by returning zero when it receives this message. The hook procedure can force the dialog box to select a particular color by sending the SETRGBSTRING registered message to the dialog box. To use these registered messages, you must pass the COLOROKSTRING and SETRGBSTRING constants to the RegisterWindowMessage function to get a message identifier. You can then use the identifier to detect and process messages sent from the dialog box, or to send messages to the dialog box.
MattyD Posted 1 hour ago Posted 1 hour ago 1 hour ago, WildByDesign said: I still have to figure out the RegisterWindowMessage stuff: its just to create your own unique WM_ value if you need to use one across apps. So you'll see every time you call $WM_MYCODE = _WinAPI_RegisterWindowMessage("myUnique_WM_Code") it'll return the same value - even after the the original process ends. This registered value will stick around until the end of your windows session. If you're not working across processes, you'd normally just declare a code in the WM_APP range (0x8000 - 0xBFFF). ie. Global Const $WM_MYCODE = $WM_APP+ 10 Just be aware AutoIt might be using some of these for it's own purposes! And to complete the set, there is also the WM_USER range (0x0400 - 0x7FFF) if you need a specify a code for a particular class. eg. toolbar messages are defined as below. The messages mean something to the toolbar control, but something else to another control. #define TB_ENABLEBUTTON (WM_USER + 1) #define TB_CHECKBUTTON (WM_USER + 2) #define TB_PRESSBUTTON (WM_USER + 3) ...
MattyD Posted 39 minutes ago Posted 39 minutes ago (edited) so basically at the top: Global Const $COLOROKSTRING = _WinAPI_RegisterWindowMessage("commdlg_ColorOK") then in _ColorChooseProc you can theoretically Switch $iMsg Case $WM_INITDIALOG .... etc. Case $COLOROKSTRING Local $tChooseColor = DllStructCreate($tagCHOOSECOLOR, $lParam) ... etc. EndSwitch Edit: Without delving too deeply into it, this documentation seems to be wrong... The dialog box sends the COLOROKSTRING registered message to the hook procedure when the user clicks the OK button. The hook procedure can reject the selected color and force the dialog box to remain open by returning zero when it receives this message. Returning 1 keeps the dialog open, 0 closes it and accepts the colour.. Edited 14 minutes ago by MattyD
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