Leaderboard
Popular Content
Showing content with the highest reputation on 06/11/2025 in Posts
-
one more from autohotkey forum: RegisterWaitCallback.ahk by @lexikos https://www.autohotkey.com/boards/viewtopic.php?p=492120#p4921201 point
-
Setting Windows Display Scale Percentage on the Fly without Reboot or Logout
argumentum reacted to ioa747 for a topic
Thank you very much to @Davegbuf for all the useful information he provided us. my homework DPI_Scaling_Utility.au3 ; https://www.autoitscript.com/forum/topic/210543-setting-windows-display-scale-percentage-on-the-fly-without-reboot-or-logout/#findComment-1543707 ;---------------------------------------------------------------------------------------- ; Title...........: DPI_Scaling_Utility.au3 ; Description.....: Setting Windows Display Scale Percentage on the Fly without Reboot or Logout ; if $Command Line argument is provided, the script runs in command-line mode to set DPI. ; else If no arguments are provided, the script runs in GUI mode. ; e.g. Run(@AutoItExe & ' /AutoIt3ExecuteScript "' & @ScriptDir & '\DPI_Scaling_Utility.au3" 100') ; AutoIt Version..: 3.3.16.1 Author: ioa747 Script Version: 1.0 ; Note............: Testet in Win10 22H2 ;---------------------------------------------------------------------------------------- #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=y #include <WinAPISys.au3> #include <GUIConstantsEx.au3> #include <Array.au3> #include <FontConstants.au3> #include <StaticConstants.au3> ; Global array of common DPI scaling percentages supported by Windows. Global $DpiVals[12] = [100, 125, 150, 175, 200, 225, 250, 300, 350, 400, 450, 500] ; Checks if a command-line argument is provided to determine operating mode. If $CmdLine[0] = 1 Then ; If one argument is provided, the script runs in command-line mode to set DPI. _CmdLineMode() Else ; If no arguments are provided, the script runs in GUI mode. Global $g_hGUI Global $g_idRecommendedDPILabel _GUImode() EndIf ;--------------------------------------------------------------------------------------- ; command-line mode to set DPI. Func _CmdLineMode() Local $bSuccess = _SetDpiScaleFromCommandLine($CmdLine[1]) ; Call the function to set DPI. If Not $bSuccess Then _ShowCommandLineSyntaxError() ; Show syntax help if setting failed. Exit(-1) ; Exit with an error code. EndIf Exit(0) ; Exit successfully. EndFunc ;--------------------------------------------------------------------------------------- ; GUI mode, DPI Scaling Utility Func _GuiMode() ; Create the main GUI window. $g_hGUI = GUICreate("DPI Scaling Utility", 220, 300) ; Label to display status messages and results Local $idMessageLabel = GUICtrlCreateLabel("Use the buttons below to get/set DPI settings.", 20, 20, 180, 40, $SS_CENTER) GUICtrlSetFont(-1, 10) ; Label to display the detected system-recommended DPI. $g_idRecommendedDPILabel = GUICtrlCreateLabel("Recommended DPI: Calculating...", 20, 65, 180, 20, $SS_CENTER) GUICtrlSetFont(-1, 9, 700) ; Set bold for emphasis. ; Button to display the current system display scaling percentage. Local $idShowDPIButton = GUICtrlCreateButton("Show Current Display Scaling (%)", 20, 100, 180, 30) ; Label for the DPI selection combo box. GUICtrlCreateLabel("Select Target DPI (%):", 20, 150, 180, 20) ; Combo box for selecting the target DPI percentage. Local $idDPIInput = GUICtrlCreateCombo("", 70, 170, 80, 25) For $i = 0 To UBound($DpiVals) - 1 GUICtrlSetData($idDPIInput, $DpiVals[$i]) Next ; It tries to set it to the current DPI if found in the list, otherwise defaults to 100%. Local $initialCurrentDPI = _GetCurrentDPIPercentage() If _GetDpiArrayIndex($initialCurrentDPI) <> -1 Then GUICtrlSetData($idDPIInput, $initialCurrentDPI) Else GUICtrlSetData($idDPIInput, "100") EndIf ; Button Try to Set DPI. Local $idSetDPIButton = GUICtrlCreateButton("Try to Set DPI", 20, 210, 180, 30) GUISetState(@SW_SHOW) ; Calculate and display the recommended DPI _UpdateRecommendedDPI() While True Local $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE ExitLoop Case $idShowDPIButton ; "Show Current Display Scaling" button. Local $currentDPIPercentage = _GetCurrentDPIPercentage() ; Get current system DPI. If $currentDPIPercentage > 0 Then GUICtrlSetData($idMessageLabel, "Current system scaling: " & $currentDPIPercentage & "%") Else GUICtrlSetData($idMessageLabel, "Error: Could not retrieve current DPI scaling.") EndIf _UpdateRecommendedDPI() ; update the recommended DPI label. Case $idSetDPIButton ; "Try to Set DPI" button. Local $dpiToSetString = GUICtrlRead($idDPIInput) Local $dpiToSetNumber = Number($dpiToSetString) If @error = 0 Then ; Attempt to set the DPI scaling using the shared logic function. Local $bSetSuccess = _SetDpiScaleLogic($dpiToSetNumber) If $bSetSuccess Then GUICtrlSetData($idMessageLabel, "Attempted to set DPI to " & $dpiToSetNumber & "%.") _UpdateRecommendedDPI() ; Update recommended DPI after a successful setting attempt. Else GUICtrlSetData($idMessageLabel, "Failed to set DPI to " & $dpiToSetNumber & "%. See console for details.") EndIf Else GUICtrlSetData($idMessageLabel, "Error: Failed to convert selected value to a number. Value read: '" & $dpiToSetString & "'") EndIf EndSwitch WEnd EndFunc ;--------------------------------------------------------------------------------------- ; Displays the syntax usage for the command-line mode in a MsgBox. Func _ShowCommandLineSyntaxError() MsgBox(16, 'Syntax Error', _ 'Syntax:' & @CRLF & @CRLF & _ 'YourScriptName.exe [percentage_value]' & @CRLF & @CRLF & _ ' [percentage_value]: The desired display scaling percentage.' & @CRLF & _ ' Examples: "100", "125", "150", "175", "200", etc.' & @CRLF & _ ' (You can optionally include the "%" sign, e.g., "125%")' & @CRLF & @CRLF & _ ' Special Value:' & @CRLF & _ ' "0": Sets the display scale to the system''s recommended DPI.' & @CRLF & @CRLF & _ 'Example 1 - Set scale to 125% : ' & @CRLF & _ ' YourScriptName.exe 125' & @CRLF & @CRLF & _ 'Example 2 - Set scale to 150% : ' & @CRLF & _ ' YourScriptName.exe 150%' & @CRLF & @CRLF & _ 'Example 3 - Set scale to Recommended DPI : ' & @CRLF & _ ' YourScriptName.exe 0', 60) EndFunc ;--------------------------------------------------------------------------------------- ; Function to set the DPI scale when called from the command line. Func _SetDpiScaleFromCommandLine($sTargetScale) Local $iTargetPercentage ; Clean the input string (remove '%' if present) $sTargetScale = StringReplace($sTargetScale, "%", "") ; Ensuring the input is an integer string. If Not StringIsInt($sTargetScale) Then ConsoleWrite("Error: Invalid input format for target scale: '" & $sTargetScale & "'. Expected an integer." & @CRLF) Return SetError(-1, 0, False) EndIf $iTargetPercentage = Number($sTargetScale) ; Convert the validated string to a number. ; If the target argument is 0, interpret it as a request for the system's recommended DPI. If $iTargetPercentage = 0 Then Local $iRecommendedPercentage = _GetSystemRecommendedDPIPercentage() If $iRecommendedPercentage = -1 Then ConsoleWrite("Error: Cannot determine recommended DPI." & @CRLF) Return SetError(-3, 0, False) ; Error if recommended DPI cannot be found. EndIf $iTargetPercentage = $iRecommendedPercentage ; Set the target percentage to the recommended value. EndIf ; Validate if the target percentage is one of the predefined DPI scales. If _GetDpiArrayIndex($iTargetPercentage) = -1 Then ConsoleWrite("Error: Target percentage " & $iTargetPercentage & "% is not a valid predefined DPI scale." & @CRLF) Return SetError(-2, 0, False) EndIf Return _SetDpiScaleLogic($iTargetPercentage) ; Call the shared core logic to set DPI. EndFunc ;--------------------------------------------------------------------------------------- ; --- Shared Core DPI Setting Logic --- ; function to calculates the correct relative index needed by the Windows API ; based on the system's detected "recommended" DPI and the desired target percentage. Func _SetDpiScaleLogic($percentScaleToSet) ; First, determine the system's recommended DPI percentage. Local $iRecommendedPercentage = _GetSystemRecommendedDPIPercentage() If $iRecommendedPercentage = -1 Then ConsoleWrite("Error: Cannot determine recommended DPI to set scaling relatively." & @CRLF) Return SetError(-6, 0, False) ; Error if recommended DPI cannot be found. EndIf ; Get the absolute array indices for the recommended and target DPIs from $DpiVals. Local $iRecommendedAbsIndex = _GetDpiArrayIndex($iRecommendedPercentage) Local $iTargetAbsIndex = _GetDpiArrayIndex($percentScaleToSet) ; Validate that both recommended and target DPIs are found in our predefined list. If $iRecommendedAbsIndex = -1 Then ConsoleWrite("Error: Recommended DPI (" & $iRecommendedPercentage & "%) not found in predefined list ($DpiVals)." & @CRLF) Return SetError(-7, 0, False) EndIf If $iTargetAbsIndex = -1 Then ConsoleWrite("Error: Target DPI (" & $percentScaleToSet & "%) not found in predefined list ($DpiVals)." & @CRLF) Return SetError(-8, 0, False) EndIf ; Calculate the relative index to pass to SystemParametersInfo. ; This is the crucial part based on the empirical observation that ; the API uses a relative step from the recommended DPI. Local $iFinalRelativeIndexToPass = $iTargetAbsIndex - $iRecommendedAbsIndex ; Log the parameters being used for the DPI setting attempt. ConsoleWrite("Attempting to set DPI:" & @CRLF & _ " Target Percentage: " & $percentScaleToSet & "%" & @CRLF & _ " Recommended Percentage: " & $iRecommendedPercentage & "%" & @CRLF & _ " Relative Index to Pass to API: " & $iFinalRelativeIndexToPass & @CRLF) ; Perform the actual Windows API call to set the display scaling. ; 0x009F corresponds to SPI_SETLOGICALDPIOVERRIDE (or SPI_SETLOGICALDPIAWARENESS). ; 0x0001 (SPIF_UPDATEINIFILE) ensures the setting is written to the user profile, making it persistent. Local $bSuccess = _WinAPI_SystemParametersInfo(0x009F, $iFinalRelativeIndexToPass, Null, 0x0001) ; Log API call failure if it occurs. If Not $bSuccess Then ConsoleWrite("API call _WinAPI_SystemParametersInfo(0x009F, " & $iFinalRelativeIndexToPass & ", ...) failed. @error=" & @error & ", @extended=" & @extended & @CRLF) EndIf Return SetError(@error, @extended, $bSuccess) ; Return success/failure status. EndFunc ;--------------------------------------------------------------------------------------- ; Function to find the array index of a given DPI percentage within the $DpiVals array. ; Returns -1 if the percentage is not found. Func _GetDpiArrayIndex($percentage) Return _ArraySearch($DpiVals, $percentage) EndFunc ;--------------------------------------------------------------------------------------- ; Function to get the current system-wide DPI in pixels per inch. ; (e.g., 96 for 100% scaling, 120 for 125% scaling). Func _GetCurrentSystemDPI() Local $hDC = _WinAPI_GetDC(0) ; Get device context for the entire screen (desktop). If $hDC = 0 Then ConsoleWrite("Error: _GetCurrentSystemDPI failed to get DC." & @CRLF) Return -1 ; Return -1 on error if DC cannot be obtained. EndIf ; LOGPIXELSX (88) retrieves the number of pixels per logical inch along the screen width. Local $iLogicalDPI = _WinAPI_GetDeviceCaps($hDC, $LOGPIXELSX) _WinAPI_ReleaseDC(0, $hDC) ; Release the device context to free up resources. Return $iLogicalDPI EndFunc ;--------------------------------------------------------------------------------------- ; Function to get the current display scaling percentage. ; Assumes that 96 DPI equals 100% scaling, which is the standard baseline for Windows. Func _GetCurrentDPIPercentage() Local $currentDPI = _GetCurrentSystemDPI() If $currentDPI = -1 Then Return -1 ; Error if DPI could not be retrieved by _GetCurrentSystemDPI. EndIf ; Calculate the percentage: (CurrentDPI / 96) * 100. Return Round(($currentDPI / 96) * 100) EndFunc ;--------------------------------------------------------------------------------------- ; Function to get the current relative DPI index (0 for recommended, 1 for next step up, etc.). ; This directly queries the value that corresponds to the second parameter of SPI_SETLOGICALDPIOVERRIDE. Func _GetRelativeCurrentDPIIndex() Local $relativeDPIIndex = 0 ; This variable will hold the relative index (0, 1, -1, etc.). ; SPI_GETLOGICALDPIAWARENESS (0x009F) when used to GET (uiParam=0), reads the current relative index into pvParam. Local $retval = _WinAPI_SystemParametersInfo(0x009F, 0, $relativeDPIIndex, 0) If $retval Then Return $relativeDPIIndex Else ConsoleWrite("Error: _GetRelativeCurrentDPIIndex failed to retrieve value. Return value: " & $retval & @CRLF) Return -9999 ; Sentinel value for error. EndIf EndFunc ;--------------------------------------------------------------------------------------- ; Function to determine the OS's recommended DPI percentage for the current display. ; This calculates the absolute percentage that corresponds to the relative index 0. Func _GetSystemRecommendedDPIPercentage() Local $currentActualPercentage = _GetCurrentDPIPercentage() If $currentActualPercentage = -1 Then Return -1 ; Return error if current percentage cannot be obtained. Local $currentRelativeIndex = _GetRelativeCurrentDPIIndex() If $currentRelativeIndex = -9999 Then Return -1 ; Return error if relative index cannot be obtained. Local $currentAbsIndexInArray = _GetDpiArrayIndex($currentActualPercentage) If $currentAbsIndexInArray = -1 Then ConsoleWrite("Warning: Current DPI percentage (" & $currentActualPercentage & "%) not found in DpiVals array. Cannot reliably determine recommended DPI." & @CRLF) ; If the current actual percentage isn't in our predefined list, we can't reliably calculate the recommended one. Return -1 EndIf ; The index of the recommended DPI in our array is the current absolute index ; minus the current relative index. Local $recommendedAbsIndexInArray = $currentAbsIndexInArray - $currentRelativeIndex ; Ensure the calculated index is within the valid bounds of the $DpiVals array. If $recommendedAbsIndexInArray < 0 Or $recommendedAbsIndexInArray >= UBound($DpiVals) Then ConsoleWrite("Error: Calculated recommended DPI index (" & $recommendedAbsIndexInArray & ") is out of bounds for DpiVals array. Cannot determine recommended DPI. This might mean the current DPI is not a standard step." & @CRLF) Return -1 EndIf Return $DpiVals[$recommendedAbsIndexInArray] ; Return the recommended DPI percentage. EndFunc ;--------------------------------------------------------------------------------------- ; function to update the recommended DPI label on the GUI. Func _UpdateRecommendedDPI() ; Only update GUI controls if the GUI window has been successfully created. If IsHWnd($g_hGUI) Then Local $recommendedDPI = _GetSystemRecommendedDPIPercentage() If $recommendedDPI > 0 Then GUICtrlSetData($g_idRecommendedDPILabel, "Recommended DPI: " & $recommendedDPI & "%") Else GUICtrlSetData($g_idRecommendedDPILabel, "Recommended DPI: N/A (Error or not in list)") EndIf EndIf EndFunc ;--------------------------------------------------------------------------------------- Added: if $CmdLine argument is provided, the script runs in command-line mode to set DPI. else If no $CmdLine arguments are provided, the script runs in GUI mode. ; e.g. Run(@AutoItExe & ' /AutoIt3ExecuteScript "' & @ScriptDir & '\DPI_Scaling_Utility.au3" 100') If the $CmdLine argument is Special Value: "0" then sets the display scale to the system''s recommended DPI. Edit: Add more info with the power of SciTE AI Assistant1 point