Sign in to follow this  
Followers 0

Dual-Monitor Resolution Detection

6 posts in this topic

Posted

I'm writing an application to help me manage the window position of a game (World of Warcraft, for those interested). My current code is bulkier than I'd like, and uses a dead-reckoning system I'm not fond of. For example, if I want it on my second monitor taking up half the screen, placed in the top right corner, i have to do WinMove("World of Warcraft", "", 2080,0,640,512). I'd like to use WinMove("World of Warcraft","",$X1+$X2/2,0,$X2/2,$Y2/2) instead so that if I change my resolution or begin distributing the app, it's one less thing I have to worry about.

In my code, I need to find a way to replace "Unknown" with a variable that represents a numerical value.

I haven't yet added support for a vertical montior config, but if I can solidify this part of the code I'll expand it as needed, and I know where to come if I need help =)

$FW = DLLCall("user32.dll", "int", "GetSystemMetrics", "int", 78)
 $FH = DLLCall("user32.dll", "int", "GetSystemMetrics", "int", 79)
 $XA = @DesktopWidth
 $YA = @DesktopHeight
 $WA = $FW[0]
 $HA = $FH[0]
 
 If $WA > $XA Then
	 $X1 = $XA
	 $X2 = $WA-$XA
 ElseIf $WA = $XA Then
	 $X1 = $XA
	 $X2 = "Unknown"
 EndIf
 
 If $HA > $YA Then
	 $Y1 = $YA
	 $Y2 = $HA
 ElseIf $HA = $YA Then
	 $Y1 = $YA
	 $Y2 = "Unknown"
 EndIf
	 
 MsgBox(0,"","Monitor A: " & $X1 & " by " & $Y1 & @LF & "Monitor B: " & $X2 & " by " & $Y2)

Share this post


Link to post
Share on other sites



Posted

I'm writing an application to help me manage the window position of a game (World of Warcraft, for those interested). My current code is bulkier than I'd like, and uses a dead-reckoning system I'm not fond of. For example, if I want it on my second monitor taking up half the screen, placed in the top right corner, i have to do WinMove("World of Warcraft", "", 2080,0,640,512). I'd like to use WinMove("World of Warcraft","",$X1+$X2/2,0,$X2/2,$Y2/2) instead so that if I change my resolution or begin distributing the app, it's one less thing I have to worry about.

In my code, I need to find a way to replace "Unknown" with a variable that represents a numerical value.

I haven't yet added support for a vertical montior config, but if I can solidify this part of the code I'll expand it as needed, and I know where to come if I need help =)

$FW = DLLCall("user32.dll", "int", "GetSystemMetrics", "int", 78)
 $FH = DLLCall("user32.dll", "int", "GetSystemMetrics", "int", 79)
 $XA = @DesktopWidth
 $YA = @DesktopHeight
 $WA = $FW[0]
 $HA = $FH[0]
 
 If $WA > $XA Then
	 $X1 = $XA
	 $X2 = $WA-$XA
 ElseIf $WA = $XA Then
	 $X1 = $XA
	 $X2 = "Unknown"
 EndIf
 
 If $HA > $YA Then
	 $Y1 = $YA
	 $Y2 = $HA
 ElseIf $HA = $YA Then
	 $Y1 = $YA
	 $Y2 = "Unknown"
 EndIf
	 
 MsgBox(0,"","Monitor A: " & $X1 & " by " & $Y1 & @LF & "Monitor B: " & $X2 & " by " & $Y2)
Here's a WMI query that can give you the monitor number and its dimensions:

CODE
$strComputer = "."

$objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $strComputer & "\root\cimv2")

$colItems = $objWMIService.ExecQuery("Select * from Win32_DesktopMonitor")

$sMsg = ""

For $objItem In $colItems

$sMsg &= "****************************" & @CRLF

$sMsg &= "Monitor: " & $objItem.DeviceID & @CRLF

$sMsg &= "****************************" & @CRLF

$sMsg &= "Description: " & $objItem.Description & @CRLF

$sMsg &= "Device ID: " & $objItem.DeviceID & @CRLF

$sMsg &= "Monitor Manufacturer: " & $objItem.MonitorManufacturer & @CRLF

$sMsg &= "Monitor Type: " & $objItem.MonitorType & @CRLF

$sMsg &= "Name: " & $objItem.Name & @CRLF

$sMsg &= "Screen Height: " & $objItem.ScreenHeight & @CRLF

$sMsg &= "Screen Width: " & $objItem.ScreenWidth & @CRLF

Next

ConsoleWrite($sMsg & @CRLF)

Share this post


Link to post
Share on other sites

Posted

Interesting...I'll have to do some digging to learn exactly how this works but for now it gets the job done. Here's how I adapted the code to fit my needs:

$strComputer = "."
$objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $strComputer & "\root\cimv2")
$colItems = $objWMIService.ExecQuery("Select * from Win32_DesktopMonitor")

$i = 0
For $objItem In $colItems
$i = $i + 1
Next
Global $w[$i], $h[$i]
$j = $i-1
$i = 0
For $objItem In $colItems
$w[$i] = $objItem.ScreenWidth
$h[$i] = $objItem.ScreenHeight
$i = $i + 1
Next

For $n = 0 to $j
MsgBox(0,"",$w[$n] & "x" & $h[$n])
Next

I know there has to be a shorter way to make this work but I can't figure it out. Any ideas?

Share this post


Link to post
Share on other sites

Posted

Global Const $SM_VIRTUALWIDTH = 78

Global Const $SM_VIRTUALHEIGHT = 79

$VIRTUALDESKTOPWIDTH = DLLCall("user32.dll","int","GetSystemMetrics","int",$SM_VIRTUALWIDTH)

$VIRTUALDESKTOPWIDTH = $VIRTUALDESKTOPWIDTH[0]

$VIRTUALDESKTOPHEIGHT = DLLCall("user32.dll","int","GetSystemMetrics","int",$SM_VIRTUALHEIGHT)

$VIRTUALDESKTOPHEIGHT = $VIRTUALDESKTOPHEIGHT[0]

Share this post


Link to post
Share on other sites

Posted

Global Const $SM_VIRTUALWIDTH = 78

Global Const $SM_VIRTUALHEIGHT = 79

$VIRTUALDESKTOPWIDTH = DLLCall("user32.dll","int","GetSystemMetrics","int",$SM_VIRTUALWIDTH)

$VIRTUALDESKTOPWIDTH = $VIRTUALDESKTOPWIDTH[0]

$VIRTUALDESKTOPHEIGHT = DLLCall("user32.dll","int","GetSystemMetrics","int",$SM_VIRTUALHEIGHT)

$VIRTUALDESKTOPHEIGHT = $VIRTUALDESKTOPHEIGHT[0]

As posted above:

$FW = DLLCall("user32.dll", "int", "GetSystemMetrics", "int", 78)
 $FH = DLLCall("user32.dll", "int", "GetSystemMetrics", "int", 79)
 $WA = $FW[0]
 $HA = $FH[0]

This code retrieves the total size of the V-Desktop. I need the width/height of each monitor being used, so I used the concept from Monamo's code to write a working script (posted above), but the code seems a little bulkier than it needs to be. I was wondering if there was a cleaner way of writing it that uses a better grasp on the concept which I don't have at the moment. The end result should be close to or the same as it is right now, giving me an array of width/height values.

Share this post


Link to post
Share on other sites

Posted (edited)

I use enumdisplaymonitors for this purpose, (I have a number of scripts to start apps on specific monitors, or on the monitor the mouse is on (from toolbars or other apps tool menus etc.))

here is the MultiMon.au3 I wrote and am currently using (could have a whole bunch more capability, but does what i need it to, the one thing I keep meaning to add is a custom MsgBox that I can place on a specific monitor)

It all seems to still work, (I just cleaned up the code a bit, added some minimal info above each function and renamed a bunch of variables ($t1, $t2, $h etc just doesn't cut it if someone else is looking at the code :P )

#include-Once
Global $__MonitorList[1][5]
$__MonitorList[0][0] = 0

; Just for testing
_ShowMonitorInfo()

;==================================================================================================
; Function Name:   _ShowMonitorInfo()
; Description::    Show the info in $__MonitorList in a msgbox (line 0 is entire screen)
; Parameter(s):    n/a
; Return Value(s): n/a
; Author(s):       xrxca (autoit@forums.xrx.ca)
;==================================================================================================
Func _ShowMonitorInfo()
    If $__MonitorList[0][0] == 0 Then
        _GetMonitors()
    EndIf
    Local $Msg = ""
    Local $i = 0
    For $i = 0 To $__MonitorList[0][0]
        $Msg &= $i & " - L:" & $__MonitorList[$i][1] & ", T:" & $__MonitorList[$i][2] 
        $Msg &= ", R:" & $__MonitorList[$i][3] & ", B:" & $__MonitorList[$i][4]
        If $i < $__MonitorList[0][0] Then $Msg &= @CRLF
    Next
    MsgBox(0, $__MonitorList[0][0] & " Monitors: ", $Msg)
EndFunc   ;==>_ShowMonitorInfo

;==================================================================================================
; Function Name:   _MaxOnMonitor($Title[, $Text = ''[, $Monitor = -1]])
; Description::    Maximize a window on a specific monitor (or the monitor the mouse is on)
; Parameter(s):    $Title   The title of the window to Move/Maximize
;     optional:    $Text    The text of the window to Move/Maximize
;     optional:    $Monitor The monitor to move to (1..NumMonitors) defaults to monitor mouse is on
; Note:            Should probably have specified return/error codes but haven't put them in yet
; Author(s):       xrxca (autoit@forums.xrx.ca)
;==================================================================================================
Func _MaxOnMonitor($Title, $Text = '', $Monitor = -1)
    _CenterOnMonitor($Title, $Text, $Monitor)
    WinSetState($Title, $Text, @SW_MAXIMIZE)
EndFunc   ;==>_MaxOnMonitor

;==================================================================================================
; Function Name:   _CenterOnMonitor($Title[, $Text = ''[, $Monitor = -1]])
; Description::    Center a window on a specific monitor (or the monitor the mouse is on)
; Parameter(s):    $Title   The title of the window to Move/Maximize
;     optional:    $Text    The text of the window to Move/Maximize
;     optional:    $Monitor The monitor to move to (1..NumMonitors) defaults to monitor mouse is on
; Note:            Should probably have specified return/error codes but haven't put them in yet
; Author(s):       xrxca (autoit@forums.xrx.ca)
;==================================================================================================
Func _CenterOnMonitor($Title, $Text = '', $Monitor = -1)
    $hWindow = WinGetHandle($Title, $Text)
    If Not @error Then
        If $Monitor == -1 Then
            $Monitor = _GetMonitorFromPoint()
        ElseIf $__MonitorList[0][0] == 0 Then
            _GetMonitors()
        EndIf
        If ($Monitor > 0) And ($Monitor <= $__MonitorList[0][0]) Then
            ; Restore the window if necessary
            Local $WinState = WinGetState($hWindow)
            If BitAND($WinState, 16) Or BitAND($WinState, 32) Then
                WinSetState($hWindow, '', @SW_RESTORE)
            EndIf
            Local $WinSize = WinGetPos($hWindow)
            Local $x = Int(($__MonitorList[$Monitor][3] - $__MonitorList[$Monitor][1] - $WinSize[2]) / 2) + $__MonitorList[$Monitor][1]
            Local $y = Int(($__MonitorList[$Monitor][4] - $__MonitorList[$Monitor][2] - $WinSize[3]) / 2) + $__MonitorList[$Monitor][2]
            WinMove($hWindow, '', $x, $y)
        EndIf
    EndIf
EndFunc   ;==>_CenterOnMonitor

;==================================================================================================
; Function Name:   _GetMonitorFromPoint([$XorPoint = -654321[, $Y = 0]])
; Description::    Get a monitor number from an x/y pos or the current mouse position
; Parameter(s):
;     optional:    $XorPoint X Position or Array with X/Y as items 0,1 (ie from MouseGetPos())
;     optional:    $Y        Y Position
; Note:            Should probably have specified return/error codes but haven't put them in yet,
;                  and better checking should be done on passed variables.
;                  Used to use MonitorFromPoint DLL call, but it didn't seem to always work.
; Author(s):       xrxca (autoit@forums.xrx.ca)
;==================================================================================================
Func _GetMonitorFromPoint($XorPoint = 0, $y = 0)
    If @NumParams = 0 then
        local $MousePos = MouseGetPos()
        Local $myX = $MousePos[0]
        Local $myY = $MousePos[1]
    Elseif ( @NumParams = 1 ) and IsArray($XorPoint) Then
        Local $myX = $XorPoint[0]
        Local $myY = $XorPoint[1]
    Else
        Local $myX = $XorPoint
        Local $myY = $y
    EndIf
    If $__MonitorList[0][0] == 0 Then
        _GetMonitors()
    EndIf
    Local $i = 0
    Local $Monitor = 0
    For $i = 1 To $__MonitorList[0][0]
        If ($myX >= $__MonitorList[$i][1]) _
                And ($myX < $__MonitorList[$i][3]) _
                And ($myY >= $__MonitorList[$i][2]) _
                And ($myY < $__MonitorList[$i][4]) Then $Monitor = $i
    Next
    Return $Monitor
EndFunc   ;==>_GetMonitorFromPoint

;==================================================================================================
; Function Name:   _GetMonitors()
; Description::    Load monitor positions
; Parameter(s):    n/a
; Return Value(s): 2D Array of Monitors
;                       [0][0] = Number of Monitors 
;                       [i][0] = HMONITOR handle of this monitor.
;                       [i][1] = Left Position of Monitor 
;                       [i][2] = Top Position of Monitor 
;                       [i][3] = Right Position of Monitor 
;                       [i][4] = Bottom Position of Monitor 
; Note:            [0][1..4] are set to Left,Top,Right,Bottom of entire screen
;                  hMonitor is returned in [i][0], but no longer used by these routines.
;                  Also sets $__MonitorList global variable (for other subs to use)
; Author(s):       xrxca (autoit@forums.xrx.ca)
;==================================================================================================
Func _GetMonitors()
    $__MonitorList[0][0] = 0  ;  Added so that the global array is reset if this is called multiple times
    Local $handle = DllCallbackRegister("_MonitorEnumProc", "int", "hwnd;hwnd;ptr;lparam")
    DllCall("user32.dll", "int", "EnumDisplayMonitors", "hwnd", 0, "ptr", 0, "ptr", DllCallbackGetPtr($handle), "lparam", 0)
    DllCallbackFree($handle)
    Local $i = 0
    For $i = 1 To $__MonitorList[0][0]
        If $__MonitorList[$i][1] < $__MonitorList[0][1] Then $__MonitorList[0][1] = $__MonitorList[$i][1]
        If $__MonitorList[$i][2] < $__MonitorList[0][2] Then $__MonitorList[0][2] = $__MonitorList[$i][2]
        If $__MonitorList[$i][3] > $__MonitorList[0][3] Then $__MonitorList[0][3] = $__MonitorList[$i][3]
        If $__MonitorList[$i][4] > $__MonitorList[0][4] Then $__MonitorList[0][4] = $__MonitorList[$i][4]
    Next
    Return $__MonitorList
EndFunc   ;==>_GetMonitors

;==================================================================================================
; Function Name:   _MonitorEnumProc($hMonitor, $hDC, $lRect, $lParam)
; Description::    Enum Callback Function for EnumDisplayMonitors in _GetMonitors
; Author(s):       xrxca (autoit@forums.xrx.ca)
;==================================================================================================
Func _MonitorEnumProc($hMonitor, $hDC, $lRect, $lParam)
    Local $Rect = DllStructCreate("int left;int top;int right;int bottom", $lRect)
    $__MonitorList[0][0] += 1
    ReDim $__MonitorList[$__MonitorList[0][0] + 1][5]
    $__MonitorList[$__MonitorList[0][0]][0] = $hMonitor
    $__MonitorList[$__MonitorList[0][0]][1] = DllStructGetData($Rect, "left")
    $__MonitorList[$__MonitorList[0][0]][2] = DllStructGetData($Rect, "top")
    $__MonitorList[$__MonitorList[0][0]][3] = DllStructGetData($Rect, "right")
    $__MonitorList[$__MonitorList[0][0]][4] = DllStructGetData($Rect, "bottom")
    Return 1 ; Return 1 to continue enumeration
EndFunc   ;==>_MonitorEnumProc

Edited Jan 8, 2009 to correct minor bug in _GetMonitors routine (Pointed out by Cusem).

Edited by xrxca
alshamma likes this

Share this post


Link to post
Share on other sites

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
Sign in to follow this  
Followers 0