#Region - TimeStamp
; 2011-09-29 19:08:13   v 0.2
#EndRegion - TimeStamp

;===============================================================================
; Script Name......: MenuWindows
; Description......: Erstellen eines Menüs "Fenster" um im Main-Window aktivierte Fenster zu verwalten
; AutoIt version...: 3.3.6.1
; Author(s)........: BugFix ( bugfix@autoit.de )
;
; Funktionen
;		_GUICtrlWindowsList_MenuCreate		Erstellen des Menüs "Fenster" und Registrierung des Main-Windows
;		_GUICtrlWindowsList_Register		Registrieren der Fenster, die im Menü Fenster verwaltet werden sollen
;                                           Bis zu 20 Fenster können in einem Aufruf registriert werden
;		_GUICtrlWindowsList_UnRegister		Fenster von der Registration entfernen
;===============================================================================

#include-once
#include <Array.au3>
#include <Constants.au3>
#include <GUIConstantsEx.au3>
#include <MenuConstants.au3>
#include <StructureConstants.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>

OnAutoItExitRegister('__GUICtrlWindowsList_ShutDown')

Global Const $MAXNUMBER_WINDOWS = 256 ; == inkl. Hauptfenster (Main immer an Index 0)
Global $Buffer_Empty = ''
For $i = 1 To 256
	$Buffer_Empty &= ' '
Next
Global $DefMenuTitle = 'Windows'
If StringInStr("0407 0807 0c07 1007 1407", @OSLang) Then $DefMenuTitle = 'Fenster'


Global $hProc_MnuWnd = DllCallbackRegister('__WinProc', 'ptr', 'hwnd;uint;wparam;lparam')
Global $aWndCollection[$MAXNUMBER_WINDOWS][3] ; <== [[hWnd, $hHook, Mnu-ID]]
Global $hWnd_Main, $hHook_Main, $ID_MainMenu

;===============================================================================
; Function Name....: _GUICtrlWindowsList_MenuCreate
; Description......: Erstellen des Menüs "Fenster" und Registrierung des Main-Windows
; Parameter(s).....: $hGui      Handle des Fensters,in dem das Menü erstellt wird
;        optional    $sTitle    Menütitel, Standard: 'Fenster'
; Return Value(s)..: ID des erstellten Menüs
; Author(s)........: BugFix ( bugfix@autoit.de )
;===============================================================================
Func _GUICtrlWindowsList_MenuCreate($hGui, $sTitle='') ; == Menü "Fenster" erstellen und Main-Window registrieren
	Switch $sTitle
		Case Default, -1, ''
			$sTitle = $DefMenuTitle
	EndSwitch
	$hHook_Main = _WinAPI_SetWindowLong($hGui, $GWL_WNDPROC, DllCallbackGetPtr($hProc_MnuWnd))
	$hWnd_Main = $hGui
	$aWndCollection[0][0] = $hWnd_Main
	$aWndCollection[0][1] = $hHook_Main
	$ID_MainMenu = GUICtrlCreateMenu($sTitle)
	Return $ID_MainMenu
EndFunc  ;==>_GUICtrlWindowsList_MenuCreate

;===============================================================================
; Function Name....: _GUICtrlWindowsList_Register
; Description......: Registrieren der Fenster, die im Menü Fenster verwaltet werden sollen
; Parameter(s).....: $hGui_1       Fensterhandle das registriert werden soll
;        optional    $hGui_2 ..20  weitere Fensterhandle (bis zu 20 gesamt pro Aufruf)
; Requirement(s)...: Ein mit _GUICtrlWindowsList_MenuCreate() erstelltes Menü
; Author(s)........: BugFix ( bugfix@autoit.de )
;===============================================================================
Func _GUICtrlWindowsList_Register($hGui_1, $hGui_2=0, $hGui_3=0, $hGui_4=0, $hGui_5=0, $hGui_6=0, $hGui_7=0, $hGui_8=0, $hGui_9=0, $hGui_10=0, _
	                              $hGui_11=0, $hGui_12=0, $hGui_13=0, $hGui_14=0, $hGui_15=0, $hGui_16=0, $hGui_17=0, $hGui_18=0, $hGui_19=0, $hGui_20=0)
	Local $aParam[2], $tmpHwnd
	For $i = 1 To 20
		$tmpHwnd = Eval('hGui_' & $i)
		If $tmpHwnd = 0 Then ExitLoop
		$aParam[0] = $tmpHwnd
		$aParam[1] = _WinAPI_SetWindowLong($tmpHwnd, $GWL_WNDPROC, DllCallbackGetPtr($hProc_MnuWnd))
		__GUICtrlWindowsList_Manage('add', $aParam)
	Next
EndFunc  ;==>_GUICtrlWindowsList_Register

;===============================================================================
; Function Name....: _GUICtrlWindowsList_UnRegister
; Description......: Fenster von der Registration entfernen
; Parameter(s).....: $hGui_1       erstes Fensterhandle das entfernt werden soll
;        optional    $hGui_2 ..20  weitere Fensterhandle (bis zu 20 gesamt pro Aufruf)
; Requirement(s)...: Ein mit _GUICtrlWindowsList_MenuCreate() erstelltes Menü
; Author(s)........: BugFix ( bugfix@autoit.de )
;===============================================================================
Func _GUICtrlWindowsList_UnRegister($hGui_1, $hGui_2=0, $hGui_3=0, $hGui_4=0, $hGui_5=0, $hGui_6=0, $hGui_7=0, $hGui_8=0, $hGui_9=0, $hGui_10=0, _
	                              $hGui_11=0, $hGui_12=0, $hGui_13=0, $hGui_14=0, $hGui_15=0, $hGui_16=0, $hGui_17=0, $hGui_18=0, $hGui_19=0, $hGui_20=0)
	Local $aParam[2], $tmpHwnd
	For $i = 1 To 20
		$tmpHwnd = Eval('hGui_' & $i)
		If $tmpHwnd = 0 Then ExitLoop
		$aParam[0] = $tmpHwnd
		$aParam[1] = _WinAPI_SetWindowLong($tmpHwnd, $GWL_WNDPROC, DllCallbackGetPtr($hProc_MnuWnd))
		__GUICtrlWindowsList_Manage('del', $aParam)
	Next
EndFunc  ;==>_GUICtrlWindowsList_UnRegister

#region - Helperfunktionen
;===============================================================================
; Function Name....: __GUICtrlWindowsList_ShutDown
; Description......: für alle Fenster __GUICtrlWindowsList_Clear() aufrufen
;===============================================================================
Func __GUICtrlWindowsList_ShutDown()
	For $i = __GUICtrlWindowsList_Manage('getCount') To 0 Step -1
		__GUICtrlWindowsList_Clear($aWndCollection[$i][0], $aWndCollection[$i][1])
	Next
EndFunc  ;==>__GUICtrlWindowsList_ShutDown

;===============================================================================
; Function Name....: __GUICtrlWindowsList_Clear
; Description......: original WinProc für das Fenster wiederherstellen
;===============================================================================
Func __GUICtrlWindowsList_Clear($hGui, $hHook)
	_WinAPI_SetWindowLong($hGui, $GWL_WNDPROC, $hHook)
EndFunc  ;==>__GUICtrlWindowsList_Clear

;===============================================================================
; Function Name....: __GUICtrlWindowsList_Manage
; Description......: Verwaltung
;                    - Registrieren /Lösche Registrierung der Fenster
;                    - Item Erstellen /Löschen
;                    - Anzahl registrierter Fenster zurückgeben
;===============================================================================
Func __GUICtrlWindowsList_Manage($sCommand, $vParam='')
	Local Static $iCountWnd = 0
	Switch $sCommand
		Case 'add' ; == neues Fenster zur Menüverwaltung "Fenster" hinzufügen (bei Fensterregistrierung) [Parameterarray: hWnd, hHook]
			If $iCountWnd = $MAXNUMBER_WINDOWS Then Return SetError(1,0,$MAXNUMBER_WINDOWS)
			$iCountWnd += 1
			$aWndCollection[$iCountWnd][0] = $vParam[0] ; hWnd
			$aWndCollection[$iCountWnd][1] = $vParam[1] ; hHook
			$aWndCollection[$iCountWnd][2] = ''         ; ID MenüItem

		Case 'del' ; == Fenster von Menüverwaltung "Fenster" entfernen [Parameter: Fensterhandle]
			Local $index = _ArraySearch($aWndCollection, $vParam)
			If @error Then Return
			__GUICtrlWindowsList_Clear($vParam, $aWndCollection[$index][1])
			_ArrayDelete($aWndCollection, $index)
			ReDim $aWndCollection[$MAXNUMBER_WINDOWS][3]
			$iCountWnd -= 1

		Case 'item_make' ; == Menüeintrag erstellen [Parameter: ArrayIndex]
			$aWndCollection[$vParam][2] = GUICtrlCreateMenuItem(WinGetTitle($aWndCollection[$vParam][0]), $ID_MainMenu, Default, 1)
			Return $aWndCollection[$vParam][2]

		Case 'item_del' ; == Menüeintrag entfernen [Parameter: Fensterhandle]
			Local $index = _ArraySearch($aWndCollection, $vParam, 1)
			If @error Then Return
			GUICtrlDelete($aWndCollection[$index][2])
			$aWndCollection[$index][2] = ''

		Case 'getCount' ; == Anzahl registrierter Fenster [Parameter: OHNE]
			Return $iCountWnd

	EndSwitch
EndFunc  ;==>__GUICtrlWindowsList_Manage

;===============================================================================
; Function Name....: __setChecked
; Description......: Menüeintrag für aktives Fenster markieren
;===============================================================================
Func __setChecked($iIndex)
    For $i = 1 To __GUICtrlWindowsList_Manage('getCount')
		If $i = $iIndex Then
			GUICtrlSetState($aWndCollection[$i][2], $GUI_CHECKED)
        Else
            If BitAND(GUICtrlRead($aWndCollection[$i][2]), $GUI_CHECKED) Then GUICtrlSetState($aWndCollection[$i][2], $GUI_UNCHECKED)
        EndIf
    Next
EndFunc  ;==>__setChecked

;===============================================================================
; Function Name....: __WinProc
; Description......: Callbackfunktion, Messageverwaltung
;===============================================================================
Func __WinProc($hWnd, $iMsg, $iwParam, $ilParam)
	Local Static $iLastMenuID = -1, $sLastMenuTxt = '', $tMENUITEMINFO = DllStructCreate($tagMENUITEMINFO)
	Local $index = _ArraySearch($aWndCollection, $hWnd)
	Local $currHook = $aWndCollection[$index][1], $menuID, $iLast
	If $index = -1 Then Return _WinAPI_CallWindowProc($currHook, $hWnd, $iMsg, $iwParam, $ilParam) ; == nicht Main oder registriertes Fenster

	Switch $iMsg
		Case $WM_ACTIVATE ; == wenn Item nicht existiert ==> Erstellen
			Local $iIndexMatch = -1
			For $i = 1 To __GUICtrlWindowsList_Manage('getCount')
				If $aWndCollection[$i][0] = $hWnd Then
					$iIndexMatch = $i
					ExitLoop
				EndIf
			Next
			If $iIndexMatch = -1 Then Return _WinAPI_CallWindowProc($currHook, $hWnd, $iMsg, $iwParam, $ilParam)
			If $aWndCollection[$iIndexMatch][2] = '' Then ; == MenüItem existiert noch nicht
				$menuID = __GUICtrlWindowsList_Manage('item_make', $iIndexMatch)
				__setChecked($iIndexMatch)
			EndIf

		Case $WM_SETFOCUS ; == Fenster hat Fokus ==> Checked setzen
			Local $index = _ArraySearch($aWndCollection, $hWnd, 1)
			If $index <> -1 Then __setChecked($index)

		Case $WM_KILLFOCUS ; == Fenster verliert Fokus (wurde geschlossen oder HIDE gesetzt)
			Local $index = _ArraySearch($aWndCollection, $hWnd, 1)
			If $index <> -1 Then
				Local $iState = WinGetState($hWnd)
				If $iState = 5 Then ; == Fenster geschlossen (@SW_HIDE gesetzt)
					__GUICtrlWindowsList_Manage('item_del', $hWnd)
				EndIf
			EndIf

		Case $WM_MENUSELECT
			Local $ID_Menu = BitAND($iwParam, 0xFFFF)                             ; == ID des Menüeintrags
			Local $aRet = DllCall('User32.dll', 'int', 'GetMenu', 'hwnd', $hWnd)
			Local $hWndMenu = $aRet[0]                                            ; == Handle des Menüs
			; $tMENUITEMINFO: 'Size','Mask','Type','State','ID','SubMenu','BmpChecked','BmpUnchecked','ItemData','ptr TypeData','CCH','BmpItem'
			Local $TypeData = DllStructCreate('char[256]')
			DllStructSetData($TypeData, 1, $Buffer_Empty & Chr(0))
			Local $fMask = BitOR($MIIM_ID,$MIIM_DATA,$MIIM_TYPE,$MIIM_SUBMENU)
			DllStructSetData($tMENUITEMINFO, 1, DllStructGetSize($tMENUITEMINFO)) ; == Size
			DllStructSetData($tMENUITEMINFO, 2, $fMask)                           ; == Mask
			DllStructSetData($tMENUITEMINFO, 3, $MF_STRING)                       ; == Type
			DllStructSetData($tMENUITEMINFO, 4, $MFS_DEFAULT)                     ; == State
			DllStructSetData($tMENUITEMINFO,10, DllStructGetPtr($TypeData))       ; == TypeData
			DllStructSetData($tMENUITEMINFO,11, 256)                              ; == CCH
			$aRet = DllCall('User32.dll', 'int', 'GetMenuItemInfo', 'hwnd', $hWndMenu, 'uint', $ID_Menu, 'bool', 0, 'ptr', DllStructGetPtr($tMENUITEMINFO))
			If $aRet[0] = 1 Then
				$iLastMenuID = $ID_Menu ; == ID speichern falls Item angeklickt wird (Event: WM_UNINITMENUPOPUP)
				$sLastMenuTxt = DllStructGetData($TypeData, 1)
			EndIf

		Case $WM_UNINITMENUPOPUP ; == MenüItem wurde angeklickt
			Local $index = _ArraySearch($aWndCollection, $iLastMenuID, 1, 0, 0, 0, 1, 2)
			If $index <> -1 Then
				WinActivate($aWndCollection[$index][0])
				__setChecked($index)
			EndIf

		Case Else
			Return _WinAPI_CallWindowProc($currHook, $hWnd, $iMsg, $iwParam, $ilParam)
	EndSwitch
    Return _WinAPI_CallWindowProc($currHook, $hWnd, $iMsg, $iwParam, $ilParam)
EndFunc  ;==>_WinProc
#endregion - Helperfunktionen
