Jump to content

Recommended Posts

Posted (edited)

Because working with multiple monitors was required during the development of ImageSearchUDF , this UDF was created

UDF:

#include-once
#include <WinAPIGdi.au3>
#include <WinAPISysWin.au3>
#include <WindowsConstants.au3>

; ===============================================================================================================================
; Title .........: Monitor UDF
; Description ...: Provides advanced monitor management and multi-monitor utilities.
; Author ........: Dao Van Trong - TRONG.PRO
; <MonitorUDF.au3>
; ===============================================================================================================================
; FUNCTIONS SUMMARY
; ===============================================================================================================================
;   _Monitor_GetList()                     - Enumerate connected monitors and fill global info.
;   _Monitor_GetCount()                    - Return total number of monitors.
;   _Monitor_GetPrimary()                  - Get index of the primary monitor.
;   _Monitor_GetInfo($iMonitor)            - Get detailed info about a monitor.
;   _Monitor_GetBounds($iMonitor, ...)     - Get full monitor rectangle (including taskbar).
;   _Monitor_GetWorkArea($iMonitor, ...)   - Get working area of a monitor (excluding taskbar).
;   _Monitor_GetDisplaySettings($iMonitor) - Get current display mode.
;   _Monitor_GetResolution($iMonitor)      - Get monitor resolution.
;   _Monitor_GetFromPoint([$x, $y])        - Get monitor from screen point or mouse.
;   _Monitor_GetFromWindow($hWnd)          - Get monitor containing a specific window.
;   _Monitor_GetFromRect(...)              - Get monitor overlapping a given rectangle.
;   _Monitor_GetVirtualBounds()            - Get bounding rectangle of the entire virtual screen.
;   _Monitor_ToVirtual($iMonitor, $x, $y)  - Convert local monitor coordinates to virtual coordinates.
;   _Monitor_FromVirtual($iMonitor, $x, $y)- Convert from virtual to local monitor coordinates.
;   _Monitor_IsVisibleWindow($hWnd)        - Check if a window is top-level visible.
;   _Monitor_MoveWindowToScreen(...)       - Move a window to specific monitor (center if unspecified).
;   _Monitor_MoveWindowToAll(...)          - Move a visible window across all monitors.
;   _Monitor_EnumAllDisplayModes($iMonitor)- Enumerate all available display modes.
;   _Monitor_ShowInfo()                    - Show all monitor information in MsgBox.
; ===============================================================================================================================


#Region --- Global Variables ---
; ===============================================================================================================================
; Global Monitor Information Array
; ===============================================================================================================================
; $__g_aMonitorList[][] structure:
;
;   [0][0] = Number of monitors detected
;   [0][1] = Virtual desktop Left coordinate (combined area)
;   [0][2] = Virtual desktop Top coordinate
;   [0][3] = Virtual desktop Right coordinate
;   [0][4] = Virtual desktop Bottom coordinate
;   [0][5] = Virtual desktop Width
;   [0][6] = Virtual desktop Height
;
; For each monitor index i (1..$__g_aMonitorList[0][0]):
;   [i][0] = Monitor handle (HMONITOR)
;   [i][1] = Left coordinate of monitor
;   [i][2] = Top coordinate of monitor
;   [i][3] = Right coordinate of monitor
;   [i][4] = Bottom coordinate of monitor
;   [i][5] = IsPrimary (1 if primary, 0 otherwise)
;   [i][6] = Device name string (e.g. "\\.\DISPLAY1")
;
; Example:
;   ;If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList()
;   $__g_aMonitorList[0][0] = 2
;   $__g_aMonitorList[1] = [0x00010001, 0, 0, 1920, 1080, 1, "\\.\DISPLAY1"]
;   $__g_aMonitorList[2] = [0x00020002, 1920, 0, 3840, 1080, 0, "\\.\DISPLAY2"]
;
; ===============================================================================================================================
Global $__g_aMonitorList[1][7] = [[0, 0, 0, 0, 0, 0, ""]]
#EndRegion --- Global Variables ---


; ===============================================================================================================================
; FUNCTION: _Monitor_GetFromPoint([$iX = -1[, $iY = -1]])
; PURPOSE : Get the monitor index from a screen coordinate or current mouse position
; RETURN  : Monitor index (1..N) or 0 if not found
; ===============================================================================================================================
Func _Monitor_GetFromPoint($iX = -1, $iY = -1)
    If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList()

    ; Use WinAPI function if available
    If $iX = -1 Or $iY = -1 Then
        Local $aMouse = MouseGetPos()
        $iX = $aMouse[0]
        $iY = $aMouse[1]
    EndIf

    Local $tPoint = DllStructCreate($tagPOINT)
    DllStructSetData($tPoint, "X", $iX)
    DllStructSetData($tPoint, "Y", $iY)
    Local $hMonitor = _WinAPI_MonitorFromPoint($tPoint, $MONITOR_DEFAULTTONEAREST)

    ; Find index in our list
    For $i = 1 To $__g_aMonitorList[0][0]
        If $__g_aMonitorList[$i][0] = $hMonitor Then Return $i
    Next

    ; Fallback to coordinate checking
    For $i = 1 To $__g_aMonitorList[0][0]
        If $iX >= $__g_aMonitorList[$i][1] _
                And $iX < $__g_aMonitorList[$i][3] _
                And $iY >= $__g_aMonitorList[$i][2] _
                And $iY < $__g_aMonitorList[$i][4] Then
            Return $i
        EndIf
    Next
    Return 0
EndFunc   ;==>_Monitor_GetFromPoint

; ===============================================================================================================================
; FUNCTION: _Monitor_GetFromWindow($hWnd[, $iFlag = $MONITOR_DEFAULTTONEAREST])
; PURPOSE : Get the monitor index that contains the specified window
; RETURN  : Monitor index (1..N) or 0 if not found
; ===============================================================================================================================
Func _Monitor_GetFromWindow($hWnd, $iFlag = $MONITOR_DEFAULTTONEAREST)
    If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList()
    If Not IsHWnd($hWnd) Then $hWnd = WinGetHandle($hWnd)
    If Not $hWnd Then Return SetError(1, 0, 0)

    Local $hMonitor = _WinAPI_MonitorFromWindow($hWnd, $iFlag)
    If Not $hMonitor Then Return SetError(2, 0, 0)

    For $i = 1 To $__g_aMonitorList[0][0]
        If $__g_aMonitorList[$i][0] = $hMonitor Then Return $i
    Next
    Return 0
EndFunc   ;==>_Monitor_GetFromWindow

; ===============================================================================================================================
; FUNCTION: _Monitor_GetFromRect($iLeft, $iTop, $iRight, $iBottom[, $iFlag = $MONITOR_DEFAULTTONEAREST])
; PURPOSE : Get the monitor index that has the largest intersection with the specified rectangle
; RETURN  : Monitor index (1..N) or 0 if not found
; ===============================================================================================================================
Func _Monitor_GetFromRect($iLeft, $iTop, $iRight, $iBottom, $iFlag = $MONITOR_DEFAULTTONEAREST)
    If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList()

    Local $tRect = DllStructCreate($tagRECT)
    DllStructSetData($tRect, "Left", $iLeft)
    DllStructSetData($tRect, "Top", $iTop)
    DllStructSetData($tRect, "Right", $iRight)
    DllStructSetData($tRect, "Bottom", $iBottom)

    Local $hMonitor = _WinAPI_MonitorFromRect($tRect, $iFlag)
    If Not $hMonitor Then Return SetError(1, 0, 0)

    For $i = 1 To $__g_aMonitorList[0][0]
        If $__g_aMonitorList[$i][0] = $hMonitor Then Return $i
    Next
    Return 0
EndFunc   ;==>_Monitor_GetFromRect

; ===============================================================================================================================
; FUNCTION: _Monitor_GetWorkArea($iMonitor, ByRef $left, ByRef $top, ByRef $right, ByRef $bottom)
; PURPOSE : Get working area of a specific monitor (excluding taskbar)
; RETURN  : 1 on success, 0 on failure
; ===============================================================================================================================
Func _Monitor_GetWorkArea($iMonitor, ByRef $left, ByRef $top, ByRef $right, ByRef $bottom)
    If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList()
    If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0)

    Local $hMonitor = $__g_aMonitorList[$iMonitor][0]
    Local $aInfo = _WinAPI_GetMonitorInfo($hMonitor)
    If @error Then Return SetError(2, 0, 0)

    Local $tWorkArea = $aInfo[1]
    $left = DllStructGetData($tWorkArea, "Left")
    $top = DllStructGetData($tWorkArea, "Top")
    $right = DllStructGetData($tWorkArea, "Right")
    $bottom = DllStructGetData($tWorkArea, "Bottom")
    Return 1
EndFunc   ;==>_Monitor_GetWorkArea

; ===============================================================================================================================
; FUNCTION: _Monitor_GetBounds($iMonitor, ByRef $left, ByRef $top, ByRef $right, ByRef $bottom)
; PURPOSE : Get full bounds of a specific monitor (including taskbar)
; RETURN  : 1 on success, 0 on failure
; ===============================================================================================================================
Func _Monitor_GetBounds($iMonitor, ByRef $left, ByRef $top, ByRef $right, ByRef $bottom)
    If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList()
    If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0)

    $left = $__g_aMonitorList[$iMonitor][1]
    $top = $__g_aMonitorList[$iMonitor][2]
    $right = $__g_aMonitorList[$iMonitor][3]
    $bottom = $__g_aMonitorList[$iMonitor][4]
    Return 1
EndFunc   ;==>_Monitor_GetBounds

; ===============================================================================================================================
; FUNCTION: _Monitor_GetInfo($iMonitor)
; PURPOSE : Get detailed information about a monitor
; RETURN  : Array [Handle, Left, Top, Right, Bottom, WorkLeft, WorkTop, WorkRight, WorkBottom, IsPrimary, DeviceName]
; ===============================================================================================================================
Func _Monitor_GetInfo($iMonitor)
    If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList()
    If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0)

    Local $hMonitor = $__g_aMonitorList[$iMonitor][0]
    Local $aInfo = _WinAPI_GetMonitorInfo($hMonitor)
    If @error Then Return SetError(2, 0, 0)

    Local $tMonitorRect = $aInfo[0]
    Local $tWorkRect = $aInfo[1]

    Local $aResult[11]
    $aResult[0] = $hMonitor
    $aResult[1] = DllStructGetData($tMonitorRect, "Left")
    $aResult[2] = DllStructGetData($tMonitorRect, "Top")
    $aResult[3] = DllStructGetData($tMonitorRect, "Right")
    $aResult[4] = DllStructGetData($tMonitorRect, "Bottom")
    $aResult[5] = DllStructGetData($tWorkRect, "Left")
    $aResult[6] = DllStructGetData($tWorkRect, "Top")
    $aResult[7] = DllStructGetData($tWorkRect, "Right")
    $aResult[8] = DllStructGetData($tWorkRect, "Bottom")
    $aResult[9] = ($aInfo[2] <> 0) ; IsPrimary
    $aResult[10] = $aInfo[3] ; DeviceName

    Return $aResult
EndFunc   ;==>_Monitor_GetInfo

; ===============================================================================================================================
; FUNCTION: _Monitor_GetDisplaySettings($iMonitor[, $iMode = $ENUM_CURRENT_SETTINGS])
; PURPOSE : Get display settings for a monitor
; RETURN  : Array [Width, Height, BitsPerPixel, Frequency, DisplayMode]
; ===============================================================================================================================
Func _Monitor_GetDisplaySettings($iMonitor, $iMode = $ENUM_CURRENT_SETTINGS)
    If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList()
    If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0)

    Local $sDevice = $__g_aMonitorList[$iMonitor][6]
    If $sDevice = "" Then
        Local $aInfo = _Monitor_GetInfo($iMonitor)
        If @error Then Return SetError(2, 0, 0)
        $sDevice = $aInfo[10]
    EndIf

    Local $aSettings = _WinAPI_EnumDisplaySettings($sDevice, $iMode)
    If @error Then Return SetError(3, 0, 0)

    Return $aSettings
EndFunc   ;==>_Monitor_GetDisplaySettings

; ===============================================================================================================================
; FUNCTION: _Monitor_GetResolution($iMonitor)
; PURPOSE : Get resolution of a monitor
; RETURN  : Array [Width, Height]
; ===============================================================================================================================
Func _Monitor_GetResolution($iMonitor)
    If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList()
    If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0)

    Local $aSettings = _Monitor_GetDisplaySettings($iMonitor)
    If @error Then Return SetError(2, 0, 0)

    Local $aResult[2] = [$aSettings[0], $aSettings[1]]
    Return $aResult
EndFunc   ;==>_Monitor_GetResolution

; ===============================================================================================================================
; FUNCTION: _Monitor_GetPrimary()
; PURPOSE : Get the index of the primary monitor
; RETURN  : Monitor index (1..N) or 0 if not found
; ===============================================================================================================================
Func _Monitor_GetPrimary()
    If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList()

    For $i = 1 To $__g_aMonitorList[0][0]
        Local $aInfo = _Monitor_GetInfo($i)
        If Not @error And $aInfo[9] = 1 Then Return $i
    Next
    Return 0
EndFunc   ;==>_Monitor_GetPrimary

; ===============================================================================================================================
; FUNCTION: _Monitor_GetCount()
; PURPOSE : Returns total number of monitors
; ===============================================================================================================================
Func _Monitor_GetCount()
    Local $aRet = DllCall("user32.dll", "int", "GetSystemMetrics", "int", $SM_CMONITORS)
    If @error Or Not IsArray($aRet) Then
        If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList()
        Return $__g_aMonitorList[0][0]
    Else
        Return $aRet[0]
    EndIf
EndFunc   ;==>_Monitor_GetCount

; ===============================================================================================================================
; FUNCTION: _Monitor_GetVirtualBounds()
; PURPOSE : Get bounding rectangle of all monitors (the "virtual screen")
; RETURN  : Array [Left, Top, Width, Height]
; ===============================================================================================================================
Func _Monitor_GetVirtualBounds()
    Local $aL = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 76) ; SM_XVIRTUALSCREEN
    Local $aT = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 77) ; SM_YVIRTUALSCREEN
    Local $aW = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 78) ; SM_CXVIRTUALSCREEN
    Local $aH = DllCall("user32.dll", "int", "GetSystemMetrics", "int", 79) ; SM_CYVIRTUALSCREEN
    Local $a[4] = [$aL[0], $aT[0], $aW[0], $aH[0]]
    Return $a
EndFunc   ;==>_Monitor_GetVirtualBounds

; ===============================================================================================================================
; FUNCTION: _Monitor_ToVirtual($iMonitor, $x, $y)
; PURPOSE : Convert local monitor coordinates to virtual screen coordinates
; ===============================================================================================================================
Func _Monitor_ToVirtual($iMonitor, $x, $y)
    If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList()
    If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0)
    Local $aRet[2] = [$__g_aMonitorList[$iMonitor][1] + $x, $__g_aMonitorList[$iMonitor][2] + $y]
    Return $aRet
EndFunc   ;==>_Monitor_ToVirtual

; ===============================================================================================================================
; FUNCTION: _Monitor_FromVirtual($iMonitor, $x, $y)
; PURPOSE : Convert virtual coordinates back to local monitor coordinates
; ===============================================================================================================================
Func _Monitor_FromVirtual($iMonitor, $x, $y)
    If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList()
    If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0)
    Local $aRet[2] = [$x - $__g_aMonitorList[$iMonitor][1], $y - $__g_aMonitorList[$iMonitor][2]]
    Return $aRet
EndFunc   ;==>_Monitor_FromVirtual

; ===============================================================================================================================
; FUNCTION: _Monitor_IsVisibleWindow($hWnd)
; PURPOSE : Check if window is visible and top-level
; RETURN  : True / False
; ===============================================================================================================================
Func _Monitor_IsVisibleWindow($hWnd)
    If Not IsHWnd($hWnd) Then $hWnd = WinGetHandle($hWnd)
    If Not $hWnd Or Not WinExists($hWnd) Then Return False
    Local $style = _WinAPI_GetWindowLong($hWnd, $GWL_STYLE)
    If BitAND($style, $WS_VISIBLE) = 0 Then Return False
    If BitAND($style, $WS_CHILD) <> 0 Then Return False
    Local $ex = _WinAPI_GetWindowLong($hWnd, $GWL_EXSTYLE)
    If BitAND($ex, $WS_EX_TOOLWINDOW) <> 0 Then Return False
    Return True
EndFunc   ;==>_Monitor_IsVisibleWindow

; ===============================================================================================================================
; FUNCTION: _Monitor_MoveWindowToScreen($vTitle, $sText = "", $iMonitor = -1, $x = -1, $y = -1, $bUseWorkArea = True)
; PURPOSE : Move visible window to a monitor (centered if $x=$y=-1)
; ===============================================================================================================================
Func _Monitor_MoveWindowToScreen($vTitle, $sText = "", $iMonitor = -1, $x = -1, $y = -1, $bUseWorkArea = True)
    Local $hWnd = IsHWnd($vTitle) ? $vTitle : WinGetHandle($vTitle, $sText)
    If Not _Monitor_IsVisibleWindow($hWnd) Then Return SetError(1, 0, 0)

    If $iMonitor = -1 Then $iMonitor = 1
    If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList()
    If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(2, 0, 0)

    Local $aWinPos = WinGetPos($hWnd)
    If @error Or Not IsArray($aWinPos) Then Return SetError(3, 0, 0)

    Local $iLeft, $iTop, $iRight, $iBottom
    If $bUseWorkArea Then
        _Monitor_GetWorkArea($iMonitor, $iLeft, $iTop, $iRight, $iBottom)
    Else
        _Monitor_GetBounds($iMonitor, $iLeft, $iTop, $iRight, $iBottom)
    EndIf

    Local $iWidth = $iRight - $iLeft
    Local $iHeight = $iBottom - $iTop

    If $x = -1 Or $y = -1 Then
        $x = $iLeft + ($iWidth - $aWinPos[2]) / 2
        $y = $iTop + ($iHeight - $aWinPos[3]) / 2
    Else
        $x += $iLeft
        $y += $iTop
    EndIf

    WinMove($hWnd, "", $x, $y)
    Return 1
EndFunc   ;==>_Monitor_MoveWindowToScreen

; ===============================================================================================================================
; FUNCTION: _Monitor_MoveWindowToAll($vTitle, $sText = "", $bCenter = True, $iDelay = 1000)
; PURPOSE : Move a visible window sequentially across all monitors
; ===============================================================================================================================
Func _Monitor_MoveWindowToAll($vTitle, $sText = "", $bCenter = True, $iDelay = 1000)
    Local $hWnd = IsHWnd($vTitle) ? $vTitle : WinGetHandle($vTitle, $sText)
    If Not _Monitor_IsVisibleWindow($hWnd) Then Return SetError(1, 0, 0)
    If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList()

    For $i = 1 To $__g_aMonitorList[0][0]
        If $bCenter Then
            _Monitor_MoveWindowToScreen($hWnd, "", $i)
        Else
            _Monitor_MoveWindowToScreen($hWnd, "", $i, 50, 50)
        EndIf
        Sleep($iDelay)
    Next
    Return 1
EndFunc   ;==>_Monitor_MoveWindowToAll

; ===============================================================================================================================
; FUNCTION: _Monitor_EnumAllDisplayModes($iMonitor)
; PURPOSE : Enumerate all available display modes for a monitor
; RETURN  : 2D array [[Width, Height, BitsPerPixel, Frequency, DisplayMode], ...]
; ===============================================================================================================================
Func _Monitor_EnumAllDisplayModes($iMonitor)
    If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList()
    If $iMonitor < 1 Or $iMonitor > $__g_aMonitorList[0][0] Then Return SetError(1, 0, 0)

    Local $aInfo = _Monitor_GetInfo($iMonitor)
    If @error Then Return SetError(2, 0, 0)
    Local $sDevice = $aInfo[10]

    Local $aModes[1][5]
    $aModes[0][0] = 0
    Local $iIndex = 0

    While True
        Local $aMode = _WinAPI_EnumDisplaySettings($sDevice, $iIndex)
        If @error Then ExitLoop

        ReDim $aModes[$aModes[0][0] + 2][5]
        $aModes[0][0] += 1
        $aModes[$aModes[0][0]][0] = $aMode[0]
        $aModes[$aModes[0][0]][1] = $aMode[1]
        $aModes[$aModes[0][0]][2] = $aMode[2]
        $aModes[$aModes[0][0]][3] = $aMode[3]
        $aModes[$aModes[0][0]][4] = $aMode[4]

        $iIndex += 1
    WEnd

    If $aModes[0][0] = 0 Then Return SetError(3, 0, 0)
    Return $aModes
EndFunc   ;==>_Monitor_EnumAllDisplayModes

; ===============================================================================================================================
; FUNCTION: _Monitor_GetList()
; PURPOSE : Enumerate connected monitors and fill the global list using _WinAPI_EnumDisplayMonitors
; RETURN  : Number of monitors, or -1 on error
; ===============================================================================================================================
Func _Monitor_GetList()
    Local $aMonitors = _WinAPI_EnumDisplayMonitors()
    If @error Then Return SetError(1, 0, -1)

    ReDim $__g_aMonitorList[$aMonitors[0][0] + 1][7]
    $__g_aMonitorList[0][0] = $aMonitors[0][0]

    Local $l_aVirtual = _Monitor_GetVirtualBounds()
    Local $l_vRight = $l_aVirtual[0] + $l_aVirtual[2]
    Local $l_vBottom = $l_aVirtual[1] + $l_aVirtual[3]
    $__g_aMonitorList[0][1] = $l_aVirtual[0]
    $__g_aMonitorList[0][2] = $l_aVirtual[1]
    $__g_aMonitorList[0][3] = $l_vRight
    $__g_aMonitorList[0][4] = $l_vBottom
    $__g_aMonitorList[0][5] = $l_aVirtual[2]
    $__g_aMonitorList[0][6] = $l_aVirtual[3]

    For $i = 1 To $aMonitors[0][0]
        Local $hMonitor = $aMonitors[$i][0]
        Local $tRect = $aMonitors[$i][1]

        $__g_aMonitorList[$i][0] = $hMonitor
        $__g_aMonitorList[$i][1] = DllStructGetData($tRect, "Left")
        $__g_aMonitorList[$i][2] = DllStructGetData($tRect, "Top")
        $__g_aMonitorList[$i][3] = DllStructGetData($tRect, "Right")
        $__g_aMonitorList[$i][4] = DllStructGetData($tRect, "Bottom")

        ; Get additional info
        Local $aInfo = _WinAPI_GetMonitorInfo($hMonitor)
        If Not @error Then
            Local $tWorkRect = $aInfo[1]
            $__g_aMonitorList[$i][5] = DllStructGetPtr($tWorkRect)
            $__g_aMonitorList[$i][6] = $aInfo[3] ; Device name
        EndIf
    Next

    Return $__g_aMonitorList[0][0]
EndFunc   ;==>_Monitor_GetList

; ===============================================================================================================================
; FUNCTION: _Monitor_ShowInfo($iTimeout = 10)
; PURPOSE : Show monitor coordinates and detailed information
; ===============================================================================================================================
Func _Monitor_ShowInfo($Msg = 1, $iTimeout = 10)
    If $__g_aMonitorList[0][0] = 0 Then _Monitor_GetList()
    Local $sMsg = "> Total Monitors: " & $__g_aMonitorList[0][0] & @CRLF & @CRLF
    $sMsg &= StringFormat("+ Virtual Desktop: " & @CRLF & "Left=%d, Top=%d, Right=%d, Bottom=%d, Width=%d, Height=%d", $__g_aMonitorList[0][1], $__g_aMonitorList[0][2], $__g_aMonitorList[0][3], $__g_aMonitorList[0][4], $__g_aMonitorList[0][5], $__g_aMonitorList[0][6]) & @CRLF & @CRLF ;

    For $i = 1 To $__g_aMonitorList[0][0]
        Local $aInfo = _Monitor_GetInfo($i)
        If @error Then ContinueLoop

        Local $aSettings = _Monitor_GetDisplaySettings($i)
        Local $sResolution = @error ? "N/A" : $aSettings[0] & "x" & $aSettings[1] & " @" & $aSettings[3] & "Hz"

        $sMsg &= StringFormat("+ Monitor %d: %s%s\n", $i, $aInfo[9] ? "(Primary) " : "", $aInfo[10])
        $sMsg &= StringFormat("  Bounds: L=%d, T=%d, R=%d, B=%d (%dx%d)\n", _
                $aInfo[1], $aInfo[2], $aInfo[3], $aInfo[4], _
                $aInfo[3] - $aInfo[1], $aInfo[4] - $aInfo[2])
        $sMsg &= StringFormat("  Work Area: L=%d, T=%d, R=%d, B=%d (%dx%d)\n", _
                $aInfo[5], $aInfo[6], $aInfo[7], $aInfo[8], _
                $aInfo[7] - $aInfo[5], $aInfo[8] - $aInfo[6])
        $sMsg &= "  Resolution: " & $sResolution & @CRLF & @CRLF
    Next
    ConsoleWrite($sMsg)
    If $Msg Then MsgBox(64 + 262144, "Monitor Information", $sMsg, $iTimeout)
    Return $sMsg
EndFunc   ;==>_Monitor_ShowInfo


;~ _Monitor_ShowInfo(1, 3)

EG:

; ==================================================================================================
; MonitorUDF_Examples.au3
; Interactive example tester for MonitorUDF.au3 UDF (fixed: uses GuiListBox functions correctly)
; ==================================================================================================


#include <GUIConstantsEx.au3>
#include <ButtonConstants.au3>
#include <WindowsConstants.au3>
#include <GuiListBox.au3>
#include <GuiEdit.au3>
#include <Array.au3>
#include "MonitorUDF.au3" ; make sure this file is In the same folder

; ==================================================================================================
; MonitorUDF_Examples.au3
; Interactive tester with buttons for each MonitorUDF function + log edit
; Requires: MonitorUDF.au3 in the same folder
; ==================================================================================================


; -----------------------------
; Create GUI
; -----------------------------
Global $GUI_W = 560, $GUI_H = 540
Global $hGUI = GUICreate("MonitorUDF - Examples (by TRONG.PRO)", $GUI_W, $GUI_H, -1, -1)
GUISetBkColor(0xF5F5F5, $hGUI)

; Title
GUICtrlCreateLabel("MonitorUDF Example Launcher", 12, 10, 400, 24)
GUICtrlSetFont(-1, 12, 800, 0, 'Segoe UI', 5)

; Buttons column 1
Local $x1 = 12, $y1 = 48, $bw = 260, $bh = 36, $gap = 8
Global $iBtn1 = GUICtrlCreateButton("1. Enumerate monitors", $x1, $y1, $bw, $bh)
Global $iBtn2 = GUICtrlCreateButton("2. Move Notepad -> Monitor #2 (center)", $x1, $y1 + ($bh + $gap) * 1, $bw, $bh)
Global $iBtn3 = GUICtrlCreateButton("3. Move Notepad -> Monitor #2 @ (100,100)", $x1, $y1 + ($bh + $gap) * 2, $bw, $bh)
Global $iBtn4 = GUICtrlCreateButton("4. Which monitor is mouse on?", $x1, $y1 + ($bh + $gap) * 3, $bw, $bh)
Global $iBtn5 = GUICtrlCreateButton("5. Show virtual desktop bounds", $x1, $y1 + ($bh + $gap) * 4, $bw, $bh)

; Buttons column 2
Local $x2 = $x1 + $bw + 12
Global $iBtn6 = GUICtrlCreateButton("6. Convert coords (local <-> virtual)", $x2, $y1 + ($bh + $gap) * 0, $bw, $bh)
Global $iBtn7 = GUICtrlCreateButton("7. Show monitor info (MsgBox)", $x2, $y1 + ($bh + $gap) * 1, $bw, $bh)
Global $iBtn8 = GUICtrlCreateButton("8. Check if Notepad is visible", $x2, $y1 + ($bh + $gap) * 2, $bw, $bh)
Global $iBtn9 = GUICtrlCreateButton("9. Move all visible windows -> primary", $x2, $y1 + ($bh + $gap) * 3, $bw, $bh)
Global $iBtn10 = GUICtrlCreateButton("10. Create small GUI on each monitor", $x2, $y1 + ($bh + $gap) * 4, $bw, $bh)

; Controls: log edit, clear, auto-demo, close
Local $logX = 12, $logY = $y1 + ($bh + $gap) * 6
Local $logW = $GUI_W - 24, $logH = 180
Global $idLog = GUICtrlCreateEdit("", $logX, $logY, $logW, $logH, BitOR($ES_READONLY, $WS_HSCROLL, $WS_VSCROLL, $ES_MULTILINE))
GUICtrlSetFont($idLog, 9)
Global $idFuncTest__ClearLog = GUICtrlCreateButton("Clear Log", 12, $logY + $logH + 10, 120, 28)
Global $idFuncTest__RunAllDemo = GUICtrlCreateButton("Auto Demo (Run 1..10)", 150, $logY + $logH + 10, 220, 28)
Global $idFuncTest__Close = GUICtrlCreateButton("Close", $GUI_W - 120, $logY + $logH + 10, 100, 28)
Global $pidNotepad = 0
GUISetState(@SW_SHOW)

; Keep a list of created GUIs for Example 10 so we can close them later
Global $Msg, $g_createdGUIs = []

; -----------------------------
; Main loop
; -----------------------------
While 1
    $Msg = GUIGetMsg()
    Switch $Msg
        Case $GUI_EVENT_CLOSE, $idFuncTest__Close
            ; close any GUIs created in example 10
            For $i = 0 To UBound($g_createdGUIs) - 1
                If IsHWnd($g_createdGUIs[$i]) Then GUIDelete($g_createdGUIs[$i])
            Next
            ExitLoop
        Case $idFuncTest__ClearLog
            GUICtrlSetData($idLog, '', '')
        Case $idFuncTest__RunAllDemo
            FuncTest_1()
            Sleep(1000) ; $iBtn2
            FuncTest_2()
            Sleep(2000) ; $iBtn3
            ProcessClose($pidNotepad)
            FuncTest_3()
            Sleep(2000) ; $iBtn4
            ProcessClose($pidNotepad)
            FuncTest_4()
            Sleep(1000) ; $iBtn5
            FuncTest_5()
            Sleep(1000) ; $iBtn6
            FuncTest_6()
            Sleep(1000) ; $iBtn7
            FuncTest_7()
            Sleep(1000) ; $iBtn8
            FuncTest_8()
            Sleep(2000) ; $iBtn9
            ProcessClose($pidNotepad)
            FuncTest_9()
            Sleep(1000) ; $iBtn10
            FuncTest_10()
            Sleep(2000) ; $iBtn10
            For $i = 0 To UBound($g_createdGUIs) - 1
                If IsHWnd($g_createdGUIs[$i]) Then GUIDelete($g_createdGUIs[$i])
            Next

        Case $iBtn1
            FuncTest_1()
        Case $iBtn2
            FuncTest_2()
        Case $iBtn3
            FuncTest_3()
        Case $iBtn4
            FuncTest_4()
        Case $iBtn5
            FuncTest_5()
        Case $iBtn6
            FuncTest_6()
        Case $iBtn7
            FuncTest_7()
        Case $iBtn8
            FuncTest_8()
        Case $iBtn9
            FuncTest_9()
        Case $iBtn10
            FuncTest_10()
    EndSwitch
    Sleep(5)
WEnd

GUIDelete()
Exit 0

; -----------------------------
; Helper: append to log (with timestamp)
; -----------------------------
Func _Log($s)
    ConsoleWrite($s & @CRLF)
    Local $t = @HOUR & ":" & @MIN & ":" & @SEC
    Local $cur = GUICtrlRead($idLog)
    If $cur = "" Then
        GUICtrlSetData($idLog, "[" & $t & "] " & $s)
    Else
        GUICtrlSetData($idLog, $cur & @CRLF & "[" & $t & "] " & $s)
    EndIf
    ; move caret to end
    _GUICtrlEdit_LineScroll($idLog, 0, _GUICtrlEdit_GetLineCount($idLog))
EndFunc   ;==>_Log

Func FuncTest_1()
    _Log('+ TEST 1: Enumerate monitors -----------------------\')
    ; Enumerate monitors
    _Monitor_GetList()
    Local $cnt = _Monitor_GetCount()
    _Log("---> Example 1: Monitors detected: " & $cnt)
    For $i = 1 To $cnt
        Local $a = _Monitor_GetInfo($i)
        _Log("  Monitor " & $i & ": Device=" & $a[10] & " Bounds=(" & $a[1] & "," & $a[2] & ")-(" & $a[3] & "," & $a[4] & ") Work=(" & $a[5] & "," & $a[6] & ")-(" & $a[7] & "," & $a[8] & ") Primary=" & $a[9])
    Next
    _Log('- End ------------------------------------------------/')
EndFunc   ;==>FuncTest_1

Func FuncTest_2()
    _Log('+ TEST 2: Move Notepad to monitor #2 centered ------\')
    ; Move Notepad to monitor #2 centered
    $pidNotepad = Run("notepad.exe")
    If Not WinWaitActive("[CLASS:Notepad]", "", 5) Then
        _Log("---> Example 2: Notepad did not start / focus")
    Else
        Sleep(1000)
        _Monitor_GetList()
        If _Monitor_GetCount() < 2 Then
            _Log("---> Example 2: Need at least 2 monitors")
        Else
            _Monitor_MoveWindowToScreen("[CLASS:Notepad]", "", 2, -1, -1, True)
            _Log("---> Example 2: Notepad moved to monitor #2 (centered)")
        EndIf
    EndIf
    _Log('- End ------------------------------------------------/')
EndFunc   ;==>FuncTest_2

Func FuncTest_3()
    _Log('+ TEST 3: Move Notepad to monitor #2 at (100,100 ----\)')
    ; Move Notepad to monitor #2 at (100,100)
    $pidNotepad = Run("notepad.exe")
    If Not WinWaitActive("[CLASS:Notepad]", "", 5) Then
        _Log("---> Example 3: Notepad did not start / focus")
    Else
        Sleep(1000)
        _Monitor_GetList()
        If _Monitor_GetCount() < 2 Then
            _Log("---> Example 3: Need at least 2 monitors")
        Else
            _Monitor_MoveWindowToScreen("[CLASS:Notepad]", "", 2, 100, 100, True)
            _Log("---> Example 3: Notepad moved to monitor #2 at (100,100)")
        EndIf
    EndIf
    _Log('- End ------------------------------------------------/')
EndFunc   ;==>FuncTest_3

Func FuncTest_4()
    _Log('+ TEST 4: Which monitor is mouse on ------------------\')
    ; Which monitor is mouse on
    _Monitor_GetList()
    Local $m = _Monitor_GetFromPoint()
    _Log("---> Example 4: Mouse is on monitor #" & $m)
    MsgBox(64, "Example 4", "Mouse is on monitor #" & $m, 2)
    _Log('- End ------------------------------------------------/')
EndFunc   ;==>FuncTest_4

Func FuncTest_5()
    _Log('+ TEST 5: Virtual desktop bounds -----------------------\')
    ; Virtual desktop bounds
    Local $aV = _Monitor_GetVirtualBounds()
    _Log("---> Example 5: Virtual bounds L=" & $aV[0] & " T=" & $aV[1] & " W=" & $aV[2] & " H=" & $aV[3])
    MsgBox(64, "Example 6", "Virtual Desktop Bounds. See log.", 2)
    _Log('- End ------------------------------------------------/')

EndFunc   ;==>FuncTest_5

Func FuncTest_6()
    _Log('+ TEST 6: Convert coords example (local -> virtual -> back) --\')
    ; Convert coords example (local -> virtual -> back)
    _Monitor_GetList()
    Local $mon = _Monitor_GetCount()
    If $mon < 1 Then
        _Log("---> Example 6: No monitors detected")
    Else
        For $i = 1 To $mon
            Local $xLocal = 50, $yLocal = 100
            Local $aV = _Monitor_ToVirtual($i, $xLocal, $yLocal)
            Local $aBack = _Monitor_FromVirtual($i, $aV[0], $aV[1])
            _Log("---> Example 6: Mon " & $i & " local(" & $xLocal & "," & $yLocal & ") -> virtual(" & $aV[0] & "," & $aV[1] & ") -> back(" & $aBack[0] & "," & $aBack[1] & ")")
        Next
        MsgBox(64, "Example 6", "Converted. See log.", 2)
    EndIf
    _Log('- End --------------------------------------------------------/')
EndFunc   ;==>FuncTest_6

Func FuncTest_7()
    _Log('+ TEST 7: Show detailed info via MsgBox (calls UDF) ------\')
    ; Show detailed info via MsgBox (calls UDF)
    _Monitor_GetList()
    _Monitor_ShowInfo(2)
    _Log("---> Example 7: _Monitor_ShowInfo() called")
    _Log('- End ------------------------------------------------/')
EndFunc   ;==>FuncTest_7

Func FuncTest_8()
    _Log('+ TEST 8: Start notepad, check visible ---------------\')
    ; Start notepad, check visible
    $pidNotepad = Run("notepad.exe")
    If Not WinWaitActive("[CLASS:Notepad]", "", 5) Then
        _Log("---> Example 8: Notepad did not start/focus")
    Else
        Sleep(1000)
        Local $h = WinGetHandle("[CLASS:Notepad]")
        Local $b = _Monitor_IsVisibleWindow($h)
        _Log("---> Example 8: Notepad handle " & $h & " visible? " & ($b ? "Yes" : "No"))
        MsgBox(64, "Example 8", "Notepad visible? " & ($b ? "Yes" : "No"), 2)
    EndIf
    _Log('- End ------------------------------------------------/')
EndFunc   ;==>FuncTest_8

Func FuncTest_9()
    _Log('+ TEST 9: Create small GUI on each monitor -------------\')
    ; Create small GUI on each monitor
    _Monitor_GetList()
    ; close previously created
    For $i = 0 To UBound($g_createdGUIs) - 1
        If IsHWnd($g_createdGUIs[$i]) Then GUIDelete($g_createdGUIs[$i])
    Next
    ReDim $g_createdGUIs[1]         ; reset
    Local $created = 0
    For $i = 1 To _Monitor_GetCount()
        Local $a = _Monitor_GetInfo($i)
        Local $h = GUICreate("Monitor #" & $i & " - " & $a[10], 260, 120, $a[1] + 40, $a[2] + 40)
        GUICtrlCreateLabel("Monitor " & $i & ($a[9] ? " (Primary)" : ""), 10, 12, 240, 20)
        GUISetState(@SW_SHOW, $h)
        ; store to close later
        __ArrayAdd($g_createdGUIs, $h)
        $created += 1
    Next
    _Log("---> Example 9: Created " & $created & " GUI(s) on monitors. Use Close to exit (they will be closed).")
    MsgBox(64, "Example 9", "Created " & $created & " GUIs (they will be closed when you close this launcher).", 2)

    _Log('- End ------------------------------------------------/')
EndFunc   ;==>FuncTest_9

Func FuncTest_10()
    _Log('+ TEST 10: Move all visible windows to primary ----------\')
    ; Move all visible windows to primary
    _Monitor_GetList()
    Local $prim = _Monitor_GetPrimary()
    If $prim = 0 Then
        _Log("---> Example 10: Primary monitor not found")
    Else
        Local $aList = WinList()
        Local $moved = 0
        For $i = 1 To $aList[0][0]
            If $aList[$i][0] <> "" Then
                Local $h = WinGetHandle($aList[$i][1])
                If _Monitor_IsVisibleWindow($h) Then
                    _Monitor_MoveWindowToScreen($h, "", $prim)
                    $moved += 1
                EndIf
            EndIf
        Next
        _Log("---> Example 10: Moved " & $moved & " visible windows to primary monitor #" & $prim)
        MsgBox(64, "Example 10", "Moved " & $moved & " visible windows to primary monitor #" & $prim, 2)
    EndIf
    _Log('- End ------------------------------------------------/')
EndFunc   ;==>FuncTest_10

; -----------------------------
; Small helper to push item into dynamic array (simple)
; -----------------------------
Func __ArrayAdd(ByRef $a, $v)
    Local $n = 0
    If IsArray($a) Then $n = UBound($a)
    ReDim $a[$n + 1]
    $a[$n] = $v
EndFunc   ;==>__ArrayAdd

 

 

Edited by Trong
fix code

Enjoy my work? Buy me a 🍻 or tip via ❤️ PayPal

Posted
16 hours ago, Trong said:
_Monitor_MoveWindowToAll

In this function here, does it display the same GUI window identically on all monitors?

Or does it split up the GUI window evenly so that different parts on the window are visible on each monitor?

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   1 member

×
×
  • Create New...