WildByDesign Posted December 27, 2025 Author Posted December 27, 2025 For what it's worth, here is what ended up working for me: ;============================================== Func WM_MOVE($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $wParam, $lParam Local Static $bSizeboxOffScreen = False If $hWnd = $g_hGUI Then Local $aPos = WinGetPos($g_hSizebox) If $aPos[0] + $aPos[2] > @DesktopWidth Or $aPos[1] + $aPos[3] > @DesktopHeight Then $bSizeboxOffScreen = True Else If $bSizeboxOffScreen Then ; sizebox was off-screen but is back in range now, redraw GUI _WinAPI_RedrawWindow($g_hGui) $bSizeboxOffScreen = False EndIf EndIf _WinAPI_RedrawWindow($g_hSizebox) EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_MOVE Keep in mind that this may or may not work in a multi-monitor setup. However, multi-monitor setups require quite a bit different DPI scaling settings and so on. So this is quite basic but it works 100% of the time for me.
WildByDesign Posted Sunday at 03:22 AM Author Posted Sunday at 03:22 AM I just wanted to share an updated version of the CreateDots function which matches the Windows gripper dots identically. The dot size, dot spacing and placement on the statusbar is a perfect match now at 100%, 125%, 150% and 175% DPI scaling. Please note, my monitor does not do 200% scaling or higher and therefore 200% and higher are untested. The dots are so accurate that I tested by removing the ownerdrawn parts and applied light mode Explorer theme to the statusbar which shows the default gripper dots. I then used System Informer to hide/unhide the "Scrollbar" window and everything was perfect at 100%, 125%, 150% and 175% DPI scaling. I am a little bit frustrated that I can't test anything higher. Changes: expandcollapse popup; set base DPI scale value and apply DPI Global $iDPI = 1 ApplyDPI() ; DPI needs to be applied before the Example() function Func ApplyDPI() ; apply System DPI awareness DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext" , "HWND", "DPI_AWARENESS_CONTEXT" -2) ; update DPI scale value based on DPI scaling already applied to AutoIt hidden window $iDPI = Round(_WinAPI_GetDpiForWindow(WinGetHandle(AutoItWinGetTitle())) / 96, 2) If @error Then $iDPI = 1 EndFunc ... ;============================================== Func CreateDots($iWidth, $iHeight, $iBackgroundColor, $iDotsColor) ; Andreik Local $iDotSize, $iDotSpace, $iDotFrame Switch $iDPI Case 1 ; 100% scaling $iDotSize = 2 $iDotSpace = $iDotSize - 1 ; ensures that dots have only 1 pixel of space between $iDotFrame = -1 ; controls the distance from frame Local $a[6][2] = [[3,9], [3,6], [3,3], [6,6], [6,3], [9,3]] Case 1.25 ; 125% scaling $iDotSize = 3 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] Case 1.5 ; 150% scaling $iDotSize = 3 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] Case 1.75 ; 175% scaling $iDotSize = 3 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] Case 2 ; 200% scaling $iDotSize = 4 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] Case Else $iDotSize = 1 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] EndSwitch Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight) Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap) Local $hBrush = _GDIPlus_BrushCreateSolid($iDotsColor) _GDIPlus_GraphicsClear($hGraphics, $iBackgroundColor) For $i = 0 To UBound($a) - 1 _GDIPlus_GraphicsFillRect($hGraphics, $iWidth - ($iDotSpace * $a[$i][0]) + $iDotFrame, $iHeight - ($iDotSpace * $a[$i][1]) + $iDotFrame, $iDotSize, $iDotSize, $hBrush) Next _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGraphics) Return $hBitmap EndFunc ;==>CreateDots ... Func _WinAPI_GetDpiForWindow($hWnd) ; UEZ 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 And here is the full working script: expandcollapse popup#include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <GuiStatusBar.au3> #include <StaticConstants.au3> #include <WinAPIGdi.au3> #include <WinAPIRes.au3> #include <WinAPISysWin.au3> #include <WinAPITheme.au3> #include <WindowsConstants.au3> Opt("MustDeclareVars", 1) Global $g_hGui, $g_hSizebox, $g_hOldProc, $g_hStatus, $g_iHeight, $g_aText, $g_aRatioW, $g_iBkColor, $g_iTextColor, $g_hDots ; Global $g_hBrush ; no need, as _GUICtrlStatusBar_SetBkColor() placed after _WinAPI_SetWindowTheme() does the job correctly ; set base DPI scale value and apply DPI Global $iDPI = 1 ApplyDPI() Func ApplyDPI() ; apply System DPI awareness DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext" , "HWND", "DPI_AWARENESS_CONTEXT" -2) ; update DPI scale value based on DPI scaling already applied to AutoIt hidden window $iDPI = Round(_WinAPI_GetDpiForWindow(WinGetHandle(AutoItWinGetTitle())) / 96, 2) If @error Then $iDPI = 1 EndFunc Example() ;============================================== Func Example() _GDIPlus_Startup() Local Const $SBS_SIZEBOX = 0x08, $SBS_SIZEGRIP = 0x10 Local $iW = 300, $iH = 100 Dim $g_iBkColor = 0x383838, $g_iTextColor = 0xFFFFFF $g_hGui = GUICreate("Resize corner", $iW, $iH, -1, -1, $WS_OVERLAPPEDWINDOW) GUISetBkColor($g_iBkColor) ;----------------- ; Create a sizebox window (Scrollbar class) BEFORE creating the StatusBar control $g_hSizebox = _WinAPI_CreateWindowEx(0, "Scrollbar", "", $WS_CHILD + $WS_VISIBLE + $SBS_SIZEBOX, _ 0, 0, 0, 0, $g_hGui) ; $SBS_SIZEBOX or $SBS_SIZEGRIP ; Subclass the sizebox (by changing the window procedure associated with the Scrollbar class) Local $hProc = DllCallbackRegister('ScrollbarProc', 'lresult', 'hwnd;uint;wparam;lparam') $g_hOldProc = _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, DllCallbackGetPtr($hProc)) Local $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZENWSE) _WinAPI_SetClassLongEx($g_hSizebox, -12, $hCursor) ; $GCL_HCURSOR = -12 ; $g_hBrush = _WinAPI_CreateSolidBrush($g_iBkColor) ;----------------- $g_hStatus = _GUICtrlStatusBar_Create($g_hGui, -1, "", $WS_CLIPSIBLINGS) ; ClipSiblings style +++ Local $aParts[3] = [90, 180, 280] If $aParts[Ubound($aParts) - 1] = -1 Then $aParts[Ubound($aParts) - 1] = $iW ; client width size _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts) Dim $g_aText[Ubound($aParts)] = ["Part 0", "Part 1", "Part 2"] Dim $g_aRatioW[Ubound($aParts)] For $i = 0 To UBound($g_aText) - 1 _GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW) ; _GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW + $SBT_NOBORDERS) ; interesting ? $g_aRatioW[$i] = $aParts[$i] / $iW Next Local $idChangeText = GUICtrlCreateLabel("Change Text", 110, 25, 80, 30, $SS_CENTER + $SS_CENTERIMAGE), $iInc GUICtrlSetColor(-1, 0xFFFF00) ; yellow ; to allow the setting of StatusBar BkColor at least under Windows 10 _WinAPI_SetWindowTheme($g_hStatus, "", "") ; Set status bar background color _GUICtrlStatusBar_SetBkColor($g_hStatus, $g_iBkColor) $g_iHeight = _GUICtrlStatusBar_GetHeight($g_hStatus) + 3 ; change the constant (+3) if necessary $g_hDots = CreateDots($g_iHeight, $g_iHeight, 0xFF000000 + $g_iBkColor, 0xFF000000 + $g_iTextColor) GUIRegisterMsg($WM_SIZE, "WM_SIZE") GUIRegisterMsg($WM_MOVE, "WM_MOVE") GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM") GUISetState() While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idChangeText $iInc += 1 For $i = 0 To UBound($g_aText) - 1 $g_aText[$i] = "Part " & $i & " : Inc " & $iInc Next _WinAPI_RedrawWindow($g_hStatus) EndSwitch WEnd _GDIPlus_BitmapDispose($g_hDots) _GUICtrlStatusBar_Destroy($g_hStatus) _WinAPI_DestroyCursor($hCursor) ; _WinAPI_DeleteObject($g_hBrush) _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, $g_hOldProc) DllCallbackFree($hProc) _GDIPlus_Shutdown() EndFunc ;==>Example ;============================================== Func ScrollbarProc($hWnd, $iMsg, $wParam, $lParam) ; Andreik If $iMsg = $WM_PAINT Then Local $tPAINTSTRUCT Local $hDC = _WinAPI_BeginPaint($hWnd, $tPAINTSTRUCT) Local $iWidth = DllStructGetData($tPAINTSTRUCT, 'rPaint', 3) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 1) Local $iHeight = DllStructGetData($tPAINTSTRUCT, 'rPaint', 4) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 2) Local $hGraphics = _GDIPlus_GraphicsCreateFromHDC($hDC) _GDIPlus_GraphicsDrawImageRect($hGraphics, $g_hDots, 0, 0, $iWidth, $iHeight) _GDIPlus_GraphicsDispose($hGraphics) _WinAPI_EndPaint($hWnd, $tPAINTSTRUCT) Return 0 EndIf Return _WinAPI_CallWindowProc($g_hOldProc, $hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>ScrollbarProc ;============================================== Func CreateDots($iWidth, $iHeight, $iBackgroundColor, $iDotsColor) ; Andreik Local $iDotSize, $iDotSpace, $iDotFrame Switch $iDPI Case 1 ; 100% scaling $iDotSize = 2 $iDotSpace = $iDotSize - 1 ; ensures that dots have only 1 pixel of space between $iDotFrame = -1 ; controls the distance from frame Local $a[6][2] = [[3,9], [3,6], [3,3], [6,6], [6,3], [9,3]] Case 1.25 ; 125% scaling $iDotSize = 3 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] Case 1.5 ; 150% scaling $iDotSize = 3 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] Case 1.75 ; 175% scaling $iDotSize = 3 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] Case 2 ; 200% scaling $iDotSize = 4 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] Case Else $iDotSize = 1 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] EndSwitch Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight) Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap) Local $hBrush = _GDIPlus_BrushCreateSolid($iDotsColor) _GDIPlus_GraphicsClear($hGraphics, $iBackgroundColor) For $i = 0 To UBound($a) - 1 _GDIPlus_GraphicsFillRect($hGraphics, $iWidth - ($iDotSpace * $a[$i][0]) + $iDotFrame, $iHeight - ($iDotSpace * $a[$i][1]) + $iDotFrame, $iDotSize, $iDotSize, $hBrush) Next _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGraphics) Return $hBitmap EndFunc ;==>CreateDots ;============================================== Func CreateDots_old($iWidth, $iHeight, $iBackgroundColor, $iDotsColor) ; Andreik Local $iDotSize = Int($iHeight / 10) Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight) Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap) Local $hBrush = _GDIPlus_BrushCreateSolid($iDotsColor) _GDIPlus_GraphicsClear($hGraphics, $iBackgroundColor) Local $a[6][2] = [[2,6], [2,4], [2,2], [4,4], [4,2], [6,2]] For $i = 0 To UBound($a) - 1 _GDIPlus_GraphicsFillRect($hGraphics, $iWidth - $iDotSize * $a[$i][0], $iHeight - $iDotSize * $a[$i][1], $iDotSize, $iDotSize, $hBrush) Next _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGraphics) Return $hBitmap EndFunc ;==>CreateDots_old ;============================================== Func _MyGUICtrlStatusBar_SetParts($hWnd, $aPartEdge) ; Pixelsearch If Not IsArray($aPartEdge) Then Return False Local $iParts = UBound($aPartEdge) Local $tParts = DllStructCreate("int[" & $iParts & "]") For $i = 0 To $iParts - 1 DllStructSetData($tParts, 1, $aPartEdge[$i], $i + 1) Next DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", $SB_SETPARTS, "wparam", $iParts, "struct*", $tParts) _GUICtrlStatusBar_Resize($hWnd) Return True EndFunc ;==>_MyGUICtrlStatusBar_SetParts ;============================================== Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) ; Pixelsearch #forceref $iMsg, $wParam, $lParam If $hWnd = $g_hGUI Then Local Static $bIsSizeBoxShown = True Local $aSize = WinGetClientSize($g_hGui) Local $aGetParts = _GUICtrlStatusBar_GetParts($g_hStatus) Local $aParts[$aGetParts[0]] For $i = 0 To $aGetParts[0] - 1 $aParts[$i] = Int($aSize[0] * $g_aRatioW[$i]) Next If BitAND(WinGetState($g_hGui), $WIN_STATE_MAXIMIZED) Then _GUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until GUI right border (AutoIt function forces it) _WinAPI_ShowWindow($g_hSizebox, @SW_HIDE) $bIsSizeBoxShown = False Else If $g_aRatioW[UBound($aParts) -1] <> 1 Then $aParts[UBound($aParts) -1] = $aSize[0] - $g_iHeight ; right size of right part stuck on sizebox (no gap) _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until sizebox (see preceding line) or until GUI right border WinMove($g_hSizebox, "", $aSize[0] - $g_iHeight, $aSize[1] - $g_iHeight, $g_iHeight, $g_iHeight) If Not $bIsSizeBoxShown Then _WinAPI_ShowWindow($g_hSizebox, @SW_SHOW) $bIsSizeBoxShown = True EndIf EndIf EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_SIZE ;============================================== Func WM_MOVE($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $wParam, $lParam If $hWnd = $g_hGUI Then _WinAPI_RedrawWindow($g_hSizebox) EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_MOVE ;============================================== Func WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam) ; Kafu #forceref $hWnd, $iMsg, $wParam Local Static $tagDRAWITEM = "uint CtlType;uint CtlID;uint itemID;uint itemAction;uint itemState;hwnd hwndItem;handle hDC;long rcItem[4];ulong_ptr itemData" Local $tDRAWITEM = DllStructCreate($tagDRAWITEM, $lParam) If $tDRAWITEM.hwndItem <> $g_hStatus Then Return $GUI_RUNDEFMSG ; only process the statusbar Local $itemID = $tDRAWITEM.itemID ; status bar part number : 0 if simple bar (or 0, 1, 2... if multi parts) Local $hDC = $tDRAWITEM.hDC Local $tRect = DllStructCreate("long left;long top;long right;long bottom", DllStructGetPtr($tDRAWITEM, "rcItem")) ; _WinAPI_FillRect($hDC, DllStructGetPtr($tRect), $g_hBrush) ; backgound color _WinAPI_SetTextColor($hDC, $g_iTextColor) ; text color _WinAPI_SetBkMode($hDC, $TRANSPARENT) DllStructSetData($tRect, "top", $tRect.top + 1) DllStructSetData($tRect, "left", $tRect.left + 1) _WinAPI_DrawText($hDC, $g_aText[$itemID], $tRect, $DT_LEFT) Return $GUI_RUNDEFMSG EndFunc ;==>WM_DRAWITEM Func _WinAPI_GetDpiForWindow($hWnd) ; UEZ 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 ioa747 and argumentum 2
ioa747 Posted Sunday at 08:08 AM Posted Sunday at 08:08 AM (edited) with sacrifice ? expandcollapse popup#include <GUIConstantsEx.au3> #include <GuiStatusBar.au3> #include <StaticConstants.au3> #include <WinAPIGdi.au3> #include <WindowsConstants.au3> #include <WinAPITheme.au3> Opt("MustDeclareVars", 1) Global $g_hGui, $g_idSizeGrip, $g_hStatus, $g_iHeight Global $g_iBkColor = 0x383838, $g_iTextColor = 0xFFFFFF Global $iDPI = 1 Global $g_iGripW = _WinAPI_GetSystemMetrics($SM_CXVSCROLL) ; Initialize arrays properly at start Global $g_aText[3] = ["Part 0", "Part 1", "Part 2"] Global $g_aRatioW[3] = [0.3, 0.6, 1.0] ; Proportions for resizing ApplyDPI() Example() ;--------------------------------------------------------------------------------------- Func Example() ; Create Main GUI Local $iW = 400, $iH = 200 ; Create Main GUI $g_hGui = GUICreate("Resize Corner ", $iW, $iH, -1, -1, $WS_OVERLAPPEDWINDOW) GUISetBkColor($g_iBkColor) ; Create StatusBar _Create_StatusBar($iW, $iH) Local $idChangeText = GUICtrlCreateLabel("Change Text", 110, 25, 80, 30, $SS_CENTER + $SS_CENTERIMAGE), $iInc GUICtrlSetColor(-1, 0xFFFF00) ; yellow GUICtrlSetResizing(-1, $GUI_DOCKSIZE) ; Register Messages for real-time response GUIRegisterMsg($WM_SIZE, "WM_SIZE") GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM") GUISetState(@SW_SHOW) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idChangeText $iInc += 1 For $i = 0 To UBound($g_aText) - 1 $g_aText[$i] = "Part " & $i & " : Inc " & $iInc Next _WinAPI_RedrawWindow($g_hGui) EndSwitch WEnd EndFunc ;==>Example ;--------------------------------------------------------------------------------------- Func _Create_StatusBar($iW, $iH) ; Create StatusBar $g_hStatus = _GUICtrlStatusBar_Create($g_hGui, -1, "", $WS_CLIPSIBLINGS) _WinAPI_SetWindowTheme($g_hStatus, "", "") _GUICtrlStatusBar_SetBkColor($g_hStatus, $g_iBkColor) ; Initial Parts setup Local $aInitialParts[3] = [Int($iW * 0.3), Int($iW * 0.6), $iW - $g_iGripW] _MyGUICtrlStatusBar_SetParts($g_hStatus, $aInitialParts) For $i = 0 To UBound($g_aText) - 1 _GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW) Next ; Create the Grip Label 0x2591(░) or 0x2592(▒) or 0x2593(▓) $g_iHeight = _GUICtrlStatusBar_GetHeight($g_hStatus) $g_idSizeGrip = GUICtrlCreateLabel(ChrW(0x2591), $iW - $g_iGripW, $iH - $g_iHeight - 3, $g_iGripW, $g_iHeight + 3) GUICtrlSetFont(-1, $g_iHeight) ;, 400, 0, "Lucida Console") GUICtrlSetColor(-1, $g_iTextColor) GUICtrlSetBkColor(-1, $g_iBkColor) ;~ GUICtrlSetCursor(-1, 12) ; IDC_SIZENWSE ; ?? GUICtrlSetResizing(-1, $GUI_DOCKSIZE + $GUI_DOCKRIGHT + $GUI_DOCKBOTTOM) ; Defines the resizing method EndFunc ;==>_Create_StatusBar ;--------------------------------------------------------------------------------------- Func _MyGUICtrlStatusBar_SetParts($hWnd, $aPartEdge) ; Function to set StatusBar parts Local $iParts = UBound($aPartEdge) Local $tParts = DllStructCreate("int[" & $iParts & "]") For $i = 0 To $iParts - 1 DllStructSetData($tParts, 1, $aPartEdge[$i], $i + 1) Next DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", $SB_SETPARTS, "wparam", $iParts, "struct*", $tParts) Return True EndFunc ;==>_MyGUICtrlStatusBar_SetParts ;--------------------------------------------------------------------------------------- Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) ; This function handles the resizing in real-time #forceref $iMsg, $wParam, $lParam If $hWnd = $g_hGui Then ; Get new Client Area dimensions Local $iW = BitAND($lParam, 0xFFFF) Local $iH = BitShift($lParam, 16) ; Resize StatusBar parts Local $aParts[3] $aParts[0] = Int($iW * $g_aRatioW[0]) $aParts[1] = Int($iW * $g_aRatioW[1]) $aParts[2] = $iW - $g_iGripW ; Ensure there's a $g_iGripW gap for the grip character _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts) _GUICtrlStatusBar_Resize($g_hStatus) ; Force the status bar to redraw itself ; Move the Grip Label precisely using WinAPI for zero lag Local $hGrip = GUICtrlGetHandle($g_idSizeGrip) _WinAPI_MoveWindow($hGrip, $iW - $g_iGripW, $iH - $g_iHeight - 3, $g_iGripW, $g_iHeight + 3, True) EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_SIZE ;--------------------------------------------------------------------------------------- Func WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam) ; Custom Text Drawing #forceref $hWnd, $iMsg, $wParam Local $tDRAWITEM = DllStructCreate("uint CtlType;uint CtlID;uint itemID;uint itemAction;uint itemState;hwnd hwndItem;handle hDC;long rcItem[4];ulong_ptr itemData", $lParam) If DllStructGetData($tDRAWITEM, "hwndItem") = $g_hStatus Then Local $hDC = DllStructGetData($tDRAWITEM, "hDC") Local $itemID = DllStructGetData($tDRAWITEM, "itemID") _WinAPI_SetTextColor($hDC, $g_iTextColor) _WinAPI_SetBkMode($hDC, 1) ; TRANSPARENT Local $tRect = DllStructCreate("long left;long top;long right;long bottom") DllStructSetData($tRect, "left", DllStructGetData($tDRAWITEM, "rcItem", 1) + 6) DllStructSetData($tRect, "top", DllStructGetData($tDRAWITEM, "rcItem", 2) + 3) DllStructSetData($tRect, "right", DllStructGetData($tDRAWITEM, "rcItem", 3)) DllStructSetData($tRect, "bottom", DllStructGetData($tDRAWITEM, "rcItem", 4)) _WinAPI_DrawText($hDC, $g_aText[$itemID], $tRect, $DT_LEFT) Return True EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_DRAWITEM ;--------------------------------------------------------------------------------------- Func ApplyDPI() ; Apply DPI DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "HWND", -2) Local $hAutoIt = WinGetHandle(AutoItWinGetTitle()) $iDPI = _WinAPI_GetDpiForWindow($hAutoIt) / 96 If @error Or $iDPI <= 0 Then $iDPI = 1 EndFunc ;==>ApplyDPI ;--------------------------------------------------------------------------------------- Func _WinAPI_GetDpiForWindow($hWnd) ; Get Dpi Local $aResult = DllCall("user32.dll", "uint", "GetDpiForWindow", "hwnd", $hWnd) If @error Then Return 96 Return $aResult[0] EndFunc ;==>_WinAPI_GetDpiForWindow ;--------------------------------------------------------------------------------------- Edited Sunday at 11:35 AM by ioa747 chance to $SM_CXVSCROLL WildByDesign 1 I know that I know nothing
argumentum Posted Sunday at 04:45 PM Posted Sunday at 04:45 PM 13 hours ago, WildByDesign said: I am a little bit frustrated that I can't test anything higher. ...all you need is an 8k monitor. If the wife ask about the expense, you say "honey: was for science", and she'll say "ok, that makes sense" and you'll be off the hook WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
WildByDesign Posted Monday at 12:37 AM Author Posted Monday at 12:37 AM 16 hours ago, ioa747 said: with sacrifice ? This is a really cool idea. Thanks for sharing. Using fonts for the texture is nice because it's quite easy but also scales very well. 7 hours ago, argumentum said: ...all you need is an 8k monitor. If the wife ask about the expense, you say "honey: was for science", and she'll say "ok, that makes sense" and you'll be off the hook If I ask for that I may be sleeping on the couch. 🙃 I ended up extracting all of the gripper images (PNG) from the aero.msstyles file for each of the resolutions to confirm my initial measurements but also to get the measurements for 200% and higher scaling. Although that makes me wonder now... I wonder if I could just add those PNG images (1 KB each x 8 images) to the compiled binary, load them and place over the same area of the statusbar that we are drawing over with the CreateDots function. I would probably convert them to ICO so that they can be 1 single file with a layer for each DPI scale. argumentum and ioa747 1 1
argumentum Posted Monday at 01:23 AM Posted Monday at 01:23 AM (edited) 23 hours ago, WildByDesign said: Case 2 ; 200% scaling $iDotSize = 4 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] Case Else 8k can easily use 500%. Thinking of after 200% "screw you buddy", ain't nice. As long as odd percentages look good ( 125% & 175% ) in your monitor, it should look the same in greater scaling like 225% All tho, if you could get yourself a 4k monitor ( they are quite inexpensive nowadays compared to some years ago ) it would be good. Edited Monday at 02:36 AM by argumentum English WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
WildByDesign Posted Monday at 12:08 PM Author Posted Monday at 12:08 PM On 1/3/2026 at 10:22 PM, WildByDesign said: $iDPI = Round(_WinAPI_GetDpiForWindow(WinGetHandle(AutoItWinGetTitle())) / 96, 2) I was actually quite proud of myself yesterday for the simple creativity of this line. Getting the DPI from the hidden AutoIt window works well and it is easier to get the handle for it with a small amount of code. This way, you can have the DPI scale before the GUI launches. However, this proved flawed. It worked yesterday. But I noticed today that it was working only about 5-10% of the time. The reason for that is quite simple: The hidden AutoIt window isn't always created yet at that point. I noticed that if I put Sleep(50) above that line, it works every time. But timing changes like that aren't always great because it may not work the same on all hardware. I'm going to fix the DPI stuff today (already have on my machine) and I will finish the CreateDots creation for 200% scaling and higher. Then I will share an updated script later. argumentum 1
WildByDesign Posted Monday at 06:11 PM Author Posted Monday at 06:11 PM (edited) Can anyone with the ability to test at 200% scaling and higher please test something for me? I made it so that the GUI has a button to hide/show the fake sizebox to make it easier to confirm whether the sizebox dot size, spacing and alignment is correct or not. When you hide the fake sizebox, it will show the genuine Windows sizebox/sizegrip for comparison. I have already confirmed 100%, 125%, 150% and 175%. I've added 200%, 250%, 300% and 400% and need those confirmed, if possible. What I've been doing is simply doing a screenshot with the fake sizebox showing and a screenshot of the fake sizebox hidden. Then I put them into an image editing program on two different layers, zoom in and show/hide one of the layers to see whether or not the dot size, spacing and alignment matches. Or if you share the screenshots here, I can compare and make any adjustments to the CreateDots function. Once everything is working right, I should be able to combine many of the lines in the CreateDots function to make it more compact. Thank you! EDIT: I should also mention that the GUI does not react to DPI changes dynamically. So when changing to another DPI scale to test, you will have to close the GUI and run the script again. expandcollapse popup#include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <GuiStatusBar.au3> #include <StaticConstants.au3> #include <WinAPIGdi.au3> #include <WinAPIRes.au3> #include <WinAPISysWin.au3> #include <WinAPITheme.au3> #include <WindowsConstants.au3> Opt("MustDeclareVars", 1) Global $g_hGui, $g_hSizebox, $g_hOldProc, $g_hStatus, $g_iHeight, $g_aText, $g_aRatioW, $g_iBkColor, $g_iTextColor, $g_hDots Global $g_hBrush ; set base DPI scale value and apply DPI Global $idChangeText Global $DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = -2 Global $iDPI = 1 ApplyDPI() Func ApplyDPI() ; apply System DPI awareness and calculate factor _WinAPI_SetThreadDpiAwarenessContext($DPI_AWARENESS_CONTEXT_SYSTEM_AWARE) If Not @error Then $iDPI = Round(_WinAPI_GetDpiForSystem() / 96, 2) If @error Then $iDPI = 1 Else $iDPI = 1 EndIf ; simulate 200% scaling for sizebox ;$iDPI = 2 ConsoleWrite("DPI scale: " & $iDPI & @CRLF) EndFunc Example() ;============================================== Func Example() _GDIPlus_Startup() Local Const $SBS_SIZEBOX = 0x08, $SBS_SIZEGRIP = 0x10 Local $iW = 320 * $iDPI, $iH = 100 * $iDPI Dim $g_iBkColor = _WinAPI_SwitchColor(_WinAPI_GetSysColor($COLOR_BTNFACE)), $g_iTextColor = 0x000000 $g_hGui = GUICreate("Resize corner", $iW, $iH, -1, -1, $WS_OVERLAPPEDWINDOW) GUISetBkColor($g_iBkColor) ;----------------- ; Create a sizebox window (Scrollbar class) BEFORE creating the StatusBar control $g_hSizebox = _WinAPI_CreateWindowEx(0, "Scrollbar", "", $WS_CHILD + $WS_VISIBLE + $SBS_SIZEBOX, _ 0, 0, 0, 0, $g_hGui) ; $SBS_SIZEBOX or $SBS_SIZEGRIP ; Subclass the sizebox (by changing the window procedure associated with the Scrollbar class) Local $hProc = DllCallbackRegister('ScrollbarProc', 'lresult', 'hwnd;uint;wparam;lparam') $g_hOldProc = _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, DllCallbackGetPtr($hProc)) Local $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZENWSE) _WinAPI_SetClassLongEx($g_hSizebox, -12, $hCursor) ; $GCL_HCURSOR = -12 $g_hBrush = _WinAPI_CreateSolidBrush($g_iBkColor) ;----------------- $g_hStatus = _GUICtrlStatusBar_Create($g_hGui, -1, "", $WS_CLIPSIBLINGS) ; ClipSiblings style +++ Local $aParts[3] = [90, 180, -1] If $aParts[Ubound($aParts) - 1] = -1 Then $aParts[Ubound($aParts) - 1] = $iW ; client width size _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts) Dim $g_aText[Ubound($aParts)] = [" ", " ", " "] Dim $g_aRatioW[Ubound($aParts)] For $i = 0 To UBound($g_aText) - 1 _GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW + $SBT_NOBORDERS) $g_aRatioW[$i] = $aParts[$i] / $iW Next $idChangeText = GUICtrlCreateButton("Hide Fake Sizebox", 110 * $iDPI, 25 * $iDPI, -1, -1) ; ensure that sizebox has Explorer theme with gripper dots _WinAPI_SetWindowTheme($g_hStatus, "Explorer") $g_iHeight = _GUICtrlStatusBar_GetHeight($g_hStatus) + 0 ; change the constant (+3) if necessary $g_hDots = CreateDots($g_iHeight, $g_iHeight, 0xFF000000 + $g_iBkColor, 0xFF000000 + $g_iTextColor) GUIRegisterMsg($WM_SIZE, "WM_SIZE") GUIRegisterMsg($WM_MOVE, "WM_MOVE") GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM") ; get rid of the focus rectangle dots on button GUICtrlSendMsg($idChangeText, $WM_CHANGEUISTATE, 65537, 0) ; set title with DPI scaling info WinSetTitle($g_hGui, "", $iDPI * 100 & "% DPI Scale") GUISetState() While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $idChangeText _ShowHideSizebox() EndSwitch WEnd _GDIPlus_BitmapDispose($g_hDots) _GUICtrlStatusBar_Destroy($g_hStatus) _WinAPI_DestroyCursor($hCursor) _WinAPI_DeleteObject($g_hBrush) _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, $g_hOldProc) DllCallbackFree($hProc) _GDIPlus_Shutdown() EndFunc ;==>Example ;============================================== Func ScrollbarProc($hWnd, $iMsg, $wParam, $lParam) ; Andreik If $iMsg = $WM_PAINT Then Local $tPAINTSTRUCT Local $hDC = _WinAPI_BeginPaint($hWnd, $tPAINTSTRUCT) Local $iWidth = DllStructGetData($tPAINTSTRUCT, 'rPaint', 3) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 1) Local $iHeight = DllStructGetData($tPAINTSTRUCT, 'rPaint', 4) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 2) Local $hGraphics = _GDIPlus_GraphicsCreateFromHDC($hDC) _GDIPlus_GraphicsDrawImageRect($hGraphics, $g_hDots, 0, 0, $iWidth, $iHeight) _GDIPlus_GraphicsDispose($hGraphics) _WinAPI_EndPaint($hWnd, $tPAINTSTRUCT) Return 0 EndIf Return _WinAPI_CallWindowProc($g_hOldProc, $hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>ScrollbarProc ;============================================== Func CreateDots($iWidth, $iHeight, $iBackgroundColor, $iDotsColor) ; Andreik Local $iDotSize, $iDotSpace, $iDotFrame Switch $iDPI ; Dot Size Spacing From Right From Bottom Confirmed ; 100% 2 1 2 2 yes ; 125% 3 1 2 2 yes ; 150% 3 1 2 2 yes ; 175% 3 1 2 2 not existing ; 200% 4 2 4 4 ? ; 250% 5 2 5 5 ? ; 300% 6 3 6 6 ? ; 400% 8 4 8 8 ? Case 1 ; 100% scaling $iDotSize = 2 $iDotSpace = $iDotSize - 1 ; ensures that dots have only 1 pixel of space between $iDotFrame = -1 ; controls the distance from frame Local $a[6][2] = [[3,9], [3,6], [3,3], [6,6], [6,3], [9,3]] Case 1.25 ; 125% scaling $iDotSize = 3 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] Case 1.5 ; 150% scaling $iDotSize = 3 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] Case 1.75 ; 175% scaling $iDotSize = 3 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] Case 2 ; 200% scaling $iDotSize = 4 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] Case 2.5 ; 250% scaling $iDotSize = 5 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] Case 3 ; 300% scaling $iDotSize = 6 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] Case 4 ; 400% scaling $iDotSize = 8 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] Case Else $iDotSize = 1 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] EndSwitch Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight) Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap) Local $hBrush = _GDIPlus_BrushCreateSolid($iDotsColor) _GDIPlus_GraphicsClear($hGraphics, $iBackgroundColor) For $i = 0 To UBound($a) - 1 _GDIPlus_GraphicsFillRect($hGraphics, $iWidth - ($iDotSpace * $a[$i][0]) + $iDotFrame, $iHeight - ($iDotSpace * $a[$i][1]) + $iDotFrame, $iDotSize, $iDotSize, $hBrush) Next _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGraphics) Return $hBitmap EndFunc ;==>CreateDots ;============================================== Func _MyGUICtrlStatusBar_SetParts($hWnd, $aPartEdge) ; Pixelsearch If Not IsArray($aPartEdge) Then Return False Local $iParts = UBound($aPartEdge) Local $tParts = DllStructCreate("int[" & $iParts & "]") For $i = 0 To $iParts - 1 DllStructSetData($tParts, 1, $aPartEdge[$i], $i + 1) Next DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", $SB_SETPARTS, "wparam", $iParts, "struct*", $tParts) _GUICtrlStatusBar_Resize($hWnd) Return True EndFunc ;==>_MyGUICtrlStatusBar_SetParts ;============================================== Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) ; Pixelsearch #forceref $iMsg, $wParam, $lParam If $hWnd = $g_hGUI Then Local Static $bIsSizeBoxShown = True Local $aSize = WinGetClientSize($g_hGui) Local $aGetParts = _GUICtrlStatusBar_GetParts($g_hStatus) Local $aParts[$aGetParts[0]] For $i = 0 To $aGetParts[0] - 1 $aParts[$i] = Int($aSize[0] * $g_aRatioW[$i]) Next If BitAND(WinGetState($g_hGui), $WIN_STATE_MAXIMIZED) Then _GUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until GUI right border (AutoIt function forces it) _WinAPI_ShowWindow($g_hSizebox, @SW_HIDE) $bIsSizeBoxShown = False Else If $g_aRatioW[UBound($aParts) -1] <> 1 Then $aParts[UBound($aParts) -1] = $aSize[0] - $g_iHeight ; right size of right part stuck on sizebox (no gap) _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until sizebox (see preceding line) or until GUI right border WinMove($g_hSizebox, "", $aSize[0] - $g_iHeight, $aSize[1] - $g_iHeight, $g_iHeight, $g_iHeight) If Not $bIsSizeBoxShown Then _WinAPI_ShowWindow($g_hSizebox, @SW_SHOW) $bIsSizeBoxShown = True EndIf EndIf EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_SIZE ;============================================== Func WM_MOVE($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $wParam, $lParam If $hWnd = $g_hGUI Then _WinAPI_RedrawWindow($g_hSizebox) EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_MOVE ;============================================== Func WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam) ; Kafu #forceref $hWnd, $iMsg, $wParam Local Static $tagDRAWITEM = "uint CtlType;uint CtlID;uint itemID;uint itemAction;uint itemState;hwnd hwndItem;handle hDC;long rcItem[4];ulong_ptr itemData" Local $tDRAWITEM = DllStructCreate($tagDRAWITEM, $lParam) If $tDRAWITEM.hwndItem <> $g_hStatus Then Return $GUI_RUNDEFMSG ; only process the statusbar Local $itemID = $tDRAWITEM.itemID ; status bar part number : 0 if simple bar (or 0, 1, 2... if multi parts) Local $hDC = $tDRAWITEM.hDC Local $tRect = DllStructCreate("long left;long top;long right;long bottom", DllStructGetPtr($tDRAWITEM, "rcItem")) ;_WinAPI_FillRect($hDC, DllStructGetPtr($tRect), $g_hBrush) ; backgound color _WinAPI_SetTextColor($hDC, $g_iTextColor) ; text color _WinAPI_SetBkMode($hDC, $TRANSPARENT) DllStructSetData($tRect, "top", $tRect.top + 1) DllStructSetData($tRect, "left", $tRect.left + 1) _WinAPI_DrawText($hDC, $g_aText[$itemID], $tRect, $DT_LEFT) Return $GUI_RUNDEFMSG EndFunc ;==>WM_DRAWITEM Func _WinAPI_SetThreadDpiAwarenessContext($DPI_AWARENESS_CONTEXT_value) ; UEZ Local $aResult = DllCall("user32.dll", "uint", "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 Func _WinAPI_GetDpiForSystem() ; UEZ 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 Func _ShowHideSizebox() If _WinAPI_IsWindowVisible ($g_hSizebox) Then _WinAPI_ShowWindow($g_hSizebox, @SW_HIDE) GUICtrlSetData($idChangeText, "Show Fake Sizebox") ElseIf Not _WinAPI_IsWindowVisible ($g_hSizebox) Then _WinAPI_ShowWindow($g_hSizebox, @SW_SHOW) GUICtrlSetData($idChangeText, "Hide Fake Sizebox") EndIf EndFunc Edited Monday at 06:19 PM by WildByDesign
argumentum Posted Monday at 06:49 PM Posted Monday at 06:49 PM 4k at 225% WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
WildByDesign Posted Monday at 09:35 PM Author Posted Monday at 09:35 PM (edited) Case 2 To 2.49 ... Case 2.5 To 2.99 ... Case 3 To ... 2 hours ago, argumentum said: 4k at 225% That looks pretty good. Thanks. I didn’t even realize that there was a 225%. The msstyles file doesn’t have resources for 175% or 225% and likely a few others but probably stretches the closest image resources. I’ll probably need to do something like: EDIT: Ahh. Silly phone always puts the code box at the top. 🙃 Edited Monday at 09:36 PM by WildByDesign argumentum 1
WildByDesign Posted 20 hours ago Author Posted 20 hours ago Alright, here we go. The following example has the following features: Dark mode statusbar with modern theme applied Updated CreateDots function with full DPI support Dot size, spacing and alignment are identical to gripper dots from light mode Explorer theme Gripper dots tested up to 400% DPI scaling Somehow it took me 3 days to complete this. But I am finally satisfied now. 😎 expandcollapse popup#include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <GuiStatusBar.au3> #include <StaticConstants.au3> #include <WinAPIGdi.au3> #include <WinAPIRes.au3> #include <WinAPISysWin.au3> #include <WinAPITheme.au3> #include <WindowsConstants.au3> Opt("MustDeclareVars", 1) Global $g_hGui, $g_hSizebox, $g_hOldProc, $g_hStatus, $g_iHeight, $g_aText, $g_aRatioW, $g_iBkColor, $g_iTextColor, $g_hDots Global $g_hBrush ; set base DPI scale value and apply DPI Global $DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = -2 Global $iDPI = 1 ApplyDPI() Func ApplyDPI() ; apply System DPI awareness and calculate factor _WinAPI_SetThreadDpiAwarenessContext($DPI_AWARENESS_CONTEXT_SYSTEM_AWARE) If Not @error Then $iDPI = Round(_WinAPI_GetDpiForSystem() / 96, 2) If @error Then $iDPI = 1 Else $iDPI = 1 EndIf EndFunc Example() ;============================================== Func Example() _GDIPlus_Startup() Local Const $SBS_SIZEBOX = 0x08, $SBS_SIZEGRIP = 0x10 Local $iW = 320 * $iDPI, $iH = 100 * $iDPI Dim $g_iBkColor = 0x202020, $g_iTextColor = 0xFFFFFF $g_hGui = GUICreate("CreateDots DPI", $iW, $iH, -1, -1, $WS_OVERLAPPEDWINDOW) GUISetBkColor(0x181818) ;----------------- ; Create a sizebox window (Scrollbar class) BEFORE creating the StatusBar control $g_hSizebox = _WinAPI_CreateWindowEx(0, "Scrollbar", "", $WS_CHILD + $WS_VISIBLE + $SBS_SIZEBOX, _ 0, 0, 0, 0, $g_hGui) ; $SBS_SIZEBOX or $SBS_SIZEGRIP ; Subclass the sizebox (by changing the window procedure associated with the Scrollbar class) Local $hProc = DllCallbackRegister('ScrollbarProc', 'lresult', 'hwnd;uint;wparam;lparam') $g_hOldProc = _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, DllCallbackGetPtr($hProc)) Local $hCursor = _WinAPI_LoadCursor(0, $OCR_SIZENWSE) _WinAPI_SetClassLongEx($g_hSizebox, -12, $hCursor) ; $GCL_HCURSOR = -12 $g_hBrush = _WinAPI_CreateSolidBrush($g_iBkColor) ;----------------- $g_hStatus = _GUICtrlStatusBar_Create($g_hGui, -1, "", $WS_CLIPSIBLINGS) ; ClipSiblings style +++ Local $aParts[3] = [90, 180, -1] If $aParts[Ubound($aParts) - 1] = -1 Then $aParts[Ubound($aParts) - 1] = $iW ; client width size _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts) Dim $g_aText[Ubound($aParts)] = ["Part 0", "Part 1", "Part 2"] Dim $g_aRatioW[Ubound($aParts)] For $i = 0 To UBound($g_aText) - 1 _GUICtrlStatusBar_SetText($g_hStatus, "", $i, $SBT_OWNERDRAW + $SBT_NOBORDERS) $g_aRatioW[$i] = $aParts[$i] / $iW Next $g_iHeight = _GUICtrlStatusBar_GetHeight($g_hStatus) + 3 ; change the constant (+3) if necessary $g_hDots = CreateDots($g_iHeight, $g_iHeight, 0xFF000000 + $g_iBkColor, 0xFF000000 + $g_iTextColor) GUIRegisterMsg($WM_SIZE, "WM_SIZE") GUIRegisterMsg($WM_MOVE, "WM_MOVE") GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM") ; apply dark mode to titlebar and statusbar _WinAPI_SetWindowTheme($g_hStatus, "DarkMode", "ExplorerStatusBar") _WinAPI_DwmSetWindowAttribute($g_hGui, $DWMWA_USE_IMMERSIVE_DARK_MODE, True) GUISetState() While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd _GDIPlus_BitmapDispose($g_hDots) _GUICtrlStatusBar_Destroy($g_hStatus) _WinAPI_DestroyCursor($hCursor) _WinAPI_DeleteObject($g_hBrush) _WinAPI_SetWindowLong($g_hSizebox, $GWL_WNDPROC, $g_hOldProc) DllCallbackFree($hProc) _GDIPlus_Shutdown() EndFunc ;==>Example ;============================================== Func ScrollbarProc($hWnd, $iMsg, $wParam, $lParam) ; Andreik If $iMsg = $WM_PAINT Then Local $tPAINTSTRUCT Local $hDC = _WinAPI_BeginPaint($hWnd, $tPAINTSTRUCT) Local $iWidth = DllStructGetData($tPAINTSTRUCT, 'rPaint', 3) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 1) Local $iHeight = DllStructGetData($tPAINTSTRUCT, 'rPaint', 4) - DllStructGetData($tPAINTSTRUCT, 'rPaint', 2) Local $hGraphics = _GDIPlus_GraphicsCreateFromHDC($hDC) _GDIPlus_GraphicsDrawImageRect($hGraphics, $g_hDots, 0, 0, $iWidth, $iHeight) _GDIPlus_GraphicsDispose($hGraphics) _WinAPI_EndPaint($hWnd, $tPAINTSTRUCT) Return 0 EndIf Return _WinAPI_CallWindowProc($g_hOldProc, $hWnd, $iMsg, $wParam, $lParam) EndFunc ;==>ScrollbarProc ;============================================== Func CreateDots($iWidth, $iHeight, $iBackgroundColor, $iDotsColor) ; Andreik Local $iDotSize, $iDotSpace, $iDotFrame Local $iDPIpct = $iDPI * 100 Switch $iDPIpct ; Dot Size Spacing From Right From Bottom Confirmed ; 100% 2 1 2 2 yes ; 125% 3 1 2 2 yes ; 150% 3 1 2 2 yes ; 175% 3 1 2 2 yes ; 200% 4 2 4 4 yes ; 250% 5 2 5 5 yes ; 300% 6 3 6 6 yes ; 400% 8 4 8 8 yes Case 100 $iDotSize = 2 $iDotSpace = $iDotSize - 0.5 ; gives some control over the spacing between dots $iDotFrame = 0.5 ; gives some control over the spacing from frame Case 125 To 175 $iDotSize = 3 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Case 200 To 225 $iDotSize = 4 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 Case 250 To 275 $iDotSize = 5 $iDotSpace = $iDotSize - 1.5 $iDotFrame = 0 Case 300 To 375 $iDotSize = 6 $iDotSpace = $iDotSize - 1.5 $iDotFrame = 1 Case 400 To 500 $iDotSize = 8 $iDotSpace = $iDotSize - 2 $iDotFrame = 2 Case Else $iDotSize = 3 $iDotSpace = $iDotSize - 1 $iDotFrame = 1 EndSwitch Local $a[6][2] = [[3,7], [3,5], [3,3], [5,5], [5,3], [7,3]] Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight) Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap) Local $hBrush = _GDIPlus_BrushCreateSolid($iDotsColor) _GDIPlus_GraphicsClear($hGraphics, $iBackgroundColor) For $i = 0 To UBound($a) - 1 _GDIPlus_GraphicsFillRect($hGraphics, $iWidth - ($iDotSpace * $a[$i][0]) + $iDotFrame, $iHeight - ($iDotSpace * $a[$i][1]) + $iDotFrame, $iDotSize, $iDotSize, $hBrush) Next _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGraphics) Return $hBitmap EndFunc ;==>CreateDots ;============================================== Func _MyGUICtrlStatusBar_SetParts($hWnd, $aPartEdge) ; Pixelsearch If Not IsArray($aPartEdge) Then Return False Local $iParts = UBound($aPartEdge) Local $tParts = DllStructCreate("int[" & $iParts & "]") For $i = 0 To $iParts - 1 DllStructSetData($tParts, 1, $aPartEdge[$i], $i + 1) Next DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", $SB_SETPARTS, "wparam", $iParts, "struct*", $tParts) _GUICtrlStatusBar_Resize($hWnd) Return True EndFunc ;==>_MyGUICtrlStatusBar_SetParts ;============================================== Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) ; Pixelsearch #forceref $iMsg, $wParam, $lParam If $hWnd = $g_hGUI Then Local Static $bIsSizeBoxShown = True Local $aSize = WinGetClientSize($g_hGui) Local $aGetParts = _GUICtrlStatusBar_GetParts($g_hStatus) Local $aParts[$aGetParts[0]] For $i = 0 To $aGetParts[0] - 1 $aParts[$i] = Int($aSize[0] * $g_aRatioW[$i]) Next If BitAND(WinGetState($g_hGui), $WIN_STATE_MAXIMIZED) Then _GUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until GUI right border (AutoIt function forces it) _WinAPI_ShowWindow($g_hSizebox, @SW_HIDE) $bIsSizeBoxShown = False Else If $g_aRatioW[UBound($aParts) -1] <> 1 Then $aParts[UBound($aParts) -1] = $aSize[0] - $g_iHeight ; right size of right part stuck on sizebox (no gap) _MyGUICtrlStatusBar_SetParts($g_hStatus, $aParts) ; set parts until sizebox (see preceding line) or until GUI right border WinMove($g_hSizebox, "", $aSize[0] - $g_iHeight, $aSize[1] - $g_iHeight, $g_iHeight, $g_iHeight) If Not $bIsSizeBoxShown Then _WinAPI_ShowWindow($g_hSizebox, @SW_SHOW) $bIsSizeBoxShown = True EndIf EndIf EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_SIZE ;============================================== Func WM_MOVE($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg, $wParam, $lParam If $hWnd = $g_hGUI Then _WinAPI_RedrawWindow($g_hSizebox) EndIf Return $GUI_RUNDEFMSG EndFunc ;==>WM_MOVE ;============================================== Func WM_DRAWITEM($hWnd, $iMsg, $wParam, $lParam) ; Kafu #forceref $hWnd, $iMsg, $wParam Local Static $tagDRAWITEM = "uint CtlType;uint CtlID;uint itemID;uint itemAction;uint itemState;hwnd hwndItem;handle hDC;long rcItem[4];ulong_ptr itemData" Local $tDRAWITEM = DllStructCreate($tagDRAWITEM, $lParam) If $tDRAWITEM.hwndItem <> $g_hStatus Then Return $GUI_RUNDEFMSG ; only process the statusbar Local $itemID = $tDRAWITEM.itemID ; status bar part number : 0 if simple bar (or 0, 1, 2... if multi parts) Local $hDC = $tDRAWITEM.hDC Local $tRect = DllStructCreate("long left;long top;long right;long bottom", DllStructGetPtr($tDRAWITEM, "rcItem")) _WinAPI_FillRect($hDC, DllStructGetPtr($tRect), $g_hBrush) ; backgound color _WinAPI_SetTextColor($hDC, $g_iTextColor) ; text color _WinAPI_SetBkMode($hDC, $TRANSPARENT) DllStructSetData($tRect, "top", $tRect.top + 1) DllStructSetData($tRect, "left", $tRect.left + 1) _WinAPI_DrawText($hDC, $g_aText[$itemID], $tRect, $DT_LEFT) Return $GUI_RUNDEFMSG EndFunc ;==>WM_DRAWITEM Func _WinAPI_SetThreadDpiAwarenessContext($DPI_AWARENESS_CONTEXT_value) ; UEZ Local $aResult = DllCall("user32.dll", "uint", "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 Func _WinAPI_GetDpiForSystem() ; UEZ 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 ioa747 1
ioa747 Posted 19 hours ago Posted 19 hours ago (edited) a good post, which explains a lot behind the philosophy of common DPI scaling percentages supported by Windows (with useful information in the links) 210543-setting-windows-display-scale-percentage-on-the-fly-without-reboot-or-logout and a little further down you will find "my homework " Edited 19 hours ago by ioa747 WildByDesign 1 I know that I know nothing
WildByDesign Posted 10 hours ago Author Posted 10 hours ago 8 hours ago, ioa747 said: and a little further down you will find "my homework " Very nice, thank you for sharing. I wasn't familiar with the _WinAPI_SystemParametersInfo function before but after reading the msdn page I see how powerful it is. Your DPI_Scaling_Utility is definitely a keeper. I like how you provide GUI and CLI options. ioa747 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