Jump to content

Recommended Posts

Posted

I'm trying to create a dark mode ChooseFont dialog. The initial hook proc with fnHook / CF_ENABLEHOOK has been successful. However, attempting to load ChooseFont dialog with a custom Font.DLG file has not been successful at all.

I have tried a few variations with $CF_ENABLETEMPLATE which failed and a few variations with $CF_ENABLETEMPLATEHANDLE that also failed.

If anyone is able to help with this, that would be fantastic. I searched back in the forum and could not find any usage of lpTemplateName with the ChooseFont dialog.

In the _ChooseFontHooked() function, I left a comment "Hook and template testing" on line 66 which is the start of the area testing hook and template stuff.

Thank you for your time. :)

Font.DLG

DARKFONTDLG DIALOG 13, 54, 243, 234
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU |
      DS_3DLOOK
CAPTION "Font"
FONT 9, "Segoe UI"
BEGIN
    LTEXT           "&Font:", stc1, 7, 7, 98, 9
    COMBOBOX        cmb1, 7, 16, 98, 76,
                    CBS_SIMPLE | CBS_AUTOHSCROLL | CBS_DISABLENOSCROLL |
                    CBS_SORT | WS_VSCROLL | WS_TABSTOP | CBS_HASSTRINGS |
                    CBS_OWNERDRAWFIXED

    LTEXT           "Font st&yle:", stc2, 114, 7, 74, 9
    COMBOBOX        cmb2, 114, 16, 74, 76,
                    CBS_SIMPLE | CBS_AUTOHSCROLL | CBS_DISABLENOSCROLL |
                    WS_VSCROLL | WS_TABSTOP | CBS_HASSTRINGS |
                    CBS_OWNERDRAWFIXED

    LTEXT           "&Size:", stc3, 198, 7, 36, 9
    COMBOBOX        cmb3, 198, 16, 36, 76,
                    CBS_SIMPLE | CBS_AUTOHSCROLL | CBS_DISABLENOSCROLL |
                    CBS_SORT | WS_VSCROLL | WS_TABSTOP | CBS_HASSTRINGS

    GROUPBOX        "Effects", grp1, 7, 97, 98, 76, WS_GROUP
    AUTOCHECKBOX    "Stri&keout", chx1, 13, 111, 90, 10, WS_TABSTOP
    AUTOCHECKBOX    "&Underline", chx2, 13, 127, 90, 10

    LTEXT           "&Color:", stc4, 13, 144, 89, 9
    COMBOBOX        cmb4, 13, 155, 85, 100,
                    CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL |
                    CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP

    GROUPBOX        "Sample", grp2, 114, 97, 120, 43, WS_GROUP
    CTEXT           "AaBbYyZz", stc5, 116, 106, 117, 33,
                    SS_NOPREFIX | NOT WS_VISIBLE
    LTEXT           "", stc6, 7, 178, 227, 20, SS_NOPREFIX | NOT WS_GROUP

    LTEXT           "Sc&ript:", stc7, 114, 145, 118, 9
    COMBOBOX        cmb5, 114, 155, 120, 30, CBS_DROPDOWNLIST |
                    CBS_AUTOHSCROLL | CBS_HASSTRINGS |
                    WS_BORDER | WS_VSCROLL | WS_TABSTOP

    CONTROL         "<A>Show more fonts</A>", IDC_MANAGE_LINK, "SysLink",
                    WS_TABSTOP, 7, 199, 227, 9

    DEFPUSHBUTTON   "OK", IDOK, 141, 215, 45, 14, WS_GROUP
    PUSHBUTTON      "Cancel", IDCANCEL, 190, 215, 45, 14, WS_GROUP
    PUSHBUTTON      "&Apply", psh3, 92, 215, 45, 14, WS_GROUP
    PUSHBUTTON      "&Help", pshHelp, 43, 215, 45, 14, WS_GROUP
END

 

Testing script:

#include <WinAPIProc.au3>
#include <FontConstants.au3>
#include <StructureConstants.au3>
#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 $CF_ENABLEHOOK = 8
Global Const $CF_ENABLETEMPLATE = 16
Global Const $CF_ENABLETEMPLATEHANDLE = 32

Global Const $sTemplate = @ScriptDir & "\font.dlg"
Global Const $sTemplateName = "DARKFONTDLG"
Global $hTemplate = FileOpen($sTemplate)

Global $g_hDialogProc = 0

_ChooseFontHooked()

FileClose($hTemplate)

Func _ChooseFontHooked($sFontName = "Courier New", $iPointSize = 10, $iFontColorRef = Default, $iFontWeight = 0, $bItalic = False, $bUnderline = False, $bStrikethru = False, $hWndOwner = 0)
    Local $iItalic = 0, $iUnderline = 0, $iStrikeout = 0, $iRetExtended = 0
    If $sFontName = Default Then $sFontName = "Courier New"
    If $iPointSize = Default Then $iPointSize = 10
    If $iFontColorRef = Default Then
        $iFontColorRef = 0
        Local $aRet = DllCall("user32.dll", "int", "GetSysColor", "int", 18) ; $COLOR_BTNTEXT
        If @error Then
            $iRetExtended = @error
        Else
            $iFontColorRef = $aRet[0]
        EndIf
    EndIf
    If $iFontWeight = Default Then $iFontWeight = 0
    If $bItalic = Default Then $bItalic = False
    If $bUnderline = Default Then $bUnderline = False
    If $bStrikethru = Default Then $bStrikethru = False
    If $hWndOwner = Default Then $hWndOwner = 0
    $iFontColorRef = BitOR(BitShift(BitAND($iFontColorRef, 0x000000FF), -16), BitAND($iFontColorRef, 0x0000FF00), BitShift(BitAND($iFontColorRef, 0x00FF0000), 16))

    Local $hDC = __MISC_GetDC(0)
    Local $iHeight = Round(($iPointSize * __MISC_GetDeviceCaps($hDC, $LOGPIXELSX)) / 72, 0)
    __MISC_ReleaseDC(0, $hDC)

    Local $tChooseFont = DllStructCreate($tagCHOOSEFONT)
    Local $tLogFont = DllStructCreate($tagLOGFONT)

    DllStructSetData($tChooseFont, "Size", DllStructGetSize($tChooseFont))
    DllStructSetData($tChooseFont, "hWndOwner", $hWndOwner)
    DllStructSetData($tChooseFont, "LogFont", DllStructGetPtr($tLogFont))
    DllStructSetData($tChooseFont, "PointSize", $iPointSize)

    ; Hook and template testing
    $g_hDialogProc = DllCallbackRegister(_DialogProc, "int", "hwnd;uint;wparam;lparam")
    DllStructSetData($tChooseFont, 'fnHook', DllCallbackGetPtr($g_hDialogProc))
    ;DllStructSetData($tChooseFont, "Flags", BitOR($CF_SCREENFONTS, $CF_PRINTERFONTS, $CF_EFFECTS, $CF_INITTOLOGFONTSTRUCT, $CF_NOSCRIPTSEL, $CF_ENABLEHOOK)) ; <<< this works with hook but no custom template
    DllStructSetData($tChooseFont, "Flags", BitOR($CF_SCREENFONTS, $CF_PRINTERFONTS, $CF_EFFECTS, $CF_INITTOLOGFONTSTRUCT, $CF_NOSCRIPTSEL, $CF_ENABLEHOOK, $CF_ENABLETEMPLATE))
    ;DllStructSetData($tChooseFont, "Flags", BitOR($CF_SCREENFONTS, $CF_PRINTERFONTS, $CF_EFFECTS, $CF_INITTOLOGFONTSTRUCT, $CF_NOSCRIPTSEL, $CF_ENABLEHOOK, $CF_ENABLETEMPLATEHANDLE))
    ;DllStructSetData($tChooseFont, 'hInstance', $hTemplate)
    DllStructSetData($tChooseFont, 'hInstance', Null)
    Local $tagBuffer = "char[4096]", $iBufferSize = 4095
    ;If $fUnicode Then $tagBuffer = "w" & $tagBuffer
    Local $tTemplateName = DllStructCreate($tagBuffer);'char[256]')
    DllStructSetData($tTemplateName, 1, $sTemplateName)
    DllStructSetData($tChooseFont, 'lpTemplateName', DllStructGetPtr($tTemplateName))

    DllStructSetData($tChooseFont, "rgbColors", $iFontColorRef)
    DllStructSetData($tChooseFont, "FontType", 0)

    DllStructSetData($tLogFont, "Height", $iHeight)
    DllStructSetData($tLogFont, "Weight", $iFontWeight)
    DllStructSetData($tLogFont, "Italic", $bItalic)
    DllStructSetData($tLogFont, "Underline", $bUnderline)
    DllStructSetData($tLogFont, "Strikeout", $bStrikethru)
    DllStructSetData($tLogFont, "FaceName", $sFontName)

    Local $aCall = DllCall("comdlg32.dll", "bool", "ChooseFontW", "struct*", $tChooseFont)
    If @error Then Return SetError(@error, @extended, -2) ; ..to differentiate from the error below
    If $aCall[0] = 0 Then Return SetError(-3, $iRetExtended, -1) ; user selected cancel or struct settings incorrect

    Local $sFaceName = DllStructGetData($tLogFont, "FaceName")
    If StringLen($sFaceName) = 0 And StringLen($sFontName) > 0 Then $sFaceName = $sFontName

    If DllStructGetData($tLogFont, "Italic") Then $iItalic = 2
    If DllStructGetData($tLogFont, "Underline") Then $iUnderline = 4
    If DllStructGetData($tLogFont, "Strikeout") Then $iStrikeout = 8

    Local $iAttributes = BitOR($iItalic, $iUnderline, $iStrikeout)
    Local $iSize = DllStructGetData($tChooseFont, "PointSize") / 10
    Local $iColorRef = DllStructGetData($tChooseFont, "rgbColors")
    Local $iWeight = DllStructGetData($tLogFont, "Weight")

    Local $sColor_picked = Hex(String($iColorRef), 6)

    Return SetError(0, $iRetExtended, StringSplit($iAttributes & "," & $sFaceName & "," & $iSize & "," & $iWeight & "," & $iColorRef & "," & _
            '0x' & $sColor_picked & "," & '0x' & StringMid($sColor_picked, 5, 2) & StringMid($sColor_picked, 3, 2) & StringMid($sColor_picked, 1, 2), ","))
EndFunc   ;==>_ChooseFontHooked

Func _DialogProc($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)

            Local $aCtrlsEx = _WinAPI_EnumProcessWindows(0, False) ; allows getting handles for tooltips_class32, ComboLBox, etc.
            If @error = 0 Then
                For $i = 1 To $aCtrlsEx[0][0]
                    ;If $aCtrlsEx[$i][1] = 'tooltips_class32' Then _GUIDarkTheme_GUICtrlSetDarkTheme($hGui, $aCtrlsEx[$i][0], $bEnableDarkTheme)
                    If $aCtrlsEx[$i][1] = 'ComboLBox' Then
                        _WinAPI_SetWindowTheme($aCtrlsEx[$i][0], "DarkMode_Explorer")
                        _SendMessage($aCtrlsEx[$i][0], $WM_THEMECHANGED, 0, 0)
                    EndIf
                Next
            EndIf

            ; Find all controls to apply dark theme
            Local $aCtrls = _WinAPI_EnumChildWindows($hWnd, False)
            If @error = 0 Then
                For $i = 1 To $aCtrls[0][0]
                    ;ConsoleWrite("class: " & $aCtrls[$i][1] & " hwnd: " & $aCtrls[$i][0] & @CRLF)
                    If $aCtrls[$i][1] = "Button" Then
                        _WinAPI_SetWindowTheme($aCtrls[$i][0], "DarkMode_Explorer")
                        ;_WinAPI_SetWindowTheme($aCtrls[$i][0], "DarkMode_DarkTheme") ; DarkMode_DarkTheme needed for group box
                        _SendMessage($aCtrls[$i][0], $WM_THEMECHANGED, 0, 0)
                    EndIf
                    If $aCtrls[$i][1] = "ComboBox" Then
                        _WinAPI_SetWindowTheme($aCtrls[$i][0], "DarkMode_CFD")
                        _SendMessage($aCtrls[$i][0], $WM_THEMECHANGED, 0, 0)
                    EndIf
                    If $aCtrls[$i][1] = "ComboLBox" 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_SHOWWINDOW
            ; center dialog on desktop
            Local $aChildPos = WinGetPos($hWnd)
            WinMove($hWnd, "", (@DesktopWidth / 2 - ($aChildPos[2] / 2)), (@DesktopHeight / 2 - ($aChildPos[3] / 2)))

        Case $WM_CTLCOLORSTATIC,  $WM_CTLCOLORDLG
            _WinAPI_SetBkMode($wParam, $TRANSPARENT)
            _WinAPI_SetTextColor($wParam, 0xFFFFFF)
            Return $hBrush

        Case $WM_CTLCOLOREDIT, $WM_CTLCOLORLISTBOX
            _WinAPI_SetBkMode($wParam, $TRANSPARENT)
            _WinAPI_SetTextColor($wParam, 0xFFFFFF)
            Return $hBrush

        Case $WM_CTLCOLORBTN
            _WinAPI_SetBkColor($wParam, 0x000000) ; needed for focus rectangle
            Return $hBrush

        Case $WM_DESTROY
            _WinAPI_DeleteObject($hBrush)

    EndSwitch
EndFunc

 

Posted
12 hours ago, ahmet said:

I suppose that you need to save font.dlg to the resource of the exe file.

Thanks for your response. Unfortunately I was really hoping to be able to achieve this without compiling to .dll or .exe binary. I'm starting to think that it might not be possible without compiling.

Posted
1 hour ago, ahmet said:

What is your goal?

I'm trying to replicate this C++ souce code in AutoIt:

	/**
	 * @brief Hook procedure for customizing common dialogs with dark mode.
	 *
	 * This function handles messages for all Windows common dialogs.
	 * When initialized (`WM_INITDIALOG`), it applies dark mode styling to the dialog.
	 *
	 * ## Special Case: Font Dialog Workaround
	 * - When a hook is used with `ChooseFont`, Windows **automatically falls back**
	 *   to an **older template**, losing modern UI elements.
	 * - To prevent this forced downgrade, a **modified template** (based on Font.dlg) is used.
	 * - **CBS_OWNERDRAWFIXED should be removed** from the **Size** and **Script** combo boxes
	 *   to restore proper visualization.
	 * - **Custom owner-draw visuals remain** for other font combo boxes to allow font preview.
	 * - Same for the `"AaBbYyZz"` sample text.
	 * - However **Automatic system translation for captions and static texts is lost** in this workaround.
	 *
	 * ## Custom Font Dialog Template (Resource File)
	 * ```rc
	 * IDD_DARK_FONT_DIALOG DIALOG 13, 54, 243, 234
	 * STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU |
	 *       DS_3DLOOK
	 * CAPTION "Font"
	 * FONT 9, "Segoe UI"
	 * BEGIN
	 *     LTEXT           "&Font:", stc1, 7, 7, 98, 9
	 *     COMBOBOX        cmb1, 7, 16, 98, 76,
	 *                     CBS_SIMPLE | CBS_AUTOHSCROLL | CBS_DISABLENOSCROLL |
	 *                     CBS_SORT | WS_VSCROLL | WS_TABSTOP | CBS_HASSTRINGS |
	 *                     CBS_OWNERDRAWFIXED
	 *
	 *     LTEXT           "Font st&yle:", stc2, 114, 7, 74, 9
	 *     COMBOBOX        cmb2, 114, 16, 74, 76,
	 *                     CBS_SIMPLE | CBS_AUTOHSCROLL | CBS_DISABLENOSCROLL |
	 *                     WS_VSCROLL | WS_TABSTOP | CBS_HASSTRINGS |
	 *                     CBS_OWNERDRAWFIXED
	 *
	 *     LTEXT           "&Size:", stc3, 198, 7, 36, 9
	 *     COMBOBOX        cmb3, 198, 16, 36, 76,
	 *                     CBS_SIMPLE | CBS_AUTOHSCROLL | CBS_DISABLENOSCROLL |
	 *                     CBS_SORT | WS_VSCROLL | WS_TABSTOP | CBS_HASSTRINGS |
	 *                     CBS_OWNERDRAWFIXED // remove CBS_OWNERDRAWFIXED
	 *
	 *     GROUPBOX        "Effects", grp1, 7, 97, 98, 76, WS_GROUP
	 *     AUTOCHECKBOX    "Stri&keout", chx1, 13, 111, 90, 10, WS_TABSTOP
	 *     AUTOCHECKBOX    "&Underline", chx2, 13, 127, 90, 10
	 *
	 *     LTEXT           "&Color:", stc4, 13, 144, 89, 9
	 *     COMBOBOX        cmb4, 13, 155, 85, 100,
	 *                     CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL |
	 *                     CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
	 *
	 *     GROUPBOX        "Sample", grp2, 114, 97, 120, 43, WS_GROUP
	 *     CTEXT           "AaBbYyZz", stc5, 116, 106, 117, 33,
	 *                     SS_NOPREFIX | NOT WS_VISIBLE
	 *     LTEXT           "", stc6, 7, 178, 227, 20, SS_NOPREFIX | NOT WS_GROUP
	 *
	 *     LTEXT           "Sc&ript:", stc7, 114, 145, 118, 9
	 *     COMBOBOX        cmb5, 114, 155, 120, 30, CBS_DROPDOWNLIST |
	 *                     CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_HASSTRINGS | // remove CBS_OWNERDRAWFIXED
	 *                     WS_BORDER | WS_VSCROLL | WS_TABSTOP
	 *
	 *     CONTROL         "<A>Show more fonts</A>", IDC_MANAGE_LINK, "SysLink",
	 *                     WS_TABSTOP, 7, 199, 227, 9
	 *
	 *     DEFPUSHBUTTON   "OK", IDOK, 141, 215, 45, 14, WS_GROUP
	 *     PUSHBUTTON      "Cancel", IDCANCEL, 190, 215, 45, 14, WS_GROUP
	 *     PUSHBUTTON      "&Apply", psh3, 92, 215, 45, 14, WS_GROUP
	 *     PUSHBUTTON      "&Help", pshHelp, 43, 215, 45, 14, WS_GROUP
	 * END
	 * ```
	 *
	 * ## Usage Example:
	 * ```cpp
	 * #define IDD_DARK_FONT_DIALOG 1000 // usually in resource.h or other header
	 *
	 * CHOOSEFONT cf{};
	 * cf.Flags |= CF_ENABLEHOOK | CF_ENABLETEMPLATE;
	 * cf.lpfnHook = static_cast<LPCFHOOKPROC>(dmlib::HookDlgProc);
	 * cf.hInstance = GetModuleHandle(nullptr);
	 * cf.lpTemplateName = MAKEINTRESOURCE(IDD_DARK_FONT_DIALOG);
	 * ```
	 *
	 * @param[in]   hWnd        Handle to the dialog window.
	 * @param[in]   uMsg        Message identifier.
	 * @param[in]   wParam      First message parameter (unused).
	 * @param[in]   lParam      Second message parameter (unused).
	 * @return UINT_PTR A value defined by the hook procedure.
	 */

Unfortunately, $CBS_OWNERDRAWFIXED is a style that cannot be removed with _WinAPI_SetWindowLong() after the dialog has already been created. So the technique that I am attempting to do involves loading a modified Font.Dlg template which has $CBS_OWNERDRAWFIXED already removed.

Posted

..if you can load the fancy combo with each line having the font applied to it, we can use that and make out own GUI.
Is an interface to choose a font and that's all that is.
Go figure if in 27H2 they fix it 🤷‍♂️
So if this approach don't work out, look for a pleasing familiar ( visually GUI wise ) and go with that.

Am sure one of those MVPs will snick it in the standard UDFs somehow 😇

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
15 hours ago, argumentum said:

..just run the thing and is too CPU intensive.

I did not spot any issues with the Dialog_Box_Resources.au3. There is high CPU usage with the generated files becuse of While loop without Sleep. Once you put sleep in the generated file CPU usage drops.

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