#include-once #include #include #include #include #include #include ;Store COLOR_* as coloref (consistancy with _WinAPI_GetSysColor()) Global Const $MSGBOX_BG_TOP = _WinAPI_SwitchColor(0x323232) Global Const $MSGBOX_BG_BOTTOM = _WinAPI_SwitchColor(0x202020) Global Const $MSGBOX_TEXT = _WinAPI_SwitchColor(0xF0F0F0) Global Const $HCBT_MOVESIZE = 0 Global Const $HCBT_MINMAX = 1 Global Const $HCBT_QS = 2 Global Const $HCBT_CREATEWND = 3 Global Const $HCBT_DESTROYWND = 4 Global Const $HCBT_ACTIVATE = 5 Global Const $HCBT_CLICKSKIPPED = 6 Global Const $HCBT_KEYSKIPPED = 7 Global Const $HCBT_SYSCOMMAND = 8 Global Const $HCBT_SETFOCUS = 9 Global $g_hMsgBoxHook, $g_idTImer, $g_sBtn1_Txt = "Close" Global $g_UseDarkMode 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;uint_ptr;dword_ptr") Global $g_pMsgBoxSubProc = DllCallbackGetPtr($g_hMsgBoxSubProc) Global Enum $PAM_Default, $PAM_AllowDark, $PAM_ForceDark, $PAM_ForceLight, $PAM_Max Global $g_iRevision = RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "UBR") Global $g_b24H2Plus = False If @OSBuild >= 26100 And $g_iRevision >= 6899 Then $g_b24H2Plus = True Global $g_iMsgBoxDpi = Round(_WinAPI_GetDPI() / 96, 2) If @error Then $g_iMsgBoxDpi = 1 OnAutoItExitRegister("_MsgBoxExCleaup") ;From testing, using $PAM_AllowDark will cause _WinAPI_ShouldAppsUseDarkMode() to follow the actual darkmode setting. ;Otherwise you can force _WinAPI_ShouldAppsUseDarkMode to return either way with $PAM_ForceDark & $PAM_ForceLight. ;_WinAPI_SetPreferredAppMode($PAM_AllowDark) Func _MsgBoxExCleaup() DllCallbackFree($g_hMsgBoxSubProc) EndFunc 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 _MsgBoxProc($hWnd, $iMsg, $wParam, $lParam, $iSubClsID, $pData) Local Static $hBkColorBrush, $hFooterBrush, $hTimer Switch $iMsg Case $WM_NCCREATE If $g_UseDarkMode Then _WinAPI_DwmSetWindowAttribute($hWnd, $DWMWA_USE_IMMERSIVE_DARK_MODE, True) Case $WM_INITDIALOG $hBkColorBrush = _WinAPI_CreateSolidBrush($MSGBOX_BG_TOP) $hFooterBrush = _WinAPI_CreateSolidBrush($MSGBOX_BG_BOTTOM) ;_WinAPI_SetDlgItemText($hWnd, $IDOK, StringFormat("%s [%d]", $g_sBtn1_Txt, $g_Timeout)) If $g_Timeout Then _WinAPI_SetDlgItemText($hWnd, $IDOK, StringFormat("%s [%d]", $g_sBtn1_Txt, $g_Timeout)) ConsoleWrite(StringFormat("%s [%d]", $g_sBtn1_Txt, $g_Timeout) & @CRLF) $hTimer = _Timer_SetTimer($hWnd, 1000, "_TimerProc") EndIf Case $WM_CTLCOLORSTATIC, $WM_CTLCOLORDLG If $g_UseDarkMode Then _WinAPI_SetTextColor($wParam, $MSGBOX_TEXT) _WinAPI_SetBkColor($wParam, $MSGBOX_BG_TOP) Return $hBkColorBrush EndIf Case $WM_CTLCOLORBTN If $g_UseDarkMode Then Return $hFooterBrush Case $WM_PAINT If $g_UseDarkMode Then Local $tPS = DllStructCreate($tagPAINTSTRUCT) Local $hDC = _WinAPI_BeginPaint($hWnd, $tPS) Local $tPaintRect = DllStructCreate($tagRECT, DllStructGetPtr($tPS, "rPaint")) ;$tPaintRect.Top = ($tPaintRect.Bottom - 42) $tPaintRect.Top = ($tPaintRect.Bottom - (48 * $g_iMsgBoxDpi)) ; this depends on DPI scale _WinAPI_FillRect($hDC, $tPaintRect, $hFooterBrush) _WinAPI_EndPaint($hWnd, $tPS) Return True EndIf Case $WM_COMMAND Local $iNotifCode = _WinAPI_HiWord($wParam) Local $iItemId = _WinAPI_LoWord($wParam) If (Not $lParam) Or ($iNotifCode = $BN_CLICKED) Then Return _Dialog_EndDialog($hWnd, $iItemId) EndIf Case $WM_DESTROY _Timer_KillTimer($hWnd, $hTimer) _WinAPI_RemoveWindowSubclass($hWnd, $g_pMsgBoxSubProc, $iSubClsID) _WinAPI_SetActiveWindow(_WinAPI_GetParent($hWnd)) _WinAPI_DeleteObject($hBkColorBrush) _WinAPI_DeleteObject($hFooterBrush) EndSwitch Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam) EndFunc Func _TimerProc($hWnd, $iMsg, $wParam, $lParam) If Not _WinAPI_IsWindow($hWnd) Then Return If $g_Timeout <= 1 Then _WinAPI_PostMessage($hWnd, $WM_COMMAND, $IDOK + 1, 0) $g_Timeout -= 1 _WinAPI_SetDlgItemText($hWnd, $IDOK + 1, StringFormat("%s [%d]", $g_sBtn1_Txt, $g_Timeout)) EndFunc Func _CBTHookProc($nCode, $wParam, $lParam) Local Const $hWnd = HWnd($wParam) If $nCode < 0 Then Return _WinAPI_CallNextHookEx($g_hMsgBoxHook, $nCode, $wParam, $lParam) Switch $nCode Case $HCBT_CREATEWND Switch _WinAPI_GetClassName($hWnd) Case "#32770" _WinAPI_SetWindowSubclass($hWnd, $g_pMsgBoxSubProc, 1000) Case "Button" If $g_b24H2Plus Then If $g_UseDarkMode Then _WinAPI_SetWindowTheme($hWnd, "DarkMode_DarkTheme") Else If $g_UseDarkMode Then _WinAPI_SetWindowTheme($hWnd, "DarkMode_Explorer") EndIf EndSwitch EndSwitch Return _WinAPI_CallNextHookEx($g_hMsgBoxHook, $nCode, $wParam, $lParam) EndFunc ;==>_CBTHookProc Func MsgBoxEx($iFlag, $sTitle, $sText, $iTimeout = 0, $hParentHWND = "", $sBtn_Txt = Default) $g_UseDarkMode = _WinAPI_ShouldAppsUseDarkMode() $g_bMsgBoxInitialized = False If $sBtn_Txt <> Default Then $g_sBtn1_Txt = $sBtn_Txt If $iFlag = Default Then $iFlag = BitOR($MB_TOPMOST, $MB_ICONINFORMATION) $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 Func _Dialog_EndDialog($hWnd, $iReturn) Local $aCall = DllCall("User32.dll", "bool", "EndDialog", "hwnd", $hWnd, "int_ptr", $iReturn) If @error Then Return SetError(@error, @extended, False) Return $aCall[0] EndFunc Func _WinAPI_ShouldAppsUseDarkMode() Local $aResult = DllCall("UxTheme.dll", "bool", 132) If @error Then Return SetError(1, 0, False) Return $aResult[0] EndFunc ;==>_WinAPI_AllowDarkModeForWindow Func _WinAPI_SetPreferredAppMode($iMode) Local $aResult = DllCall("UxTheme.dll", "ptr", 135, "int", $iMode) If @error Then Return SetError(1, 0, False) Return $aResult[0] EndFunc Func _WinAPI_GetDPI($hWnd = 0) ; UEZ $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