Jump to content
Sign in to follow this  

What's wrong with my understanding of this code?

Recommended Posts


I found >this thread started by chuber while searching for a way to get the useable desktop area (size of primary monitor desktop minus taskbar).

My first bit of bafflement was why the code written by chuber does not match the quote of his code in the reply that follows his post.

Since I didn't want to tackle figuring out Sysinternal's debug viewer I went with the version of his code that omits all the lines starting with "If $DEBUG_001...". (more is omitted than that but I think it's missing only comments)  I'll paste this version below. It compiles fine.

What chuber posted is a function. So my first goal is to write a simple MsgBox that will show me the results of his function.

When I insert a simple MsgBox to see the results of his function...


...I get an error saying "Subscript used with non-Array variable.", yet he used $aDesktop_Pos as an array variable throughout his function and it's a global variable. What part of this do I not understand and how can I extract the info I'm seeking?

Here's the code from the original thread.

    Script:        Desktop client size and Taskbar position (code snippet)
    Author:        Bruce Huber (cbruce)
    AutoIt:        v3.2.12.1
    Date:        2008.08.13 - Original release

        Determine whether the Taskbar is visible or hidden and where it is docked on the Desktop.
        Also calculate the available Desktop client region, accounting for any Taskbar space.

;    Desktop and Taskbar position information - GetDesktopAndTaskbarPos().
Global Enum $DTP_X, $DTP_Y, $DTP_W, $DTP_H
Global $aDesktop_Pos, $aTaskbar_Pos
Global $Taskbar_Dock_Location = $TBDL_UNKNOWN
Global $Taskbar_Visible

Func GetDesktopAndTaskbarPos()
    ;    Get the Desktop size - which includes the Taskbar space, if the Taskbar is visible.
    $aDesktop_Pos = WinGetPos( "Program Manager")
    ;    Get the Taskbar size.
    $aTaskbar_Pos = WinGetPos( "[Class:Shell_TrayWnd]")
    ;    Determine if Taskbar is taking up space on the Desktop.
    If ( $aTaskbar_Pos[$DTP_X] > -3) And ( $aTaskbar_Pos[$DTP_Y] > -3) And ( $aTaskbar_Pos[$DTP_X] < ( $aDesktop_Pos[$DTP_W] - 5)) And ( $aTaskbar_Pos[$DTP_Y] < ( $aDesktop_Pos[$DTP_H] - 5)) Then
        ;    Taskbar is Visible.
        $Taskbar_Visible = True
        ;    Calculate the parameters of the AVAILABLE Desktop client region.
        If ( $aTaskbar_Pos[$DTP_X] < 1) and ( $aTaskbar_Pos[$DTP_Y] > 0) and ( $aTaskbar_Pos[$DTP_W] > $aTaskbar_Pos[$DTP_H]) Then
            ;    Taskbar is on the BOTTOM.
            $Taskbar_Dock_Location = $TBDL_BOTTOM
            ;    We need to adjust the Desktop Height.
            $aDesktop_Pos[$DTP_H] = $aTaskbar_Pos[$DTP_Y] - 1
        ElseIf ( $aTaskbar_Pos[$DTP_X] < 1) and ( $aTaskbar_Pos[$DTP_Y] < 1) and ( $aTaskbar_Pos[$DTP_W] < $aTaskbar_Pos[$DTP_H]) Then
            ;    Taskbar is on the LEFT.
            $Taskbar_Dock_Location = $TBDL_LEFT
            ;    We need to adjust the Desktop X and Width.
            $aDesktop_Pos[$DTP_X] = $aTaskbar_Pos[$DTP_X] + $aTaskbar_Pos[$DTP_W] + 1
            $aDesktop_Pos[$DTP_W] = $aTaskbar_Pos[$DTP_X] - 1
        ElseIf ( $aTaskbar_Pos[$DTP_X] > 0) and ( $aTaskbar_Pos[$DTP_Y] < 1) and ( $aTaskbar_Pos[$DTP_W] < $aTaskbar_Pos[$DTP_H]) Then
            ;    Taskbar is on the RIGHT.
            $Taskbar_Dock_Location = $TBDL_RIGHT
            ;    We need to adjust the Desktop Width.
            $aDesktop_Pos[$DTP_W] = $aTaskbar_Pos[$DTP_X] - 1
        ElseIf ( $aTaskbar_Pos[$DTP_X] < 1) and ( $aTaskbar_Pos[$DTP_Y] < 1) and ( $aTaskbar_Pos[$DTP_W] > $aTaskbar_Pos[$DTP_H]) Then
            ;    Taskbar is on the TOP.
            $Taskbar_Dock_Location = $TBDL_TOP
            ;    We need to adjust the Desktop Y and Height.
            $aDesktop_Pos[$DTP_Y] = $aTaskbar_Pos[$DTP_Y] + $aTaskbar_Pos[$DTP_H] + 1
            $aDesktop_Pos[$DTP_H] = $aTaskbar_Pos[$DTP_Y] - 1
            ;    Where the heck has the Taskbar gone?
            $Taskbar_Dock_Location = $TBDL_UNKNOWN
        ;    Taskbar is Hidden.
        $Taskbar_Visible = False
            $aDesktop_Pos now contains parameters that only define the AVAILABLE Desktop client region.  This will
        be the entire Desktop if the Taskbar is hidden.  Otherwise, the region will be the Desktop area minus the
        Taskbar area.

            $Taskbar_Dock_Location now specifies WHERE, on the Desktop, that the Taskbar is docked.
EndFunc   ; GetDesktopAndTaskbarPos()

I realize there's> a post in another thread that uses a different approach to finding the data I seek but all I need are "x,y,h,w" and I can't figure out how to extact that info from the script provided in that code (copy pasted below).  This is humbling.

Global Const $MONITOR_DEFAULTTONULL     = 0x00000000
Global Const $MONITOR_DEFAULTTOPRIMARY  = 0x00000001
Global Const $MONITOR_DEFAULTTONEAREST  = 0x00000002

Global Const $CCHDEVICENAME             = 32
Global Const $MONITORINFOF_PRIMARY      = 0x00000001

$hMonitor = GetMonitorFromPoint(0, 0)
;$hMonitor = GetMonitorFromPoint(-2, 0)
;$hMonitor = GetMonitorFromPoint(@DesktopWidth, 0)

If $hMonitor <> 0 Then
    Dim $arMonitorInfos[4]
    If GetMonitorInfos($hMonitor, $arMonitorInfos) Then _
        Msgbox(0, "Monitor-Infos", "Rect-Monitor" & @Tab & ": " & $arMonitorInfos[0] & @LF & _
                            "Rect-Workarea" & @Tab & ": " & $arMonitorInfos[1] & @LF & _
                            "PrimaryMonitor?" & @Tab & ": " & $arMonitorInfos[2] & @LF & _
                            "Devicename" & @Tab & ": " & $arMonitorInfos[3])


Func GetMonitorFromPoint($x, $y)
    $hMonitor = DllCall("user32.dll", "hwnd", "MonitorFromPoint", _
                                            "int", $x, _
                                            "int", $y, _
                                            "int", $MONITOR_DEFAULTTONULL)
    Return $hMonitor[0]

Func GetMonitorInfos($hMonitor, ByRef $arMonitorInfos)
    Local $stMONITORINFOEX = DllStructCreate("dword;int[4];int[4];dword;char[" & $CCHDEVICENAME & "]")
    DllStructSetData($stMONITORINFOEX, 1, DllStructGetSize($stMONITORINFOEX))

    $nResult = DllCall("user32.dll", "int", "GetMonitorInfo", _
                                            "hwnd", $hMonitor, _
                                            "ptr", DllStructGetPtr($stMONITORINFOEX))
    If $nResult[0] = 1 Then
        $arMonitorInfos[0] = DllStructGetData($stMONITORINFOEX, 2, 1) & ";" & _
            DllStructGetData($stMONITORINFOEX, 2, 2) & ";" & _
            DllStructGetData($stMONITORINFOEX, 2, 3) & ";" & _
            DllStructGetData($stMONITORINFOEX, 2, 4)
        $arMonitorInfos[1] = DllStructGetData($stMONITORINFOEX, 3, 1) & ";" & _
            DllStructGetData($stMONITORINFOEX, 3, 2) & ";" & _
            DllStructGetData($stMONITORINFOEX, 3, 3) & ";" & _
            DllStructGetData($stMONITORINFOEX, 3, 4)
        $arMonitorInfos[2] = DllStructGetData($stMONITORINFOEX, 4)
        $arMonitorInfos[3] = DllStructGetData($stMONITORINFOEX, 5)

    Return $nResult[0]

Share this post

Link to post
Share on other sites

I've made sometimes the following function for this:

; Function Name:   _GetTaskBarProps($hProperty="")
; Description::    Gets the Taskbar properties
; Parameter(s):    $_hProperty    propertiy, you want to get
;                                 "" (default) returns rectangle of taskbar as array [left,top,right,bottom]
;                                 "top"    - X1 left position
;                                 "left"   - Y1 top position
;                                 "height" - Y2-Y1 height of taskbar
;                                 "width"  - X2-X1 width of taskbar
;                                 "align"  - Alignment (Clockwise): 1=right, 2=bottom, 3=left, 4=top
;                  $_fAlignAsStr  TRUE returns alignment as string (left, top, right, bottom), FALSE (default) as number
; Return Value(s): see $_hProperty
; Author(s):       BugFix (bugfix@autoit.de)
Func _GetTaskBarProps($_hProperty="", $_fAlignAsStr=False)
    Local $tRect = DllStructCreate("long;long;long;long"), $hWnd, $ret, $vRet, $aAlign[5] = ['', 'right', 'bottom', 'left', 'top']
    $_hProperty = StringStripWS($_hProperty, 3)
    $ret = DllCall("user32.dll", 'long', "FindWindowA", 'str', "Shell_traywnd", 'str', "")
    $hWnd = $ret[0]
    DllCall("User32.dll", "int", "GetWindowRect", "hwnd", $hWnd, "ptr", DllStructGetPtr($tRect))
    Local $left   = DllStructGetData($tRect, 1)
    Local $top    = DllStructGetData($tRect, 2)
    Local $right  = DllStructGetData($tRect, 3)
    Local $bottom = DllStructGetData($tRect, 4)
    If $_hProperty = "" Then
        Local $aOut[4] = [$left, $top, $right, $bottom]
        Return $aOut
    Switch $_hProperty
        Case "top"
            Return $top
        Case "left"
            Return $left
        Case "height"
            Return $bottom - $top
        Case "width"
            Return $right - $left
        Case "align"
            If $top < 1 And $left < 1 Then
                    If $bottom > $right Then $vRet = 3
                    If $right > $bottom Then $vRet = 4
            ElseIf $top < 1 And $left > 0 Then
                $vRet = 1
                $vRet = 2
    If $_fAlignAsStr Then Return $aAlign[$vRet]
    Return $vRet
EndFunc  ;==>_GetTaskBarProps 

Best Regards BugFix  

Share this post

Link to post
Share on other sites

This script doesn't get the primary monitor's dimensions, it gets the total desktop width (dual monitors on my setup), then subtracts the taskbar height from the desktop height but doesn't take into account you might have more than one monitor.

Not to mention, it's poorly written.

EDIT: Just wanted to make a note here that this reply was to the OP, and not to BugFix's post.

Edited by BrewManNH

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Share this post

Link to post
Share on other sites


Rather than use those old functions, why not use something much simpler to get the useable desktop area? ;)

#include <Array.au3> ; Just for display

$aDeskTopData = _DeskTopData()
$iError = @error
If IsArray($aDeskTopData) Then
    MsgBox(0, "Error", $iError)

Func _DeskTopData()

    Local $tWorkArea
    ; Determine which struct syntax to use to use
    If @AutoItVersion < "" Then
        $tWorkArea = DllStructCreate("long Left;long Top;long Right;long Bottom")
        $tWorkArea = DllStructCreate("struct;long Left;long Top;long Right;long Bottom;endstruct")

    ; Determine available work area ; $SPI_GETWORKAREA = 48
    DllCall("user32.dll", "bool", "SystemParametersInfoW", "uint", 48, "uint", 0, "ptr", DllStructGetPtr($tWorkArea), "uint", 0)
    If @error Then
        Return SetError(2, 0, "")
    Local $aDeskTopData[5] = [DllStructGetData($tWorkArea, "Left"), DllStructGetData($tWorkArea, "Top"), _
            DllStructGetData($tWorkArea, "Right"), DllStructGetData($tWorkArea, "Bottom"), 1] ; Assume taskbar visible

    ; Check if Taskbar is hidden
    Local $aRet = DllCall("shell32.dll", "uint", "SHAppBarMessage", "dword", 0x00000004, "ptr*", 0) ; $ABM_GETSTATE
    If @error Then
        Return SetError(1, 0, "")
    If BitAND($aRet[0], 0x01) Then
        $aDeskTopData[4] = 0 ; Set to hidden

    Return $aDeskTopData

EndFunc   ;==>_DeskTopData
I leave you to do the maths to find out the width and height. ;)



Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:


ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area


Share this post

Link to post
Share on other sites

I haven't looked at the code, but it also probably doesn't take into account where the taskbar is. rarely I've seen the taskbar along the side of the screen.

I've also noticed that taskbar functions I've found here will sometimes not return the correct properties causing unexpected behavior in scripts (I've only used getting taskbar properties in a loop to catch changes that might be made) so I use this to get the taskbar properties.

$tray = WinGetPos("[CLASS:Shell_TrayWnd]")

With that and these functions, I'm able to calculate the usable screen area

Global $__MonitorList[1][5]
$__MonitorList[0][0] = 0

#Region thanks to xrxca for these functions
Func _GetMonitorFromPoint($XorPoint = 0, $y = 0)
    Local $MousePos, $myX, $myY
    If @NumParams = 0 Then
        $MousePos = MouseGetPos()
        $myX = $MousePos[0]
        $myY = $MousePos[1]
    ElseIf (@NumParams = 1) And IsArray($XorPoint) Then
        $myX = $XorPoint[0]
        $myY = $XorPoint[1]
        $myX = $XorPoint
        $myY = $y
    If $__MonitorList[0][0] == 0 Then
    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
    Return $Monitor
EndFunc   ;==>_GetMonitorFromPoint

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)
    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]
    Return $__MonitorList
EndFunc   ;==>_GetMonitors

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]
    If $hDC = $hDC Then
    If $lParam = $lParam Then
    $__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
#EndRegion thanks to xrxca for these functions



My Android cat and mouse game

We're gonna need another Timmy!

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  

  • Similar Content

    • nitekram
      By nitekram
      I am trying to do something, but it appears that I am having issues with trying to get the right functions called, in the right order.
      What I want to do is move a window to a certain position and then move it back, but as stated, the order appears to be an issue, as if the window is minimized, the wingetclientsize is not able to pull the info, not is the wingetpos. It appears to be able to get the size and position of the window in question is activated, but I have to activate it first, but that defeats the purpose, as once activated, the functions called to get the position and size, are not correct, as the screen is now active. I have tried to use wingetstate, to get the state first, but I am not sure how to move the window back to the original location with the right state.
      If window is minimized, I want it to go back to minimized state, as well as keeping the window size the same, so if the user activates the window, the user does not have to resize it.
      If the window is active and is on another screen, it appears I do not have the same issue.
      Here is my attempt, but I have tried other combinations. Has anyone got an idea on how to resolve this issue?
      Func MoveVNC($Move) CreateLogEntry("Called MoveVNC($Move) $Move = " & $Move) Local $aStartBar = StartBar() Local $bMove = False Local $VNC = 'NAMEOFWINDOW' Static $aWin_VNC_Pos = '' Static $iWin_VNC_State = '' Static $aWin_VNC_Size = '' #cs ;$aWin_VNC_Pos = WinGetPos($VNC, '') MsgBox('','VNC POS','') _ArrayDisplay(WinGetPos($VNC, '')) MsgBox('','VNC STATE',WinGetState($VNC, '')) WinActivate($VNC) Sleep(20) WinWaitActive($VNC, '', 10) Sleep(20) Local $aSize = WinGetClientSize($VNC, '') MsgBox('','VNC SIZE','') _ArrayDisplay($aSize) #ce If $Move = 'Get' Then Opt("WinTitleMatchMode", -1) ;1=start, 2=subStr, 3=exact, 4=advanced, -1 to -4=Nocase If WinExists($VNC) Then WinActivate($VNC) Sleep(20) WinWaitActive($VNC, '', 10) Sleep(20) $aWin_VNC_Pos = WinGetPos($VNC, '') Sleep(20) ;_ArrayDisplay($aWin_VNC_Pos, '$aWin_VNC_Pos') $iWin_VNC_State = WinGetState($VNC, '') Sleep(20) $aWin_VNC_Size = WinGetClientSize($VNC, '') ;_ArrayDisplay($aWin_VNC_Size) ;MsgBox('','$VNC',$VNC) ;MsgBox('', '$iWin_VNC_State', $iWin_VNC_State) ;WinSetState($VNC, '', @SW_MAXIMIZE) ;Sleep(20) WinMove($VNC, '', 0, 0, 1600, 950) ; - (3 * $aStartBar[3]) Sleep(20) ;MouseClick('Left', 1764, 174) $bMove = True Else MsgBox($MB_TOPMOST, 'ERROR GET', 'Window ' & $VNC & ' Does not exists - VNC is not running!') EndIf If Not $bMove Then CreateLogEntry("MoveVNC(GET) FAILED") Return False Else CreateLogEntry("MoveVNC(GET) PASSED") Return True EndIf ElseIf $Move = 'Put' Then CreateLogEntry("Called MoveVNC($Move) $Move = " & $Move) If WinExists($VNC) Then ;WinSetState($VNC, '', @SW_RESTORE) ;If @error Then MsgBox('', '', @error) ;Sleep(20) WinMove($VNC, '', $aWin_VNC_Pos[0], $aWin_VNC_Pos[1], $aWin_VNC_Pos[2], $aWin_VNC_Pos[3]) If @error Then MsgBox('', '', @error) Sleep(20) ;WinSetState($VNC, '', $iWin_VNC_State) ;If @error Then MsgBox('', 'Not setting state', @error & ' ' & $VNC) ;Sleep(20) $bMove = True Else MsgBox($MB_TOPMOST, 'ERROR PUT', 'Window ' & $VNC & ' Does not exists - VNC is not running!') EndIf If Not $bMove Then CreateLogEntry("MoveVNC(PUT) FAILED") Return False Else CreateLogEntry("MoveVNC(PUT) PASSED") Return True EndIf EndIf CreateLogEntry(" Returned from MoveVNC()") EndFunc ;==>MoveVNC  
    • Schoening
      By Schoening
      This question is for WinGetClientSize and multiple screen sizes.

      When using WinGetClientSize in a Function, how to i then go on and set pixel search areas for example?

      Let's say i want to find the middle of a window; is there a %percentage syntax like in HTML ?

      Same problem goes for PixelCoordMode i think.

      It appears that i have to know every screen size usable beforehand.

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.