-
Posts
7,542 -
Joined
-
Last visited
-
Days Won
98
UEZ last won the day on August 13
UEZ had the most liked content!
About UEZ

- Birthday 12/03/2007
Profile Information
-
Member Title
Never say never
-
Location
Germany
-
Interests
Computer, watching movies, football (soccer), being lazy :-)
UEZ's Achievements
-
UEZ reacted to a post in a topic:
BrainBake DSP
-
Danyfirex reacted to a post in a topic:
_WinAPI_DPI UDF build 2026-08-26 beta
-
bladem2003 reacted to a post in a topic:
_WinAPI_DPI UDF build 2026-08-26 beta
-
ioa747 reacted to a post in a topic:
_WinAPI_DPI UDF build 2026-08-26 beta
-
mutleey reacted to a post in a topic:
_WinAPI_DPI UDF build 2026-08-26 beta
-
funkey reacted to a post in a topic:
_WinAPI_DPI UDF build 2026-08-26 beta
-
I think the _WinAPI_DPI UDF is now complete enough to be released here. ;Coded by UEZ build 2026-08-26 beta #include-once #include <GDIPlus.au3> #include <StructureConstants.au3> #include <WinAPIGdi.au3> #include <WinAPISysWin.au3> #include <WinAPIsysinfoConstants.au3> ;$SM_* constants for _WinAPI_GetSystemMetricsForDpi #Region DPI Constants ;https://learn.microsoft.com/en-us/windows/win32/api/windef/ne-windef-dpi_awareness Global Enum $DPI_AWARENESS_INVALID = -1, $DPI_AWARENESS_UNAWARE = 0, $DPI_AWARENESS_SYSTEM_AWARE = 1, $DPI_AWARENESS_PER_MONITOR_AWARE = 2 ;https://learn.microsoft.com/en-us/windows/win32/hidpi/dpi-awareness-context ;These are pseudo-handles: formally pointers (DECLARE_HANDLE), but the values -1..-5 are ;sentinels the API maps internally. Never dereference them. Kept as plain literals on ;purpose - deriving them from the DPI_AWARENESS enum couples two unrelated enumerations. Global Const $DPI_AWARENESS_CONTEXT_UNAWARE = -1 Global Const $DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = -2 Global Const $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = -3 Global Const $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = -4 Global Const $DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED = -5 ;Unified awareness levels for _WinAPI_SetDPIAwareness (version independent). ;Note the ordering is NOT "increasing awareness": GDISCALED is a variant of UNAWARE and ;deliberately sits last, so never clamp an out-of-range value to it. Global Enum $DPI_LEVEL_UNAWARE = 0, $DPI_LEVEL_SYSTEM, $DPI_LEVEL_PER_MONITOR, $DPI_LEVEL_PER_MONITOR_V2, $DPI_LEVEL_UNAWARE_GDISCALED ;Scope for _WinAPI_SetDPIAwareness Global Enum $DPI_SCOPE_PROCESS = 1, $DPI_SCOPE_THREAD = 2 ;enum PROCESS_DPI_AWARENESS (shellscalingapi.h) Global Enum $PROCESS_DPI_UNAWARE = 0, $PROCESS_SYSTEM_DPI_AWARE, $PROCESS_PER_MONITOR_DPI_AWARE ;enum _MONITOR_DPI_TYPE Global Enum $MDT_EFFECTIVE_DPI = 0, $MDT_ANGULAR_DPI, $MDT_RAW_DPI Global Const $MDT_DEFAULT = $MDT_EFFECTIVE_DPI ;Cursor creation scaling (winuser.h, guarded by NTDDI_WIN10_CO = Windows 11 21H2) Global Const $CURSOR_CREATION_SCALING_NONE = 1 Global Const $CURSOR_CREATION_SCALING_DEFAULT = 2 ;enum DPI_HOSTING_BEHAVIOR (Win10 1803+) - controls whether a window may host child windows ;with a different DPI awareness. MIXED is needed for legacy controls inside a modern window. Global Enum $DPI_HOSTING_BEHAVIOR_INVALID = -1, $DPI_HOSTING_BEHAVIOR_DEFAULT = 0, $DPI_HOSTING_BEHAVIOR_MIXED = 1 ;Windows Message Codes Global Const $WM_DPICHANGED = 0x02E0, $WM_DPICHANGED_BEFOREPARENT = 0x02E2, $WM_DPICHANGED_AFTERPARENT = 0x02E3, $WM_GETDPISCALEDSIZE = 0x02E4 ;DpiChangeBehavior Global Const $DDC_DEFAULT = 0 Global Const $DDC_DISABLE_ALL = 1 Global Const $DDC_DISABLE_RESIZE = 2 Global Const $DDC_DISABLE_CONTROL_RELAYOUT = 4 Global Const $DCDC_DEFAULT = 0 Global Const $DCDC_DISABLE_FONT_UPDATE = 1 Global Const $DCDC_DISABLE_RELAYOUT = 2 ;Internal: OS build thresholds. @OSBuild is compared against these instead of using ;hand-written Case ranges, which is where the original version left a gap. Global Const $__DPI_BUILD_VISTA = 6000 ;SetProcessDPIAware Global Const $__DPI_BUILD_WIN81 = 9600 ;SetProcessDpiAwareness, GetDpiForMonitor Global Const $__DPI_BUILD_1607 = 14393 ;SetThreadDpiAwarenessContext, GetDpiForSystem, SetProcessDpiAwarenessContext Global Const $__DPI_BUILD_1703 = 15063 ;PER_MONITOR_AWARE_V2 context value Global Const $__DPI_BUILD_1803 = 17134 ;GetDpiFromDpiAwarenessContext, InheritWindowMonitor Global Const $__DPI_BUILD_1809 = 17763 ;UNAWARE_GDISCALED Global Const $__DPI_ERROR_ACCESS_DENIED = 5 ;Win32 ERROR_ACCESS_DENIED Global Const $__DPI_E_ACCESSDENIED = 0x80070005 ;HRESULT E_ACCESSDENIED Global Const $__DPI_DEFAULT_DPI = 96 ;USER_DEFAULT_SCREEN_DPI #EndRegion DPI Constants #Region Internal helpers ;Reads the thread's last Win32 error. Must be called immediately after the DllCall whose ;failure reason is wanted - any intervening call may overwrite it. Func __WinAPI_DPI_GetLastError() Local $aResult = DllCall("kernel32.dll", "dword", "GetLastError") If @error Or Not IsArray($aResult) Then Return 0 Return $aResult[0] EndFunc ;==>__WinAPI_DPI_GetLastError ;Best available way of reading the current DPI, degrading with the OS version. ;Returns 0 if nothing worked. Func __WinAPI_DPI_QueryCurrent() Local $iDPI = 0 If @OSBuild >= $__DPI_BUILD_1607 Then $iDPI = _WinAPI_GetDpiForSystem() If @error Then $iDPI = 0 EndIf If Not $iDPI And @OSBuild >= $__DPI_BUILD_WIN81 Then $iDPI = _WinAPI_GetDpiForMonitor() If @error Then $iDPI = 0 EndIf If Not $iDPI Then $iDPI = _WinAPI_GetDPI() ;GetDeviceCaps fallback, works on every version If @error Then $iDPI = 0 EndIf Return $iDPI EndFunc ;==>__WinAPI_DPI_QueryCurrent ;Maps a unified level (0..4) to its DPI_AWARENESS_CONTEXT pseudo-handle. ;Every level is listed explicitly. Anything unexpected falls back to PER_MONITOR_AWARE_V2 and ;never to GDISCALED - an unknown value must not silently end up in an unaware mode. Func __WinAPI_DPI_LevelToContext($iLevel) Switch $iLevel Case $DPI_LEVEL_UNAWARE Return $DPI_AWARENESS_CONTEXT_UNAWARE Case $DPI_LEVEL_SYSTEM Return $DPI_AWARENESS_CONTEXT_SYSTEM_AWARE Case $DPI_LEVEL_PER_MONITOR Return $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE Case $DPI_LEVEL_UNAWARE_GDISCALED Return $DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED Case Else Return $DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 EndSwitch EndFunc ;==>__WinAPI_DPI_LevelToContext ;Folds a unified level onto the three PROCESS_DPI_AWARENESS values. GDISCALED is a variant of ;UNAWARE and V2 a variant of PER_MONITOR, so both collapse onto their base level. Func __WinAPI_DPI_LevelToCoarse($iLevel) Switch $iLevel Case $DPI_LEVEL_SYSTEM Return $PROCESS_SYSTEM_DPI_AWARE Case $DPI_LEVEL_PER_MONITOR, $DPI_LEVEL_PER_MONITOR_V2 Return $PROCESS_PER_MONITOR_DPI_AWARE Case Else ;UNAWARE and UNAWARE_GDISCALED Return $PROCESS_DPI_UNAWARE EndSwitch EndFunc ;==>__WinAPI_DPI_LevelToCoarse ;Determines the DPI awareness level (0..4) that is in effect for the CALLING THREAD - which is ;the process default as long as the thread has not overridden it. There is no way around that ;restriction: asked about its own process, Windows answers with the calling thread's context, ;GetDpiAwarenessContextForProcess and GetProcessDpiAwareness included, no matter whether the ;process handle is NULL or a real one. Use the result accordingly and never as proof about ;another thread. ;Returns -1 when the level cannot be determined - that means "unknown", not "mismatch". ;@extended tells how precise the answer is: 0 = exact, 1 = PROCESS_DPI_AWARENESS granularity, ;where PER_MONITOR and V2 are indistinguishable and GDISCALED reads as UNAWARE. Compare such a ;value with __WinAPI_DPI_LevelSatisfies() instead of testing it for equality. Func __WinAPI_DPI_GetActiveLevel() Local $iContext = 0, $iLevel = 0, $iAwareness = 0 If @OSBuild >= $__DPI_BUILD_1607 Then $iContext = _WinAPI_GetThreadDpiAwarenessContext() If Not @error And $iContext Then ;The context is an opaque handle, so ask the API which of the known levels it equals For $iLevel = $DPI_LEVEL_UNAWARE To $DPI_LEVEL_UNAWARE_GDISCALED If _WinAPI_AreDpiAwarenessContextsEqual($iContext, __WinAPI_DPI_LevelToContext($iLevel)) Then Return SetError(0, 0, $iLevel) Next ;Unknown context - fall back to the coarse DPI_AWARENESS value (0..2) $iAwareness = _WinAPI_GetAwarenessFromDpiAwarenessContext($iContext) If Not @error And $iAwareness <> $DPI_AWARENESS_INVALID Then Return SetError(0, 1, $iAwareness) EndIf EndIf If @OSBuild >= $__DPI_BUILD_WIN81 Then $iAwareness = _WinAPI_GetProcessDpiAwareness() If Not @error Then Return SetError(0, 1, $iAwareness) ;PROCESS_DPI_AWARENESS 0..2 EndIf If @OSBuild >= $__DPI_BUILD_VISTA Then ;Vista..Win8 know system awareness only $iAwareness = _WinAPI_IsProcessDPIAware() If Not @error Then Return SetError(0, 1, ($iAwareness ? $DPI_LEVEL_SYSTEM : $DPI_LEVEL_UNAWARE)) EndIf Return SetError(0, 0, -1) EndFunc ;==>__WinAPI_DPI_GetActiveLevel ;Decides whether the level that is really active satisfies the request. $bCoarse is the ;precision flag of __WinAPI_DPI_GetActiveLevel(): on that granularity both sides have to be ;folded down first, otherwise a correctly applied V2 would be reported as a mismatch. ;An undetermined level (-1) counts as satisfied - guessing would only produce false alarms. Func __WinAPI_DPI_LevelSatisfies($iActiveLevel, $bCoarse, $iRequestedLevel) If $iActiveLevel = -1 Then Return True If Not $bCoarse Then Return ($iActiveLevel = $iRequestedLevel) Return (__WinAPI_DPI_LevelToCoarse($iActiveLevel) = __WinAPI_DPI_LevelToCoarse($iRequestedLevel)) EndFunc ;==>__WinAPI_DPI_LevelSatisfies #EndRegion Internal helpers #Region WinAPI DPI - queries ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-adjustwindowrectexfordpi ;The API expands an existing client RECT into a window RECT, so the rectangle is an input. ;Passing all four coordinates as 0 yields the pure frame offsets (left/top become negative). ;Returns: $tagRECT structure. @error 1 = call failed (@extended = @error), 2 = API returned FALSE. Func _WinAPI_AdjustWindowRectExForDpi($iDpi, $dwStyle, $dwExStyle = 0, $bMenu = False, $iLeft = 0, $iTop = 0, $iRight = 0, $iBottom = 0) Local $tRECT = DllStructCreate($tagRECT) $tRECT.Left = $iLeft $tRECT.Top = $iTop $tRECT.Right = $iRight $tRECT.Bottom = $iBottom ;Parameter order per MSDN: lpRect, dwStyle, bMenu, dwExStyle, dpi Local $aResult = DllCall("user32.dll", "bool", "AdjustWindowRectExForDpi", "struct*", $tRECT, "dword", $dwStyle, "bool", $bMenu, "dword", $dwExStyle, "uint", $iDpi) ;Win10 1607+ / no server support If @error Or Not IsArray($aResult) Then Return SetError(1, @error, 0) If Not $aResult[0] Then Return SetError(2, __WinAPI_DPI_GetLastError(), 0) Return $tRECT EndFunc ;==>_WinAPI_AdjustWindowRectExForDpi ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfofordpi ;$pvParam must be a DllStruct (or pointer) matching the requested $uiAction. Func _WinAPI_SystemParametersInfoForDpi($uiAction, $uiParam, $pvParam, $fWinIni, $iDpi) Local $aResult = DllCall("user32.dll", "bool", "SystemParametersInfoForDpi", "uint", $uiAction, "uint", $uiParam, "struct*", $pvParam, "uint", $fWinIni, "uint", $iDpi) ;Win10 1607+ / no server support If @error Or Not IsArray($aResult) Then Return SetError(1, @error, 0) If Not $aResult[0] Then Return SetError(2, __WinAPI_DPI_GetLastError(), 0) Return True EndFunc ;==>_WinAPI_SystemParametersInfoForDpi ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-inheritwindowmonitor Func _WinAPI_InheritWindowMonitor($hWnd, $hWndInherit) Local $aResult = DllCall("user32.dll", "bool", "InheritWindowMonitor", "hwnd", $hWnd, "hwnd", $hWndInherit) ;Win10 1803+ / Windows Server 2016+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, 0) If Not $aResult[0] Then Return SetError(2, __WinAPI_DPI_GetLastError(), 0) Return True EndFunc ;==>_WinAPI_InheritWindowMonitor ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-isvaliddpiawarenesscontext ;A result of False means "this context is not valid" - that is an answer, not an error. ;@error is only set when the call itself could not be made. Func _WinAPI_IsValidDpiAwarenessContext($iContext) Local $aResult = DllCall("user32.dll", "bool", "IsValidDpiAwarenessContext", "int_ptr", $iContext) ;Win10 1607+ / no server support If @error Or Not IsArray($aResult) Then Return SetError(1, @error, False) Return ($aResult[0] <> 0) EndFunc ;==>_WinAPI_IsValidDpiAwarenessContext ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-logicaltophysicalpointforpermonitordpi Func _WinAPI_LogicalToPhysicalPointForPerMonitorDPI($hWnd, $iX, $iY) Local $tPOINT = DllStructCreate($tagPOINT) $tPOINT.x = $iX $tPOINT.y = $iY Local $aResult = DllCall("user32.dll", "bool", "LogicalToPhysicalPointForPerMonitorDPI", "hwnd", $hWnd, "struct*", $tPOINT) ;Win8.1+ / no server support If @error Or Not IsArray($aResult) Then Return SetError(1, @error, 0) If Not $aResult[0] Then Return SetError(2, __WinAPI_DPI_GetLastError(), 0) Return $tPOINT EndFunc ;==>_WinAPI_LogicalToPhysicalPointForPerMonitorDPI ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-physicaltologicalpointforpermonitordpi Func _WinAPI_PhysicalToLogicalPointForPerMonitorDPI($hWnd, $iX, $iY) Local $tPOINT = DllStructCreate($tagPOINT) $tPOINT.x = $iX $tPOINT.y = $iY Local $aResult = DllCall("user32.dll", "bool", "PhysicalToLogicalPointForPerMonitorDPI", "hwnd", $hWnd, "struct*", $tPOINT) ;Win8.1+ / no server support If @error Or Not IsArray($aResult) Then Return SetError(1, @error, 0) If Not $aResult[0] Then Return SetError(2, __WinAPI_DPI_GetLastError(), 0) Return $tPOINT EndFunc ;==>_WinAPI_PhysicalToLogicalPointForPerMonitorDPI ;GDI+ based DPI of a window (0 = desktop). Requires _GDIPlus_Startup beforehand. Func _GDIPlus_GetDPI($hGUI = 0) Local $hGfx = _GDIPlus_GraphicsCreateFromHWND($hGUI) If @error Then Return SetError(1, @error, 0) Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipGetDpiX", "handle", $hGfx, "float*", 0) Local $iErr = @error _GDIPlus_GraphicsDispose($hGfx) ;always dispose, even on failure - the original leaked here If $iErr Or Not IsArray($aResult) Then Return SetError(2, $iErr, 0) If $aResult[0] Then Return SetError(3, $aResult[0], 0) ;GDI+ status, 0 = Ok Return $aResult[2] EndFunc ;==>_GDIPlus_GetDPI ;GetDeviceCaps based DPI. Works on every Windows version, but returns a virtualised value ;when the calling thread is DPI unaware. Func _WinAPI_GetDPI($hWnd = 0) If Not $hWnd Then $hWnd = _WinAPI_GetDesktopWindow() Local Const $hDC = _WinAPI_GetDC($hWnd) If @error Or Not $hDC Then Return SetError(1, 0, 0) Local Const $iDPI = _WinAPI_GetDeviceCaps($hDC, $LOGPIXELSX) Local Const $iErr = @error _WinAPI_ReleaseDC($hWnd, $hDC) If $iErr Or Not $iDPI Then Return SetError(2, $iErr, 0) Return $iDPI EndFunc ;==>_WinAPI_GetDPI ;https://learn.microsoft.com/en-us/windows/win32/api/shellscalingapi/nf-shellscalingapi-getdpiformonitor ;$hMonitor = 0 auto-selects the primary monitor. ;$bBothAxes = True returns a 2-element array [dpiX, dpiY] instead of dpiX only. Func _WinAPI_GetDpiForMonitor($hMonitor = 0, $iDpiType = $MDT_DEFAULT, $bBothAxes = False) If Not $hMonitor Then Local $aMonitors = _WinAPI_EnumDisplayMonitors() If @error Or Not IsArray($aMonitors) Then Return SetError(1, @error, 0) Local $aMI For $i = 1 To $aMonitors[0][0] $aMI = _WinAPI_GetMonitorInfo($aMonitors[$i][0]) If @error Or Not IsArray($aMI) Then ContinueLoop ;_WinAPI_GetMonitorInfo already reduces the MONITORINFO flags to 0 or 1 in $aMI[2], ;BitAND keeps working should that ever change back to the raw flag field If BitAND($aMI[2], 1) Then ;MONITORINFOF_PRIMARY $hMonitor = $aMonitors[$i][0] ExitLoop EndIf Next If Not $hMonitor Then Return SetError(2, 0, 0) ;no primary monitor found EndIf Local $tDpiX = DllStructCreate("uint dpiX") Local $tDpiY = DllStructCreate("uint dpiY") Local $aResult = DllCall("Shcore.dll", "long", "GetDpiForMonitor", _ ;Win8.1+ "handle", $hMonitor, _ "long", $iDpiType, _ "struct*", $tDpiX, _ "struct*", $tDpiY) If @error Or Not IsArray($aResult) Then Return SetError(3, @error, 0) If $aResult[0] <> 0 Then Return SetError(4, $aResult[0], 0) ;HRESULT check If Not $bBothAxes Then Return $tDpiX.dpiX Local $aReturn[2] = [$tDpiX.dpiX, $tDpiY.dpiY] Return $aReturn EndFunc ;==>_WinAPI_GetDpiForMonitor ;Kept for source compatibility - always returns a 2 element array [dpiX, dpiY], on failure ;filled with 0 so that a caller indexing the result does not run into a subscript error. Func _WinAPI_GetDpiForMonitor2($hMonitor, $iDpiType = $MDT_EFFECTIVE_DPI) Local $aReturn = _WinAPI_GetDpiForMonitor($hMonitor, $iDpiType, True) Local Const $iErr = @error, $iExt = @extended If $iErr Or Not IsArray($aReturn) Then Local $aEmpty[2] = [0, 0] Return SetError($iErr, $iExt, $aEmpty) EndIf Return SetError(0, $iExt, $aReturn) EndFunc ;==>_WinAPI_GetDpiForMonitor2 ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpiforwindow Func _WinAPI_GetDpiForWindow($hWnd) Local $aResult = DllCall("user32.dll", "uint", "GetDpiForWindow", "hwnd", $hWnd) ;Win10 1607+ / no server support If @error Or Not IsArray($aResult) Then Return SetError(1, @error, 0) If Not $aResult[0] Then Return SetError(2, 0, 0) ;0 = invalid hwnd Return $aResult[0] EndFunc ;==>_WinAPI_GetDpiForWindow ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpiforsystem Func _WinAPI_GetDpiForSystem() Local $aResult = DllCall("user32.dll", "uint", "GetDpiForSystem") ;Win10 1607+ / no server support If @error Or Not IsArray($aResult) Then Return SetError(1, @error, 0) If Not $aResult[0] Then Return SetError(2, 0, 0) Return $aResult[0] EndFunc ;==>_WinAPI_GetDpiForSystem ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getthreaddpiawarenesscontext ;The returned handle is opaque: depending on the build it can be a real pointer or one of the ;-1..-5 pseudo-handles. Never compare it with the DPI_AWARENESS_CONTEXT_* constants directly, ;always use _WinAPI_AreDpiAwarenessContextsEqual. Func _WinAPI_GetThreadDpiAwarenessContext() Local $aResult = DllCall("user32.dll", "int_ptr", "GetThreadDpiAwarenessContext") ;Win10 1607+ / no server support If @error Or Not IsArray($aResult) Then Return SetError(1, @error, 0) If Not $aResult[0] Then Return SetError(2, 0, 0) Return $aResult[0] EndFunc ;==>_WinAPI_GetThreadDpiAwarenessContext ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpifromdpiawarenesscontext ;MSDN: PER_MONITOR_AWARE and PER_MONITOR_AWARE_V2 contexts return 0 because the real DPI ;cannot be determined without an HWND. 0 is therefore NOT an error here. Func _WinAPI_GetDpiFromDpiAwarenessContext($iContext) Local $aResult = DllCall("user32.dll", "uint", "GetDpiFromDpiAwarenessContext", "int_ptr", $iContext) ;Win10 1803+ / Windows Server 2016+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, 0) Return $aResult[0] EndFunc ;==>_WinAPI_GetDpiFromDpiAwarenessContext ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getawarenessfromdpiawarenesscontext ;Returns a DPI_AWARENESS value. 0 = DPI_AWARENESS_UNAWARE is a valid result, and the "int" ;return type keeps DPI_AWARENESS_INVALID (-1) intact instead of turning it into 4294967295. ;Note: PER_MONITOR_AWARE and PER_MONITOR_AWARE_V2 both report 2 - use ;_WinAPI_AreDpiAwarenessContextsEqual to distinguish them. Func _WinAPI_GetAwarenessFromDpiAwarenessContext($iContext) Local $aResult = DllCall("user32.dll", "int", "GetAwarenessFromDpiAwarenessContext", "int_ptr", $iContext) ;Win10 1607+ / no server support If @error Or Not IsArray($aResult) Then Return SetError(1, @error, $DPI_AWARENESS_INVALID) Return $aResult[0] EndFunc ;==>_WinAPI_GetAwarenessFromDpiAwarenessContext ;Convenience: DPI_AWARENESS of the calling thread. Func _WinAPI_GetThreadDpiAwareness() Local $iContext = _WinAPI_GetThreadDpiAwarenessContext() If @error Then Return SetError(1, @error, $DPI_AWARENESS_INVALID) Local $iAwareness = _WinAPI_GetAwarenessFromDpiAwarenessContext($iContext) If @error Then Return SetError(2, @error, $DPI_AWARENESS_INVALID) Return $iAwareness EndFunc ;==>_WinAPI_GetThreadDpiAwareness ;Convenience: does the calling thread run in the given context? Func _WinAPI_IsThreadDpiAwarenessContext($iContext) Local $iCurrent = _WinAPI_GetThreadDpiAwarenessContext() If @error Then Return SetError(1, @error, False) Local $bEqual = _WinAPI_AreDpiAwarenessContextsEqual($iCurrent, $iContext) If @error Then Return SetError(2, @error, False) Return $bEqual EndFunc ;==>_WinAPI_IsThreadDpiAwarenessContext ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpiawarenesscontextforprocess ;$hProcess = 0 means the current process. Careful with that: asked about its own process, ;Windows returns the context of the CALLING THREAD, so a thread that overrode its awareness ;gets its own value back, not the process default. For another process the answer is the real ;process context. ;MSDN names Win10 1607 as the minimum, winuser.h however guards the API with NTDDI_WIN10_19H1, ;so only from 1903 (build 18362) on can the export be relied on. Func _WinAPI_GetDpiAwarenessContextForProcess($hProcess = 0) Local $aResult = DllCall("user32.dll", "int_ptr", "GetDpiAwarenessContextForProcess", "handle", $hProcess) ;Win10 1903+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, 0) If Not $aResult[0] Then Return SetError(2, 0, 0) Return $aResult[0] EndFunc ;==>_WinAPI_GetDpiAwarenessContextForProcess ;https://learn.microsoft.com/en-us/windows/win32/api/shellscalingapi/nf-shellscalingapi-getprocessdpiawareness ;Counterpart of _WinAPI_SetProcessDpiAwareness. $hProcess = 0 asks for the current process. ;Returns a PROCESS_DPI_AWARENESS value (0..2). PER_MONITOR_AWARE_V2 is reported as ;$PROCESS_PER_MONITOR_DPI_AWARE - this API cannot tell V1 and V2 apart. Func _WinAPI_GetProcessDpiAwareness($hProcess = 0) Local $tAwareness = DllStructCreate("int value") Local $aResult = DllCall("Shcore.dll", "long", "GetProcessDpiAwareness", "handle", $hProcess, "struct*", $tAwareness) ;Win8.1+ / Server 2012 R2+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, $DPI_AWARENESS_INVALID) If $aResult[0] <> 0 Then Return SetError(2, $aResult[0], $DPI_AWARENESS_INVALID) ;HRESULT check Return $tAwareness.value EndFunc ;==>_WinAPI_GetProcessDpiAwareness ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-isprocessdpiaware ;Counterpart of _WinAPI_SetProcessDPIAware. Legacy check: it only distinguishes "unaware" ;from "aware", so a per monitor aware process also reports True. Func _WinAPI_IsProcessDPIAware() Local $aResult = DllCall("user32.dll", "bool", "IsProcessDPIAware") ;Vista+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, False) Return ($aResult[0] <> 0) EndFunc ;==>_WinAPI_IsProcessDPIAware ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemdpiforprocess Func _WinAPI_GetSystemDpiForProcess($hProcess = 0) Local $aResult = DllCall("user32.dll", "uint", "GetSystemDpiForProcess", "handle", $hProcess) ;Win10 1803+ / Windows Server 2016+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, 0) If Not $aResult[0] Then Return SetError(2, 0, 0) Return $aResult[0] EndFunc ;==>_WinAPI_GetSystemDpiForProcess ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowdpiawarenesscontext Func _WinAPI_GetWindowDpiAwarenessContext($hWnd) Local $aResult = DllCall("user32.dll", "int_ptr", "GetWindowDpiAwarenessContext", "hwnd", $hWnd) ;Win10 1607+ / Windows Server 2016+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, 0) If Not $aResult[0] Then Return SetError(2, 0, 0) ;NULL = invalid window Return $aResult[0] EndFunc ;==>_WinAPI_GetWindowDpiAwarenessContext ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getthreaddpihostingbehavior ;Returns a DPI_HOSTING_BEHAVIOR value. $DPI_HOSTING_BEHAVIOR_DEFAULT (0) is a valid result. Func _WinAPI_GetThreadDpiHostingBehavior() Local $aResult = DllCall("user32.dll", "int", "GetThreadDpiHostingBehavior") ;Win10 1803+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, $DPI_HOSTING_BEHAVIOR_INVALID) Return $aResult[0] EndFunc ;==>_WinAPI_GetThreadDpiHostingBehavior ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowdpihostingbehavior ;Returns a DPI_HOSTING_BEHAVIOR value, $DPI_HOSTING_BEHAVIOR_INVALID (-1) for an invalid window. Func _WinAPI_GetWindowDpiHostingBehavior($hWnd) Local $aResult = DllCall("user32.dll", "int", "GetWindowDpiHostingBehavior", "hwnd", $hWnd) ;Win10 1803+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, $DPI_HOSTING_BEHAVIOR_INVALID) If $aResult[0] = $DPI_HOSTING_BEHAVIOR_INVALID Then Return SetError(2, 0, $DPI_HOSTING_BEHAVIOR_INVALID) Return $aResult[0] EndFunc ;==>_WinAPI_GetWindowDpiHostingBehavior ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-aredpiawarenesscontextsequal ;False is a valid answer, so @error is only set when the call itself failed. Func _WinAPI_AreDpiAwarenessContextsEqual($iContextA, $iContextB) Local $aResult = DllCall("user32.dll", "bool", "AreDpiAwarenessContextsEqual", "int_ptr", $iContextA, "int_ptr", $iContextB) ;Win10 1607+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, False) Return ($aResult[0] <> 0) EndFunc ;==>_WinAPI_AreDpiAwarenessContextsEqual ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemmetricsfordpi ;0 can be a legitimate metric value, so it is not treated as an error. Func _WinAPI_GetSystemMetricsForDpi($nIndex, $iDpi) Local $aResult = DllCall("user32.dll", "int", "GetSystemMetricsForDpi", "int", $nIndex, "uint", $iDpi) ;Win10 1607+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, 0) Return $aResult[0] EndFunc ;==>_WinAPI_GetSystemMetricsForDpi ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdialogdpichangebehavior ;Returns a DDC_* bit mask. $DDC_DEFAULT (0) is a valid result. Func _WinAPI_GetDialogDpiChangeBehavior($hWnd) Local $aResult = DllCall("user32.dll", "int", "GetDialogDpiChangeBehavior", "hwnd", $hWnd) ;Win10 1703+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, -1) Return $aResult[0] EndFunc ;==>_WinAPI_GetDialogDpiChangeBehavior ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdialogcontroldpichangebehavior ;Returns a DCDC_* bit mask. $DCDC_DEFAULT (0) is a valid result. Func _WinAPI_GetDialogControlDpiChangeBehavior($hWnd) Local $aResult = DllCall("user32.dll", "int", "GetDialogControlDpiChangeBehavior", "hwnd", $hWnd) ;Win10 1703+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, -1) Return $aResult[0] EndFunc ;==>_WinAPI_GetDialogControlDpiChangeBehavior #EndRegion WinAPI DPI - queries #Region WinAPI DPI - setters ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setprocessdpiawarenesscontext ;@extended carries GetLastError() on failure - ERROR_ACCESS_DENIED (5) means the awareness ;was already fixed (typically by the application manifest) and cannot be changed. Func _WinAPI_SetProcessDpiAwarenessContext($iContext) Local $aResult = DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", "int_ptr", $iContext) ;Win10 1703+ / Windows Server 2016+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, False) If Not $aResult[0] Then Return SetError(2, __WinAPI_DPI_GetLastError(), False) Return True EndFunc ;==>_WinAPI_SetProcessDpiAwarenessContext ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setthreaddpiawarenesscontext ;Returns the PREVIOUS context - keep it and restore it when you are done, otherwise you ;change the behaviour of unrelated code running on the same thread. Func _WinAPI_SetThreadDpiAwarenessContext($iContext) Local $aResult = DllCall("user32.dll", "int_ptr", "SetThreadDpiAwarenessContext", "int_ptr", $iContext) ;Win10 1607+ / Windows Server 2016+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, 0) If Not $aResult[0] Then Return SetError(2, __WinAPI_DPI_GetLastError(), 0) ;NULL = invalid context Return $aResult[0] EndFunc ;==>_WinAPI_SetThreadDpiAwarenessContext ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setthreadcursorcreationscaling ;Decides for which DPI cursors created by this thread are scaled: $CURSOR_CREATION_SCALING_NONE ;switches the scaling off, $CURSOR_CREATION_SCALING_DEFAULT restores the system behaviour, any ;larger value is used as the target DPI. Only affects cursors created afterwards, so set it, ;create them, restore the previous value that this function returns. ;winuser.h guards the API with NTDDI_WIN10_CO - Windows 11 21H2 is the first version with it. Func _WinAPI_SetThreadCursorCreationScaling($iCursorDpi = $CURSOR_CREATION_SCALING_DEFAULT) Local $aResult = DllCall("user32.dll", "uint", "SetThreadCursorCreationScaling", "uint", $iCursorDpi) ;Win11 21H2+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, 0) If Not $aResult[0] Then Return SetError(2, __WinAPI_DPI_GetLastError(), 0) ;0 = call failed Return $aResult[0] EndFunc ;==>_WinAPI_SetThreadCursorCreationScaling ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setthreaddpihostingbehavior ;Decides whether windows created by this thread may host child windows with a different DPI ;awareness ($DPI_HOSTING_BEHAVIOR_MIXED) or not ($DPI_HOSTING_BEHAVIOR_DEFAULT). ;Returns the PREVIOUS behaviour - restore it once the windows in question have been created. Func _WinAPI_SetThreadDpiHostingBehavior($iBehavior) Local $aResult = DllCall("user32.dll", "int", "SetThreadDpiHostingBehavior", "int", $iBehavior) ;Win10 1803+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, $DPI_HOSTING_BEHAVIOR_INVALID) If $aResult[0] = $DPI_HOSTING_BEHAVIOR_INVALID Then Return SetError(2, 0, $DPI_HOSTING_BEHAVIOR_INVALID) Return $aResult[0] EndFunc ;==>_WinAPI_SetThreadDpiHostingBehavior ;https://learn.microsoft.com/en-us/windows/win32/api/shellscalingapi/nf-shellscalingapi-setprocessdpiawareness ;$iAwareness is a PROCESS_DPI_AWARENESS value (0..2), not a DPI_AWARENESS_CONTEXT. ;@extended carries the HRESULT - E_ACCESSDENIED (0x80070005) means "already set". Func _WinAPI_SetProcessDpiAwareness($iAwareness = $PROCESS_PER_MONITOR_DPI_AWARE) Local $aResult = DllCall("Shcore.dll", "long", "SetProcessDpiAwareness", "int", $iAwareness) ;Win8.1+ / Server 2012 R2+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, False) If $aResult[0] <> 0 Then Return SetError(2, $aResult[0], False) Return True EndFunc ;==>_WinAPI_SetProcessDpiAwareness ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setprocessdpiaware Func _WinAPI_SetProcessDPIAware() Local $aResult = DllCall("user32.dll", "bool", "SetProcessDPIAware") ;Vista+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, False) If Not $aResult[0] Then Return SetError(2, __WinAPI_DPI_GetLastError(), False) Return True EndFunc ;==>_WinAPI_SetProcessDPIAware ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enablenonclientdpiscaling ;Unnecessary in PER_MONITOR_AWARE_V2 contexts - V2 scales the non-client area already. Func _WinAPI_EnableNonClientDpiScaling($hWnd) Local $aResult = DllCall("user32.dll", "bool", "EnableNonClientDpiScaling", "hwnd", $hWnd) ;Win10 1607+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, False) If Not $aResult[0] Then Return SetError(2, __WinAPI_DPI_GetLastError(), False) Return True EndFunc ;==>_WinAPI_EnableNonClientDpiScaling ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setdialogdpichangebehavior Func _WinAPI_SetDialogDpiChangeBehavior($hWnd, $iMask, $iValues) Local $aResult = DllCall("user32.dll", "bool", "SetDialogDpiChangeBehavior", "hwnd", $hWnd, "int", $iMask, "int", $iValues) ;Win10 1703+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, False) If Not $aResult[0] Then Return SetError(2, __WinAPI_DPI_GetLastError(), False) Return True EndFunc ;==>_WinAPI_SetDialogDpiChangeBehavior ;https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setdialogcontroldpichangebehavior Func _WinAPI_SetDialogControlDpiChangeBehavior($hWnd, $iMask, $iValues) Local $aResult = DllCall("user32.dll", "bool", "SetDialogControlDpiChangeBehavior", "hwnd", $hWnd, "int", $iMask, "int", $iValues) ;Win10 1703+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, False) If Not $aResult[0] Then Return SetError(2, __WinAPI_DPI_GetLastError(), False) Return True EndFunc ;==>_WinAPI_SetDialogControlDpiChangeBehavior ;https://learn.microsoft.com/en-us/windows/win32/api/uxtheme/nf-uxtheme-openthemedatafordpi ;The caller owns the returned HTHEME and must release it with _WinAPI_CloseThemeData. Func _WinAPI_OpenThemeDataForDpi($hWnd, $pszClassList, $iDpi) Local $aResult = DllCall("uxtheme.dll", "handle", "OpenThemeDataForDpi", "hwnd", $hWnd, "wstr", $pszClassList, "uint", $iDpi) ;Win10 1703+ If @error Or Not IsArray($aResult) Then Return SetError(1, @error, 0) If Not $aResult[0] Then Return SetError(2, 0, 0) Return $aResult[0] EndFunc ;==>_WinAPI_OpenThemeDataForDpi #EndRegion WinAPI DPI - setters #Region High level ; #FUNCTION# =================================================================================== ; Name ..........: _WinAPI_SetDPIAwareness ; Description ...: Sets the DPI awareness using the best method the running OS supports. ; Syntax ........: _WinAPI_SetDPIAwareness([$iAwarenessLevel = $DPI_LEVEL_PER_MONITOR[, $iMode = $DPI_SCOPE_PROCESS]]) ; Parameters ....: $iAwarenessLevel - unified level, one of $DPI_LEVEL_*: ; 0 = UNAWARE ; 1 = SYSTEM ; 2 = PER_MONITOR (default) ; 3 = PER_MONITOR_V2 (Win10 1703+) ; 4 = UNAWARE_GDISCALED (Win10 1809+) ; Raw DPI_AWARENESS_CONTEXT values (-1..-5) are also ; accepted for backwards compatibility. ; $iMode - $DPI_SCOPE_PROCESS (1, default) or $DPI_SCOPE_THREAD (2) ; Return values .: Success: the current DPI. @extended = 1 means the DPI could not be ; determined and the default of 96 was returned instead. ; Failure: 0 and @error set: ; 1 - no method available or all methods failed (@extended = last Win32 error) ; 10 - thread scope requested but the OS is older than Win10 1607 ; 11 - SetThreadDpiAwarenessContext failed (@extended = last Win32 error) ; Mismatch: the current DPI is returned and @error is set to ; 12 - the awareness in effect differs from the requested one, either ; because the application manifest already fixed it or because ; only an older API was available, which cannot reach every ; level. @extended holds the $DPI_LEVEL_* value that is really ; active. Process scope only - see the remarks. ; Remarks .......: Call this before the first GUICreate or any other window access. ; Levels above the OS capability are silently downgraded: V2 -> PER_MONITOR, ; GDISCALED -> UNAWARE. That downgrade is expected and does NOT raise @error 12. ; The result is verified afterwards, so a manifest that pins a different ; awareness, and a fallback that only reached a lower level, both surface as ; @error 12 instead of being reported as plain success. Which level a ; successful step established is known without asking; only an awareness that ; turned out to be immutable has to be queried, and that query answers for the ; calling thread, because Windows reports nothing else about its own process. ; A thread that overrode its own awareness beforehand can therefore turn that ; one case into a mismatch report. On systems where the active level cannot be ; determined at all the check is skipped. ; In thread scope the previous context is NOT returned. If you need to ; restore it, call _WinAPI_SetThreadDpiAwarenessContext directly. ; Setting the awareness via the application manifest is more robust than ; calling this function, because windows can in principle be created before ; the first script statement runs. ; ============================================================================================== Func _WinAPI_SetDPIAwareness($iAwarenessLevel = $DPI_LEVEL_PER_MONITOR, $iMode = $DPI_SCOPE_PROCESS) Local $iActiveLevel = -1, $iDPI = 0, $iThreadDPI = 0, $iFlags = 0 ;--- Normalise the requested level --------------------------------------------------- ;Accept raw DPI_AWARENESS_CONTEXT values: -1 -> 0, -2 -> 1, ... -5 -> 4 If $iAwarenessLevel < 0 Then $iAwarenessLevel = (-$iAwarenessLevel) - 1 ;Int() first: a fractional value would pass both clamps below and then hit the fallback ;branch of the context map $iAwarenessLevel = Int($iAwarenessLevel) If $iAwarenessLevel < $DPI_LEVEL_UNAWARE Then $iAwarenessLevel = $DPI_LEVEL_UNAWARE ;Clamp to V2, NOT to GDISCALED: an out-of-range value must not silently select an ;unaware mode. This also closes the out-of-bounds crash the old context map had. If $iAwarenessLevel > $DPI_LEVEL_UNAWARE_GDISCALED Then $iAwarenessLevel = $DPI_LEVEL_PER_MONITOR_V2 ;--- Downgrade to what this OS actually supports -------------------------------------- If $iAwarenessLevel = $DPI_LEVEL_PER_MONITOR_V2 And @OSBuild < $__DPI_BUILD_1703 Then $iAwarenessLevel = $DPI_LEVEL_PER_MONITOR ;GDISCALED is an UNAWARE variant, so its fallback is UNAWARE - not PER_MONITOR If $iAwarenessLevel = $DPI_LEVEL_UNAWARE_GDISCALED And @OSBuild < $__DPI_BUILD_1809 Then $iAwarenessLevel = $DPI_LEVEL_UNAWARE Local Const $iContext = __WinAPI_DPI_LevelToContext($iAwarenessLevel) If $iMode <> $DPI_SCOPE_THREAD Then $iMode = $DPI_SCOPE_PROCESS ;--- Thread scope --------------------------------------------------------------------- If $iMode = $DPI_SCOPE_THREAD Then ;There is no legacy equivalent - per-thread awareness starts with Win10 1607 If @OSBuild < $__DPI_BUILD_1607 Then Return SetError(10, 0, 0) _WinAPI_SetThreadDpiAwarenessContext($iContext) ;@extended of the wrapper carries the Win32 error, @error only says which check failed If @error Then Return SetError(11, @extended, 0) $iThreadDPI = __WinAPI_DPI_QueryCurrent() If Not $iThreadDPI Then $iThreadDPI = $__DPI_DEFAULT_DPI $iFlags = 1 EndIf ;No verification needed: SetThreadDpiAwarenessContext applies the context as given or ;fails outright, which the check above already turned into @error 11. Return SetError(0, $iFlags, $iThreadDPI) EndIf ;--- Process scope: descending fallback chain ----------------------------------------- ;$iAchievedLevel keeps what the successful step really established. It stays -1 only when ;the awareness turned out to be immutable, which is the one case that has to be queried. Local $bDone = False, $iLastError = 0, $iAchievedLevel = -1, $iPrecision = 0 ;Step 1: SetProcessDpiAwarenessContext - the only route to V2 / GDISCALED. MSDN gives 1607 ;as the minimum, so it is tried from there on; the context VALUES for V2 and GDISCALED need ;1703 / 1809, which the downgrade above already took care of. Should the export be missing ;on an early build, the call simply fails and step 2 takes over. If @OSBuild >= $__DPI_BUILD_1607 Then If _WinAPI_SetProcessDpiAwarenessContext($iContext) Then $bDone = True $iAchievedLevel = $iAwarenessLevel ;the context was applied exactly as passed Else $iLastError = @extended ;ERROR_ACCESS_DENIED: the awareness is already fixed (manifest) and immutable. ;Do not fail here - whether the fixed state matches the request is decided by the ;verification at the end of this function. If $iLastError = $__DPI_ERROR_ACCESS_DENIED Then $bDone = True EndIf EndIf ;Step 2: SetProcessDpiAwareness - Win8.1+, knows only three levels If Not $bDone And @OSBuild >= $__DPI_BUILD_WIN81 Then ;PER_MONITOR and V2 both land on PROCESS_PER_MONITOR_DPI_AWARE, GDISCALED on UNAWARE Local $iLegacy = __WinAPI_DPI_LevelToCoarse($iAwarenessLevel) If _WinAPI_SetProcessDpiAwareness($iLegacy) Then $bDone = True ;This API cannot deliver V2, so a V2 request ends up one level lower here $iAchievedLevel = $iLegacy ;PROCESS_DPI_AWARENESS 0..2 = the first three levels Else $iLastError = @extended If $iLastError = $__DPI_E_ACCESSDENIED Then $bDone = True ;already set EndIf EndIf ;Step 3: SetProcessDPIAware - Vista+, system aware only. Pointless for unaware levels. If Not $bDone And @OSBuild >= $__DPI_BUILD_VISTA And $iAwarenessLevel <> $DPI_LEVEL_UNAWARE And $iAwarenessLevel <> $DPI_LEVEL_UNAWARE_GDISCALED Then If _WinAPI_SetProcessDPIAware() Then $bDone = True $iAchievedLevel = $DPI_LEVEL_SYSTEM ;this API knows nothing above system awareness Else $iLastError = @extended If $iLastError = $__DPI_ERROR_ACCESS_DENIED Then $bDone = True ;already set EndIf EndIf ;Step 4: unaware is the default state of every process - nothing to call, nothing failed. ;GDI scaling however cannot be switched on this way, so only plain UNAWARE is reached here. If Not $bDone And ($iAwarenessLevel = $DPI_LEVEL_UNAWARE Or $iAwarenessLevel = $DPI_LEVEL_UNAWARE_GDISCALED) Then $bDone = True $iAchievedLevel = $DPI_LEVEL_UNAWARE EndIf If Not $bDone Then Return SetError(1, $iLastError, 0) ;--- Report the resulting DPI --------------------------------------------------------- $iDPI = __WinAPI_DPI_QueryCurrent() ;Awareness was set successfully, so a failed DPI query is not a hard error - flag it ;in @extended and hand back the 96 DPI default. If Not $iDPI Then $iDPI = $__DPI_DEFAULT_DPI $iFlags = 1 EndIf ;--- Verify what is really in effect --------------------------------------------------- ;Two cases end up here without the request having been honoured: the fallback chain reached ;a lower level than asked for - SetProcessDPIAware can only deliver system awareness - and ;the awareness was already fixed (ACCESS_DENIED above, typically by the manifest). Both used ;to be reported as plain success, which hides wrong scaling on multi monitor setups. ;The first case is known from the step that succeeded, only the second one has to be asked ;about - and only there does the thread relative answer of __WinAPI_DPI_GetActiveLevel() ;come into play. $iActiveLevel = $iAchievedLevel If $iActiveLevel = -1 Then $iActiveLevel = __WinAPI_DPI_GetActiveLevel() $iPrecision = @extended EndIf If Not __WinAPI_DPI_LevelSatisfies($iActiveLevel, $iPrecision, $iAwarenessLevel) Then Return SetError(12, $iActiveLevel, $iDPI) Return SetError(0, $iFlags, $iDPI) EndFunc ;==>_WinAPI_SetDPIAwareness #EndRegion High level Example: ;Coded by UEZ build 2026-08-26 beta ;Compile the script and run the EXE. Running it uncompiled inherits the manifest of ;AutoIt3.exe, which already fixes the DPI awareness, so the runtime call below cannot ;take effect any more. #AutoIt3Wrapper_Res_HiDpi=n ;must stay off - see the note at the top #AutoIt3Wrapper_UseX64=n #AutoIt3Wrapper_Change2CUI=y #include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> #include <WindowsConstants.au3> #include "_WinAPI_DPI.au3" Global Const $LOGICAL_DPI = 96 ;USER_DEFAULT_SCREEN_DPI, the baseline of all layout values ;Main window controls: ctrl id, logical x, y, w, h, logical font size Global $g_aMainCtrl[5][6] = [[0, 16, 16, 40, 21, 10], _ [0, 64, 16, 40, 21, 10], _ [0, 112, 16, 40, 21, 10], _ [0, 160, 16, 137, 22, 10], _ [0, 16, 48, 283, 65, 16]] ;Child window controls, same layout: id, x, y, w, h, font size (0 = no font handling) Global $g_aChildCtrl[2][6] = [[0, 16, 16, 288, 168, 65], _ [0, 0, 190, 68, 71, 0]] Global Const $MAIN_W = 314, $MAIN_H = 130 ;logical client size of the main window Global Const $CHILD_W = 320, $CHILD_H = 260 ;logical client size of the child window ;The system DPI is frozen at process start. GDI converts point sizes to pixels with THIS ;value, not with the DPI of the monitor a window currently sits on - so font sizes need ;the correction factor windowDPI / systemDPI, while pixel values need windowDPI / 96. Global $g_iSystemDPI = $LOGICAL_DPI Global $hGUI, $hGUI_child, $sImage Example1() Func Example1() ;-1..-5 are pseudo handles, not real pointers - see _WinAPI_DPI.au3 Local $iDPI = _WinAPI_SetDPIAwareness($DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) Local $iErr = @error, $iActiveLevel = @extended ;@error 12 is not fatal: the awareness is fixed - usually by a manifest - and differs from ;the request, but the returned DPI is still valid, so only the layout hint below applies. If ($iErr And $iErr <> 12) Or Not $iDPI Then Exit MsgBox($MB_ICONERROR, "ERROR", "Cannot set DPI awareness!", 10) $g_iSystemDPI = $iDPI ConsoleWrite("System DPI: " & $iDPI & @CRLF) ;Only V2 scales the non client area (title bar, borders) automatically, so it is worth ;knowing when something else is active. _WinAPI_IsThreadDpiAwarenessContext() answers the ;same question for any context at any later point. If $iErr = 12 Then ConsoleWrite("! PER_MONITOR_AWARE_V2 is NOT active, level " & $iActiveLevel & " is - check the manifest settings" & @CRLF) EndIf $sImage = _FindMerlin() If Not $sImage Then ConsoleWrite("! Merlin.gif not found, the picture control is skipped" & @CRLF) Local $iRatio = $iDPI / $LOGICAL_DPI ;--- main window --------------------------------------------------------------------- $hGUI = GUICreate("Example 1", $MAIN_W * $iRatio, $MAIN_H * $iRatio, -1, 10) ;no ratio here - point sizes are already scaled by GDI via the system DPI GUISetFont(12, 400, 0, "Times New Roman") Local $i For $i = 0 To 2 $g_aMainCtrl[$i][0] = GUICtrlCreateLabel("Label" & ($i + 1), 0, 0, 10, 10) GUICtrlSetBkColor(-1, 0x3399FF) GUICtrlSetResizing(-1, $GUI_DOCKAUTO) Next $g_aMainCtrl[3][0] = GUICtrlCreateInput("Input1", 0, 0, 10, 10) GUICtrlSetResizing(-1, $GUI_DOCKAUTO) $g_aMainCtrl[4][0] = GUICtrlCreateButton("Close", 0, 0, 10, 10) GUICtrlSetResizing(-1, $GUI_DOCKAUTO) ;--- child window -------------------------------------------------------------------- $hGUI_child = GUICreate("Child", $CHILD_W * $iRatio, $CHILD_H * $iRatio, -1, -1, -1, -1, $hGUI) GUISetBkColor(0xFFFFFF) $g_aChildCtrl[0][0] = GUICtrlCreateLabel("Label11", 0, 0, 10, 10) If $sImage Then $g_aChildCtrl[1][0] = GUICtrlCreatePic($sImage, 0, 0, 10, 10) ;The windows may well open on a monitor whose DPI differs from the system DPI, so lay ;the controls out from the DPI each window actually has instead of the initial ratio. _ApplyDpi($hGUI, _GetWindowDpi($hGUI), True) _ApplyDpi($hGUI_child, _GetWindowDpi($hGUI_child), True) ;register before GUISetState, otherwise a DPI change triggered while showing is lost GUIRegisterMsg($WM_DPICHANGED, "WM_DPICHANGED") GUISetState(@SW_SHOW, $hGUI) GUISetState(@SW_SHOW, $hGUI_child) While True Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $g_aMainCtrl[4][0] GUIDelete($hGUI_child) GUIDelete($hGUI) ExitLoop EndSwitch WEnd EndFunc ;==>Example1 ;Applies the layout of one window for the given DPI. All values are recomputed from the ;logical tables, never from the currently visible (already scaled) values. ;$bResizeWindow = True also adjusts the window itself - during WM_DPICHANGED Windows has ;already supplied the target rectangle, so it must stay False there. Func _ApplyDpi($hWnd, $iDPI, $bResizeWindow = False) Local $i ;pixel values are logical 96 DPI values and scale with windowDPI / 96 ... Local $nRatio = $iDPI / $LOGICAL_DPI ;... point sizes are converted by GDI with the frozen system DPI, so they only need the ;difference between that and the DPI of the monitor this window is currently on Local $nFontRatio = $iDPI / $g_iSystemDPI Switch $hWnd Case $hGUI If $bResizeWindow Then _ResizeClientArea($hWnd, $MAIN_W * $nRatio, $MAIN_H * $nRatio) For $i = 0 To UBound($g_aMainCtrl) - 1 _ApplyCtrl($g_aMainCtrl, $i, $nRatio, $nFontRatio) Next Case $hGUI_child If $bResizeWindow Then _ResizeClientArea($hWnd, $CHILD_W * $nRatio, $CHILD_H * $nRatio) For $i = 0 To UBound($g_aChildCtrl) - 1 _ApplyCtrl($g_aChildCtrl, $i, $nRatio, $nFontRatio) Next ;a picture control does not rescale its bitmap on its own - reassign the image If $g_aChildCtrl[1][0] Then GUICtrlSetImage($g_aChildCtrl[1][0], $sImage) EndSwitch EndFunc ;==>_ApplyDpi ;Positions and sizes a single control from its logical values. Func _ApplyCtrl(ByRef $aCtrl, $iRow, $nRatio, $nFontRatio) If Not $aCtrl[$iRow][0] Then Return ;control was not created (missing image) GUICtrlSetPos($aCtrl[$iRow][0], Round($aCtrl[$iRow][1] * $nRatio), _ Round($aCtrl[$iRow][2] * $nRatio), _ Round($aCtrl[$iRow][3] * $nRatio), _ Round($aCtrl[$iRow][4] * $nRatio)) ;$nFontRatio, NOT $nRatio - multiplying by the full DPI ratio here scales the font twice If $aCtrl[$iRow][5] Then GUICtrlSetFont($aCtrl[$iRow][0], $aCtrl[$iRow][5] * $nFontRatio, 400, 0, "Times New Roman", 5) EndFunc ;==>_ApplyCtrl ;Sets the CLIENT area to the given size, keeping the current position. Func _ResizeClientArea($hWnd, $iClientW, $iClientH) Local $aWin = WinGetPos($hWnd) If @error Or Not IsArray($aWin) Then Return Local $aClient = WinGetClientSize($hWnd) If @error Or Not IsArray($aClient) Then Return ;difference between window and client size = the non client frame at the current DPI WinMove($hWnd, "", $aWin[0], $aWin[1], Round($iClientW) + ($aWin[2] - $aClient[0]), Round($iClientH) + ($aWin[3] - $aClient[1])) EndFunc ;==>_ResizeClientArea ;DPI of a window with a fallback - a failed call must never yield 0, that would produce ;a font size of 0 further down the line. Func _GetWindowDpi($hWnd) Local $iDPI = _WinAPI_GetDpiForWindow($hWnd) ;Win10 1607+ If @error Or Not $iDPI Then $iDPI = _WinAPI_GetDpiForMonitor() ;Win8.1+ If @error Or Not $iDPI Then $iDPI = $LOGICAL_DPI EndIf Return $iDPI EndFunc ;==>_GetWindowDpi ;Looks for Merlin.gif in the usual places. Returns "" when nothing was found. Func _FindMerlin() Local $sSub = "Examples\GUI\Merlin.gif" Local $sAutoItDir = StringLeft(@AutoItExe, StringInStr(@AutoItExe, "\", 0, -1)) Local $aCandidates[4] = [@ScriptDir & "\Merlin.gif", _ $sAutoItDir & $sSub, _ @ProgramFilesDir & "\AutoIt3\" & $sSub, _ EnvGet("ProgramFiles(x86)") & "\AutoIt3\" & $sSub] Local $i For $i = 0 To UBound($aCandidates) - 1 If $aCandidates[$i] And FileExists($aCandidates[$i]) Then Return $aCandidates[$i] Next Return "" EndFunc ;==>_FindMerlin ;https://learn.microsoft.com/en-us/windows/win32/hidpi/wm-dpichanged ;wParam: LOWORD = new X DPI, HIWORD = new Y DPI ;lParam: pointer to the suggested new window RECT, already including the non client frame Func WM_DPICHANGED($hWnd, $iMsg, $wParam, $lParam) #forceref $iMsg Local $iNewDPI = _WinAPI_LoWord($wParam) Local $tRECT = DllStructCreate($tagRECT, $lParam) ;Apply the suggested rectangle as is - no AdjustWindowRectExForDpi needed here _WinAPI_SetWindowPos($hWnd, 0, $tRECT.Left, $tRECT.Top, $tRECT.Right - $tRECT.Left, $tRECT.Bottom - $tRECT.Top, BitOR($SWP_NOZORDER, $SWP_NOACTIVATE)) ;Only the controls of THIS window are touched - the old version also ran the child ;window code when the parent received the message _ApplyDpi($hWnd, $iNewDPI) $tRECT = 0 ConsoleWrite("DPI change to " & $iNewDPI & " applied to " & (($hWnd = $hGUI) ? "main" : "child") & " window" & @CRLF) Return 0 ;0 = handled, as the API expects EndFunc ;==>WM_DPICHANGED Claude added the comments and fixed some bugs. Please test if everything is working as expected, and feel free to leave comments.
-
UEZ reacted to a post in a topic:
Png2Icon Update of 4 july 2026
-
Try: Global $sRemote = "192.168.1.50:9000" ; IP of the receiver Global $sCmd = $sFFMPEG & ' ' & $sInput & ' ' & _ '-filter_complex "[0:v]split[rec][tmp];[tmp]fps=30[net]" ' & _ '-map "[rec]" -c:v libx264 -pix_fmt yuv420p ' & $sAudioMap & '"' & $sOutFile & '" ' & _ '-map "[net]" -c:v libx264 -preset ultrafast -tune zerolatency -g 10 -an ' & _ '-fflags +nobuffer -flags +low_delay -muxdelay 0 -muxpreload 0 -flush_packets 1 ' & _ '-f tee "[f=mpegts]' & $sUDP & '|[f=mpegts]srt://' & $sRemote & '?mode=caller"'
-
What are you trying to do? Record from the webcam?
-
Last try - see above. Personally, I don't like this approach of using ffmpeg and mpv to display and record the webcam.
-
I updated the code above - the latency should be better now.
-
Made some updates - please try again.
-
Try this: ;Code by UEZ build 2026-06-27 #include <AutoItConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <WinAPIError.au3> Global $iW = 1280, $iH = 720 Global $sFFMPEG = '"...\FFMPEG\bin\ffmpeg.exe"' Global $sMPV = '"...\MPV\mpv.exe"' Global $sOutFile = "C:\Temp\WebCamRec.mkv" Global $aVid, $aAud _GetDShowDevices($sFFMPEG, $aVid, $aAud) If $aVid[0] = 0 Then Exit MsgBox(16, "Error", "No video capture device found") Global $sVideo = $aVid[1] ; first WebCam Global $sAudio = ($aAud[0] > 0) ? $aAud[1] : "" ; first micro, if available Global $bHasAudio = ($sAudio <> "") ; Input-Optionen MUESSEN vor dem -i stehen (gelten fuer den folgenden Input) Global $sInput = '-f dshow -rtbufsize 256M -video_size 1280x720 -framerate 30 -pixel_format nv12 ' & _ '-use_wallclock_as_timestamps 1 -i video="' & $sVideo & '"' If $bHasAudio Then $sInput &= ' -f dshow -use_wallclock_as_timestamps 1 -i audio="' & $sAudio & '"' Global $sAudioMap = $bHasAudio ? '-map 1:a -c:a aac -ar 48000 -ac 2 ' : '' Global $hGUI = GUICreate("WebCam + Live Preview + Record", $iW, $iH + 40, -1, -1, BitOR($WS_OVERLAPPEDWINDOW, $WS_CLIPCHILDREN)) Global $idStop = GUICtrlCreateButton("Stop", 10, $iH + 6, 80, 26) Global $hChild = GUICreate("", $iW, $iH, 0, 0, $WS_CHILD, -1, $hGUI) GUISetState(@SW_SHOW, $hChild) GUISwitch($hGUI) GUISetState(@SW_SHOW, $hGUI) Global $wid = Number($hChild) If FileExists($sOutFile) Then FileDelete($sOutFile) Global $sUDP = "udp://127.0.0.1:1234?pkt_size=1316" Global $sCmd = $sFFMPEG & ' ' & $sInput & ' ' & _ '-filter_complex "[0:v]split[rec][tmp];[tmp]fps=30[prev]" ' & _ '-map "[rec]" -c:v libx264 -pix_fmt yuv420p ' & $sAudioMap & '"' & $sOutFile & '" ' & _ '-map "[prev]" -c:v libx264 -preset ultrafast -tune zerolatency -g 10 -an ' & _ '-fflags +nobuffer -flags +low_delay -muxdelay 0 -muxpreload 0 -flush_packets 1 ' & _ '-f mpegts ' & $sUDP Global $iPID = Run($sCmd, "", @SW_HIDE, $STDIN_CHILD) Global $sMpvPipe = "\\.\pipe\mpv_preview" Global $sMpvCmd = $sMPV & ' --wid=' & $wid & ' --no-audio --no-osc --force-window=yes ' & _ '--profile=low-latency --untimed --no-cache --demuxer-readahead-secs=0 ' & _ '--vd-queue-enable=no --demuxer-lavf-o=fflags=+nobuffer ' & _ '--demuxer-lavf-format=mpegts --input-ipc-server=' & $sMpvPipe & ' "' & $sUDP & '"' Global $iPIDmpv = Run($sMpvCmd, "") While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idStop _StopAll($iPID, $iPIDmpv) ExitLoop EndSwitch WEnd GUIDelete($hGUI) Func _GetDShowDevices($sFFMPEG, ByRef $aVideo, ByRef $aAudio) Local $sExe = StringReplace($sFFMPEG, '"', '') Local $iPID = Run('"' & $sExe & '" -hide_banner -list_devices true -f dshow -i dummy', "", @SW_HIDE, $STDERR_CHILD) Local $sOut = "" While 1 $sOut &= StderrRead($iPID) If @error Then ExitLoop WEnd Local $aV[1] = [0], $aA[1] = [0], $sType = "" Local $aLines = StringSplit(StringStripCR($sOut), @LF), $sLine, $aM For $i = 1 To $aLines[0] $sLine = $aLines[$i] If StringInStr($sLine, "(video)") Then $sType = "v" If StringInStr($sLine, "(audio)") Then $sType = "a" If StringInStr($sLine, "Alternative name") Then ContinueLoop $aM = StringRegExp($sLine, '"([^"]+)"', 1) If @error Then ContinueLoop If $sType = "v" Then _ArrayAdd_($aV, $aM[0]) ElseIf $sType = "a" Then _ArrayAdd_($aA, $aM[0]) EndIf Next $aVideo = $aV $aAudio = $aA EndFunc Func _ArrayAdd_(ByRef $a, $v) ReDim $a[$a[0] + 2] $a[0] += 1 $a[$a[0]] = $v EndFunc Func _StopAll($iPID, $iPIDmpv) If ProcessExists($iPID) Then StdinWrite($iPID, "q") StdinWrite($iPID) ProcessWaitClose($iPID, 10) If ProcessExists($iPID) Then ProcessClose($iPID) EndIf Local $h = FileOpen($sMpvPipe, 2) If $h <> -1 Then FileWrite($h, '{"command":["quit"]}' & @LF) FileClose($h) EndIf ProcessWaitClose($iPIDmpv, 2) If ProcessExists($iPIDmpv) Then ProcessClose($iPIDmpv) EndFunc mpv can be found here: https://sourceforge.net/projects/mpv-player-windows/files/ Adjust the pathes to ffmpeg and mpv!
-
Really nice screensavers. I like the falling hearts. Firework looks great, too. Well done!
-
UEZ reacted to a post in a topic:
GDI+ ScreenSavers
-
Need help with GDI+ line curve or arc
UEZ replied to WildByDesign's topic in AutoIt GUI Help and Support
Try: ... Local $hPath2 = _GDIPlus_PathCreate() _GDIPlus_PathAddArc($hPath2, $iW - 6, 0, 5, 5, 270, 90) _GDIPlus_PathAddLine($hPath2, $iW - 1, 5, $iW - 1, $iH - 6) ; button border fix <<<< need help with curve here _GDIPlus_PathAddArc($hPath2, $iW - 6, $iH - 6, 5, 5, 0, 90) Local $hPen = _GDIPlus_PenCreate(0xFFa0a0a0, 1) Local $hPen2 = _GDIPlus_PenCreate(0xFF9b9b9b, 1) _GDIPlus_GraphicsDrawPath($hBmpCtxt, $hPath, $hPen) _GDIPlus_GraphicsDrawPath($hBmpCtxt, $hPath2, $hPen2) ... -
Nice idea. Let's see who will win...
-
UEZ reacted to a post in a topic:
World Cup Mascots CrossFade
-
This is what I expected because what I understood is that "Camera" is also based on Media Foundation (Frame-Server) API.
-
You can disable "Click-through" in Tray icon -> Recorder -> WebCam settings ->Click-through. The DLL works with Media Foundation (Frame-Server) API which is probably not compatible with generic Microsoft Windows driver. Other apps may use DirectShow to display WebCam. Is Windows "Camera" built-in app working with your WebCam? You may update the drivers if available. Thanks for testing again. Coming soon a trim editor for recorded video inkl. reencode (4:2:0 (YUV) recorded video only).
-
Salut wakillion, I updated the version to AirCapRec v0.9.3 beta build 2026-06-05. Does your webcam show a picture in the Windows Camera app? Does it work in any other apps? In AirCapRec: enable Debug logging in Settings, then toggle the webcam (Ctrl+Alt+W) and send me the new AirCapRec_debug.log — it now logs the webcam state. Is it a built-in laptop cam or an external USB one? Brand/model? Does the webcam preview window show a black box in the corner (cam initialized but no image), or nothing at all? Any privacy/antivirus camera blocker active (Windows camera privacy setting, or third-party security)? I saw in the logfile a problem with your display info: It should display 4k and 300%. Please update and test again and post the log. MERCI!
-
You can create the grid manually without loading it from a file: #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> Opt("MustDeclareVars", 1) Global $g_hImage, $g_idPic Example() Func Example() Local $iW = 800, $iH = 400 ; Gui client width & height _GDIPlus_Startup() Local $xGrid = 20, $yGrid = 20 Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($xGrid, $yGrid) Local $hGfx = _GDIPlus_ImageGetGraphicsContext($hBitmap), $hPen = _GDIPlus_PenCreate(0xFF000000, 2) _GDIPlus_GraphicsClear($hGfx, 0xFFFFFFFF) _GDIPlus_GraphicsDrawLine($hGfx, 0, 0, $xGrid, 0, $hPen) _GDIPlus_GraphicsDrawLine($hGfx, 0, 1, 0, $yGrid, $hPen) _GDIPlus_PenDispose($hPen) _GDIPlus_GraphicsDispose($hGfx) Local $hTexture = _GDIPlus_TextureCreate($hBitmap) _GDIPlus_BitmapDispose($hBitmap) $g_hImage = _GDIPlus_BitmapCreateFromScan0($iW, $iH) $hGfx = _GDIPlus_ImageGetGraphicsContext($g_hImage) _GDIPlus_GraphicsClear($hGfx, 0xFFFFFFFF) _GDIPlus_GraphicsFillRect($hGfx, 0, 0, $iW, $iH, $hTexture) _GDIPlus_BrushDispose($hTexture) _GDIPlus_GraphicsDispose($hGfx) Local $hGUI = GUICreate("Test Grid #2", $iW, $iH, -1, -1, $WS_OVERLAPPEDWINDOW, $WS_EX_COMPOSITED) $g_idPic = GUICtrlCreatePic("", 0, 0, $iW, $iH) GUICtrlSetResizing(-1, $GUI_DOCKAUTO) ; or $GUI_DOCKBORDERS ? Update_Pic($g_hImage) GUISetState(@SW_SHOW) GUIRegisterMsg($WM_SIZE, "WM_SIZE") While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE _GDIPlus_ImageDispose($g_hImage) _GDIPlus_Shutdown() GUIDelete() Exit EndSwitch WEnd EndFunc ;==>Example Func Update_Pic($hHandle) Local $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hHandle) Local $hPrevImage = GUICtrlSendMsg($g_idPic, 0x0172, 0, $hBitmap) ; $STM_SETIMAGE = 0x0172, $IMAGE_BITMAP = 0 If $hPrevImage Then _WinAPI_DeleteObject($hPrevImage); delete prev image if any (help file) _WinAPI_DeleteObject($hBitmap) EndFunc ;==>Update_Pic Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) Local $hImage_resized = _GDIPlus_ImageResize($g_hImage, BitAND($lParam, 0xFFFF), BitShift($lParam, 16), 2) ; high-quality mode Update_Pic($hImage_resized) _GDIPlus_ImageDispose($hImage_resized) Return "GUI_RUNDEFMSG" EndFunc ;==>WM_SIZE
-
UEZ reacted to a post in a topic:
Testing fullscreen video capturing @ 60 FPS
-
@wakillon I can't thank you enough—you're the only tester! Indeed, 4:4:4 is flickering for me, too. Seems that I changed something without testing it. Hmmm. It's also strange that I can't see the system info section in the log file, even though you've obviously tested the latest version (AirCapRec v0.9.3 beta build 2026-06-02). I’ll include the app version number in the log so you can see which version was used. === AirCapRec session started 06-03-2026 20:19:02 === Log file: C:\_BZ25LN\Coding\FreeBASIC\__UEZ\_Tools\AirCapRec\AirCapRec_debug.log [sysinfo] Windows 10 Enterprise 25H2 (10.0 Build 26200.8390) [sysinfo] Architecture: x64 / 64-bit process [sysinfo] CPU: Intel(R) Core(TM) Ultra 5 135U (14 logical cores) [sysinfo] RAM: 15.5 GB (15892 MB) free 2.0 GB (2077 MB) (load 86%) [sysinfo] Commit/Pagefile: total 32.6 GB (33414 MB) free 7.3 GB (7504 MB) [sysinfo] Disk (EXE): C:\ free 20.5 GB (21047 MB) of 235.0 GB (240695 MB) [sysinfo] Disk (System): C:\ free 20.5 GB (21047 MB) of 235.0 GB (240695 MB) [sysinfo] Display: primary 1920x1080 virtual 1920x1080 monitors 1 DPI 96 (100%) [sysinfo] GPU: Intel(R) Graphics [sysinfo] Locale: de-DE [sysinfo] Camera(s): 1 [sysinfo] [0] Integrated Webcam [sysinfo] Uptime: 79h 19m [285548187] HighlightClicks=1 Origin=(0,0) MMCSS=1 [285548187] Audio requested: sys=1 mic=0 bitrate=128000 [285549265] Audio_Init OK [285549265] SR_Init OK: C:\_BZ25LN\Coding\FreeBASIC\__UEZ\_Tools\AirCapRec\Capture_20260603_201901.mp4 30fps CRF=32 preset=superfast tune=zerolatency audio=1 [285549265] SR_Start OK [285549281] Recording-Thread started [285549281] MMCSS AvSetMmThreadCharacteristicsW('Capture') = OK [285550609] Opening MP4: C:\_BZ25LN\Coding\FreeBASIC\__UEZ\_Tools\AirCapRec\Capture_20260603_201901.mp4 (1920x1080 @ 30fps) [285550609] MP4Min_Open OK [285555625] Ring stats: produced=72 dropped=60 consumed=70 filled=2 encFrames=149 repeated=50 duped=29 [285560671] Ring stats: produced=191 dropped=130 consumed=189 filled=2 encFrames=300 repeated=73 duped=38 [285561000] SR_Stop called - video frames=310 audio frames=443 [285561000] Final ring stats: produced=198 dropped=132 consumed=197 filled=1 [285561046] Recording-Thread done: total frames=311 repeated=74 realDuration=10.41174930002308s [285567296] HighlightClicks=1 Origin=(0,0) MMCSS=1 [285567296] Audio requested: sys=1 mic=0 bitrate=128000 [285567296] Audio_Init OK [285567296] SR_Init OK: C:\_BZ25LN\Coding\FreeBASIC\__UEZ\_Tools\AirCapRec\Capture_20260603_201922.mp4 30fps CRF=32 preset=superfast tune=zerolatency audio=1 [285567296] SR_Start OK [285567296] Recording-Thread started [285567296] MMCSS AvSetMmThreadCharacteristicsW('Capture') = OK [285567312] Opening MP4: C:\_BZ25LN\Coding\FreeBASIC\__UEZ\_Tools\AirCapRec\Capture_20260603_201922.mp4 (1920x1080 @ 30fps) [285567312] MP4Min_Open OK [285572312] Ring stats: produced=135 dropped=51 consumed=133 filled=2 encFrames=149 repeated=16 duped=0 [285577312] Ring stats: produced=263 dropped=98 consumed=263 filled=0 encFrames=299 repeated=36 duped=0 [285577718] SR_Stop called - video frames=311 audio frames=481 [285577718] Final ring stats: produced=276 dropped=102 consumed=274 filled=2 [285577781] Recording-Thread done: total frames=312 repeated=37 realDuration=10.45726320001995s [285582031] Drained 0 leftover slot(s) before cleanup === session ended === Thanks so much for your feedback! Edit: 4:4:4 flicker bug found and fixed -> new version uploaded