;-- TIME_STAMP   2018-07-11 20:05:59   v 0.1

#Region    ;************ Includes ************
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#Include <WinAPIsysinfoConstants.au3>
;~ #Include <Array.au3>
#include <File.au3>
#include <WinAPIGdi.au3>
#Include <WinAPISys.au3>
#EndRegion ;************ Includes ************

;~ Press Ctrl+Shift+O --> https://www.autoitscript.com/forum/topic/159545-spi_setworkarea-updates-windows-if-reduced-but-not-increased/
;~ Press Ctrl+Shift+O --> https://docs.microsoft.com/en-us/windows/desktop/api/shellapi/nf-shellapi-shappbarmessage
;~ Press Ctrl+Shift+O --> https://docs.microsoft.com/de-de/windows/desktop/api/shellapi/ns-shellapi-_appbardata
;~ Press Ctrl+Shift+O --> https://docs.microsoft.com/en-us/windows/desktop/gdi/the-virtual-screen

Global Enum $emHandle, $emPrimary, $emRect, $emPos, $emSizeOff
Global $g_aMonitorsInfo, $g_iMonitor = 0 ; <<<=== bei mir: 0 = primary, 1 = secondary

Global $g_sIniFile = StringRegExpReplace(@ScriptFullPath, '(.+)\..+', '\1.ini')

;~ _RestoreSettings()

Global $g_hAppBar, $g_aButtons[5], $g_tAppBar

;~ Global Const $tagAppBar = "dword;int;uint;uint;int;int;int;int;int" ; @Valiante
Global Const $tagAppBar = "struct;DWORD cbSize;HWND hWnd;UINT uCallbackMessage;UINT uEdge;" & $tagRECT & ";LPARAM lParam;endstruct"
;~ Global Const $tagAppBar = "struct;DWORD cbSize;HWND hWnd;UINT uCallbackMessage;UINT uEdge;struct;long Left;long Top;long Right;long Bottom;endstruct;LPARAM lParam;endstruct"

Global Const $ABM_ACTIVATE         = 0x06
Global Const $ABM_GETAUTOHIDEBAR   = 0x07
Global Const $ABM_GETSTATE         = 0x04
Global Const $ABM_SETSTATE         = 0x0000000A
Global Const $ABM_GETTASKBARPOS    = 0x05
Global Const $ABM_NEW              = 0x00
Global Const $ABM_QUERYPOS         = 0x02
Global Const $ABM_REMOVE           = 0x01
Global Const $ABM_SETAUTOHIDEBAR   = 0x08
Global Const $ABM_SETPOS           = 0x03
Global Const $ABM_WINDOWPOSCHANGED = 0x09
;---
Global Const $ABS_ALWAYSONTOP = 0x2
Global Const $ABS_AUTOHIDE    = 0x1
;---
Global Const $ABE_LEFT   = 0
Global Const $ABE_TOP    = 1
Global Const $ABE_RIGHT  = 2
Global Const $ABE_BOTTOM = 3

_Example()

Func _Example()
	$g_aMonitorsInfo = _GetMonitorsInfo()
	If @error Then Exit 111
	_ArrayDisplay($g_aMonitorsInfo, '$g_aMonitorsInfo')
;~ 	Exit
	Local $aWorArea = $g_aMonitorsInfo[$g_iMonitor][$emPos]

	; Create the GUI
	Local $sTitle = StringTrimRight(@ScriptName, 4)
	Local $iToolBarWidth = 200
	Local $iToolBarHeight = $aWorArea[3]
	Local $iToolBarLeft = $aWorArea[0] + $aWorArea[2] - $iToolBarWidth
	Local $iToolBarTop = 0
	Local $iToolBarRight = $aWorArea[0] + $aWorArea[2] - $iToolBarWidth
	Local $iToolBarBottom = $iToolBarHeight

	Local $g_hAppBar = GUICreate($sTitle, $iToolBarWidth, $iToolBarHeight, $iToolBarLeft, $iToolBarTop, $WS_POPUPWINDOW, $WS_EX_TOOLWINDOW)
	Local $x = 10, $y = 10, $w = 180, $h = 25
	$g_aButtons[0] = GUICtrlCreateButton('Left  ', $x, $y, $w, $h)
	$g_aButtons[1] = GUICtrlCreateButton('Top   ', $x, $y * 2 + $h, $w, $h)
	$g_aButtons[2] = GUICtrlCreateButton('Right ', $x, $y * 3 + $h * 2, $w, $h)
	$g_aButtons[3] = GUICtrlCreateButton('Bottom', $x, $y * 4 + $h * 3, $w, $h)
	$g_aButtons[4] = GUICtrlCreateButton('Restore Settings', $x, $y * 5 + $h * 4, $w, $h)
	ReDim $g_aButtons[5 + UBound($g_aMonitorsInfo)]
	For $i = 5 To UBound($g_aButtons) -1 Step 1
		$g_aButtons[$i] = GUICtrlCreateButton('Move to Monitor #' & $i - 4, $x, $y * ($i + 1) + $h * $i, $w, $h)
	Next

	GUISetState()

	; Register the AppBar
	$g_tAppBar = DllStructCreate($tagAppBar)
	DllStructSetData($g_tAppBar, 1, DllStructGetSize($g_tAppBar)) ; cbSize
	DllStructSetData($g_tAppBar, 2, $g_hAppBar)                   ; hWnd
	DllStructSetData($g_tAppBar, 3, 1001)                         ; uCallbackMessage
	DllStructSetData($g_tAppBar, 4, $ABE_RIGHT)                   ; uEdge
	DllStructSetData($g_tAppBar, 5, $iToolBarLeft)                ; (rc) Left
	DllStructSetData($g_tAppBar, 6, $iToolBarTop)                 ; (rc) Top
	DllStructSetData($g_tAppBar, 7, $iToolBarRight)               ; (rc) Right
	DllStructSetData($g_tAppBar, 8, $iToolBarBottom)              ; (rc) Bottom
	_ShAppBarMessage($ABM_NEW, $g_tAppBar)
	_ShAppBarMessage($ABM_SETPOS, $g_tAppBar)

	OnAutoItExitRegister('_Exit')

	; Loop until the user exits.
	Local $iMsg
	While 1
		$iMsg = GUIGetMsg()
		Switch $iMsg
			Case $GUI_EVENT_CLOSE
				Exit
			Case $g_aButtons[0] To $g_aButtons[3]
				MsgBox(64, @ScriptName, 'Du hast Button ' & $iMsg - $g_aButtons[0] + 1 & ' gedrückt!')
			Case $g_aButtons[4]
				_RestoreWorkAreas()
			Case $g_aButtons[5] To $g_aButtons[UBound($g_aButtons) -1]
				If $iMsg - $g_aButtons[5] <> $g_iMonitor Then
					$g_iMonitor = $iMsg - $g_aButtons[5]
					$aWorArea = $g_aMonitorsInfo[$g_iMonitor][$emPos]
					$iToolBarHeight = $aWorArea[3]
					$iToolBarLeft = $aWorArea[0] + $aWorArea[2] - $iToolBarWidth
					$iToolBarTop = 0
					$iToolBarRight = $aWorArea[0] + $aWorArea[2] - $iToolBarWidth
					$iToolBarBottom = $iToolBarHeight
					ConsoleWrite("> $g_iMonitor                --> " & $g_iMonitor & @CRLF)
					ConsoleWrite("> $iToolBarWidth             --> " & $iToolBarWidth & @CRLF)
					ConsoleWrite("> $iToolBarHeight            --> " & $iToolBarHeight & @CRLF)

					ConsoleWrite("! $iToolBarLeft              --> " & $iToolBarLeft & @CRLF)
					ConsoleWrite("! $iToolBarTop               --> " & $iToolBarTop & @CRLF)
					ConsoleWrite("! $iToolBarRight             --> " & $iToolBarRight & @CRLF)
					ConsoleWrite("! $iToolBarBottom            --> " & $iToolBarBottom & @CRLF)

					WinMove($g_hAppBar, '', $iToolBarLeft, $iToolBarTop, $iToolBarWidth, $iToolBarHeight)
					DllStructSetData($g_tAppBar, 4, $ABE_RIGHT)
					DllStructSetData($g_tAppBar, 5, $iToolBarLeft)
					DllStructSetData($g_tAppBar, 6, $iToolBarTop)
					DllStructSetData($g_tAppBar, 7, $iToolBarRight)
					DllStructSetData($g_tAppBar, 8, $iToolBarBottom)
					_ShAppBarMessage($ABM_SETPOS, $g_tAppBar)
				EndIf
		EndSwitch
	WEnd
EndFunc  ;==>_Example

Func _ShAppBarMessage($dwMessage, ByRef $tAppBar)
;~ 	Local $aRes = DllCall("shell32.dll", "int", "SHAppBarMessage", "int", $dwMessage, "ptr", DllStructGetPtr($tAppBar)) ; @Valiante
    Local $aRes = DllCall("shell32.dll", "UINT_PTR", "SHAppBarMessage", "DWORD", $dwMessage, "PTR", DllStructGetPtr($tAppBar))
	If @error Or Not $aRes[0] Then Exit 999
	Return $aRes[0]
EndFunc  ;==>_ShAppBarMessage

Func _GetMonitorsInfo()
	Local $aData = _WinAPI_EnumDisplayMonitors()

	If Not IsArray($aData) Then Return SetError(1, 0, False)

	Local $aInfo[$aData[0][0]][$emSizeOff]
	For $i = 1 To $aData[0][0]
		$aInfo[$i -1][$emHandle] = $aData[$i][0] ; Handle
		$aInfo[$i -1][$emRect] = _GetWorArea($aInfo[$i -1][$emHandle])
		$aInfo[$i -1][$emPrimary] = @extended
		If @error Then Return SetError(2, 0, False)
		$aInfo[$i -1][$emPos] = _WinAPI_GetPosFromRect($aInfo[$i -1][$emRect])
	Next

	_SaveIni($aInfo)

	Return $aInfo
EndFunc  ;==>_GetMonitorsInfo

Func _GetWorArea($hMonitor)
	Local $aData = _WinAPI_GetMonitorInfo($hMonitor)
	If Not IsArray($aData) Then Return SetError(2, 0, False)

	Return SetExtended($aData[2], $aData[1])
EndFunc  ;==>_GetWorArea

Func _SaveIni(ByRef $aInfo)
	If Not FileExists($g_sIniFile) Then
		Local $aIni[UBound($aInfo)][5], $tWorArea
		For $i = 0 To UBound($aIni) -1 Step 1
			$aIni[$i][0] = $aInfo[$i][$emHandle]
			$tWorArea = $aInfo[$i][$emRect]
			$aIni[$i][1] = $tWorArea.Left
			$aIni[$i][2] = $tWorArea.Top
			$aIni[$i][3] = $tWorArea.Right
			$aIni[$i][4] = $tWorArea.Bottom
		Next
		_FileWriteFromArray($g_sIniFile, $aIni)
	EndIf
EndFunc  ;==>_SaveIni

Func _RestoreWorkAreas()
	Local $aIni, $hMonitor, $tWorArea = DllStructCreate($tagRECT), $aWorArea, $aWindows = _WinAPI_EnumWindowsTop(), $aPos
	_FileReadToArray($g_sIniFile, $aIni, $FRTA_NOCOUNT, '|')
	If @error Then Exit 222
;~ 	_ArrayDisplay($aIni, '$aIni')

	For $i = 0 To UBound($aIni) -1 Step 1
		$hMonitor        = $aIni[$i][0]
		$tWorArea.Left   = $aIni[$i][1]
		$tWorArea.Top    = $aIni[$i][2]
		$tWorArea.Right  = $aIni[$i][3]
		$tWorArea.Bottom = $aIni[$i][4]
		ConsoleWrite(StringFormat('\n> $hMonitor = %s\n> $tWorArea = Left: %5i, Top: %5i, Right: %5i, Bottom: %5i\n', $hMonitor, $tWorArea.Left, $tWorArea.Top, $tWorArea.Right, $tWorArea.Bottom))
		; Restore WorAreas
		ConsoleWrite('> Restore WorArea = ' & _WinAPI_SystemParametersInfo($SPI_SETWORKAREA, 0, DllStructGetPtr($tWorArea), $SPIF_SENDCHANGE) & @CRLF)
		; Refresh Windows
		For $j = 1 To $aWindows[0][0] Step 1
			If _WinAPI_MonitorFromWindow($aWindows[$j][0]) = $hMonitor Then
				If BitAND(WinGetState($aWindows[$j][0]), $WIN_STATE_MAXIMIZED) Then ; $WIN_STATE_MAXIMIZED = 32
					ConsoleWrite('> Refresh Window = ' & $aWindows[$j][0] & @CRLF)
					$aWorArea = _WinAPI_GetPosFromRect($tWorArea)
					$aPos = WinGetPos($aWindows[$j][0])
					WinMove($aWindows[$j][0], '', $aPos[0], $aPos[1], $aWorArea[2], $aWorArea[3])
				EndIf
			EndIf
		Next
	Next

	Exit
EndFunc  ;==>_RestoreWorkAreas

Func _Exit()
	; Unregister the AppBar
	Local $vRes = _ShAppBarMessage($ABM_REMOVE, $g_tAppBar)

	GUIDelete($g_hAppBar)

	; ***********************************************************************************************************
	; Eigentlich sollte spätestens nach GUIDelete($g_hAppBar) alles wieder automatisch zurückgesetzt werden,
	; doch bei mir muss ich zumindest für den sekundären Monitor noch die Funktion _RestoreWorkAreas() ausführen!
	; ***********************************************************************************************************

	_RestoreWorkAreas()
EndFunc  ;==>_Exit
