;-- TIME_STAMP   2020-09-10 06:12:53   v 0.1

Opt('MustDeclareVars', 1)

#include <GUIConstantsEx.au3>   ; $GUI_EVENT_CLOSE
#include <WindowsConstants.au3> ; $GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, ...
#include <Array.au3>            ; _ArraySearch, _ArrayAdd
#include <Date.au3>             ; _NowCalc, _Date_Time_GetTickCount
#include <GuiEdit.au3>          ; _GUICtrlEdit_AppendText
#include <GuiButton.au3>        ; _GUICtrlButton_SetNote
#include <String.au3>           ; _StringRepeat
#include <WinAPIConv.au3>       ; _WinAPI_HashString
#include <WinAPISys.au3>        ; _WinAPI_ComputeCrc32, _WinAPI_GetClassName
;~ #include <WinAPISysWin.au3>  ; _WinAPI_GetClassName
#include <Crypt.au3>            ; _Crypt_HashData, _Crypt_HashFile, _Crypt_*

Global Const $g_aAlgIDs = [[$CALG_MD2, '$CALG_MD2 (128bit)'], [$CALG_MD4, '$CALG_MD4 (128bit)'], [$CALG_MD5, '$CALG_MD5 (128bit)'], [$CALG_SHA1, '$CALG_SHA1 (160bit)'], [$CALG_SHA_256, '$CALG_SHA_256'], [$CALG_SHA_384, '$CALG_SHA_384'], [$CALG_SHA_512, '$CALG_SHA_512']]

Global Enum $eString = 1, $eFile

Global $g_hGUI, $g_idEdit, $g_hEdit, $g_sClassName = 'AutoIt v3 GUI', $g_Hash, $g_sSpacer = _StringRepeat('-', 194), $g_sMemoBuffer

_Crypt_Startup() ; To optimize performance start the crypt library.
OnAutoItExitRegister('_Exit')

Example2() ; Find and restore the first instance of this script and exit this second instance - or do something until the user exits the script.

Func Example2()
	_Memo(@CRLF & $g_sSpacer & @CRLF & '! Example2() - 2. Instanz' & @CRLF & $g_sSpacer & @CRLF & @CRLF)
	$g_Hash = _GetCrc32(@ScriptFullPath) ; or @ScriptName, or "Any string of characters"
	Local $hWnd = _WinGetHandle('.+\Q' & $g_Hash & '\E', $g_sClassName, 1)
	If IsHWnd($hWnd) Then
		$g_hEdit = ControlGetHandle($hWnd, '', '[CLASS:Edit; INSTANCE:1]')
		If $g_sMemoBuffer Then
			_Memo($g_sMemoBuffer)
			$g_sMemoBuffer = ''
		EndIf
;~ 		WinSetState($hWnd, '', @SW_MAXIMIZE)
		WinSetState($hWnd, '', @SW_RESTORE)
		_Memo('Exit - 2. Instanz' & @CRLF & $g_sSpacer & @CRLF & @CRLF)
		Exit
	EndIf

;~ 	$g_hGUI = GUICreate('', 1024, 768, -1, -1, BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX))
	$g_hGUI = GUICreate('', 1024, 768, -1, -1, BitOR($GUI_SS_DEFAULT_GUI, $WS_OVERLAPPEDWINDOW))
	GUISetFont(11, 800, 0, 'Courier New')
;~ 	$g_sClassName = _WinAPI_GetClassName($g_hGUI)
	GUISetState(@SW_SHOWMAXIMIZED, $g_hGUI)
	Local $aClientSize = WinGetClientSize($g_hGUI)
	$g_idEdit = GUICtrlCreateEdit('', 0, 0, $aClientSize[0], $aClientSize[1] - 50)
	GUIctrlSetBkColor(-1, 0x20B2AA)
	GUIctrlSetColor(-1, 0xEEE9D5)
	$g_hEdit = GUICtrlGetHandle(-1)
	_Memo($g_sSpacer & @CRLF & '! Example2()' & @CRLF & $g_sSpacer & @CRLF & @CRLF)
	_Memo('! $g_hGUI        = ' & $g_hGUI & @CRLF)
	_Memo('! $g_sClassName  = ' & $g_sClassName & @CRLF & @CRLF)

	Local $iStyle = BitOR($BS_COMMANDLINK, $BS_DEFPUSHBUTTON, $BS_PUSHLIKE)
	Local $idBtn_sInfo = GUICtrlCreateButton('Jetzt eine weitere Instanz starten...', 0, $aClientSize[1] - 50, $aClientSize[0], 50, $iStyle)
	_GUICtrlButton_SetNote($idBtn_sInfo, 'Dieses Fenster wird dann vorher minimiert.')

	_SetWinTitle()
	_Memo($g_sSpacer & @CRLF & @CRLF)

	While True
		Switch GUIGetMsg()
			Case $GUI_EVENT_CLOSE
				Exit
			Case $idBtn_sInfo
				GUISetState(@SW_MINIMIZE, $g_hGUI)
				Switch StringRegExpReplace(@ScriptName, '.+(\..*)', '\1')
					Case '.exe'
						Run(@ScriptFullPath)
					Case Else
						Run(@AutoItExe & ' /AutoIt3ExecuteScript "' & @ScriptFullPath & '"')
				EndSwitch
		EndSwitch
		_SetWinTitle()
	WEnd
EndFunc   ;==>Example2

Func _GetCrc32($sString, $iType = $eString)
	Local $sType = $iType = $eString ? '$eString' : $iType = $eFile ? '$eFile' : 'Undefined $iType!'
	_Memo('> _GetCrc32("' & $sString & '", ' & $sType & ')' & @CRLF)
	$sString = _GetType($sString, $iType)
	If @error Then Return SetError(1, 0, '')
	Local $iLength = StringLen($sString), $tCrc32 = DllStructCreate('char Crc32[' & $iLength & ']')
	If @error Then Return SetError(2, 0, '')
	DllStructSetData($tCrc32, 'Crc32', $sString)
	Local $pMemory = DllStructGetPtr($tCrc32)
	Local $iCrc32 = _WinAPI_ComputeCrc32($pMemory, $iLength)
	_Memo('- $iCrc32        = ' & $iCrc32 & @CRLF)
	Return $iCrc32 ? _AddBrackets($iCrc32) : SetError(3, 0, '')
;~ 	Return $iCrc32 ? Binary($iCrc32) : SetError(3, 0, '')
EndFunc   ;==>_GetCrc32

;~ _WinAPI_HashString($sString)
Func _GetHashString($sString, $iType = $eString)
	Local $sType = $iType = $eString ? '$eString' : $iType = $eFile ? '$eFile' : 'Undefined $iType!'
	_Memo('> _GetHashString("' & $sString & '", ' & $sType & ')' & @CRLF)
	$sString = _GetType($sString, $iType)
	If @error Then Return SetError(1, 0, '')
	Local $bHashString = _WinAPI_HashString($sString)
	_Memo('- $bHashString   = ' & $bHashString & @CRLF)
	Return $bHashString ? _AddBrackets($bHashString) : SetError(2, 0, '')
EndFunc   ;==>_GetHashString

;~ _Crypt_HashData ( $vData, $iAlgID [, $bFinal = True [, $hCryptHash = 0]] )
Func _GetHashData($vData, $iAlgID = $CALG_MD2)
	Local $iIndex = _ArraySearch($g_aAlgIDs, $iAlgID)
	_Memo('> _GetHashData("' & $vData & '", 0x' & Hex($iAlgID) & ') ; ' & ($iIndex = -1 ? 'No Hashing algorithm!' : $g_aAlgIDs[$iIndex][1]) & @CRLF)
	If $vData = '' Then Return SetError(1, 0, '')
	If $iIndex = -1 Then Return SetError(2, 0, '')
	Local $bHashData = _Crypt_HashData($vData, $iAlgID), $iError = @error
	_Memo('- $bHashData     = ' & $bHashData & @CRLF)
	Return $iError ? SetError($iError, 0, '') : _AddBrackets($bHashData)
EndFunc   ;==>_GetHashData

;~ _Crypt_HashFile ( $sFilePath, $iAlgID )
Func _GetHashFile($sFilePath, $iAlgID = $CALG_MD2)
	Local $iIndex = _ArraySearch($g_aAlgIDs, $iAlgID)
	_Memo('> _GetHashFile("' & $sFilePath & '", 0x' & Hex($iAlgID) & ') ; ' & ($iIndex = -1 ? 'No Hashing algorithm!' : $g_aAlgIDs[$iIndex][1]) & @CRLF)
	If $iIndex = -1 Then Return SetError(2)
	Local $bHashFile = _Crypt_HashFile($sFilePath, $iAlgID), $iError = @error
	_Memo('- $bHashFile     = ' & $bHashFile & @CRLF)
	Return $iError ? SetError($iError, 0, '') : _AddBrackets($bHashFile)
EndFunc   ;==>_GetHashFile

Func _GetType($sString, $iType)
	If $sString = '' Then Return SetError(1, 0, '')
	Switch $iType
		Case $eString
			Return $sString
		Case $eFile
			Return FileExists($sString) ? FileRead($sString) : SetError(2, 0, '')
		Case Else
			Return SetError(3, 0, '')
	EndSwitch
EndFunc   ;==>_GetType

Func _AddBrackets($g_Hash)
	$g_Hash = '{' & $g_Hash & '}'
	Return $g_Hash
EndFunc

Func _SetWinTitle()
	Local $sTitle = @ScriptName & ' ' & _NowCalc() & ' TickCount:' & _Date_Time_GetTickCount() & ' ' & $g_Hash
;~ 	_Memo('> WinSetTitle(' & $g_hGUI & ', "", "' & $sTitle & '")' & @CRLF)
	WinSetTitle($g_hGUI, '', $sTitle)
	Return $sTitle
EndFunc

; Total Commander Ultima Prime: ' Total Commander Ultima Prime 7.3 :: CPU: 022% (3,2 GHz) :: RAM: 078% (6,0 GB) :: C: 50% :: 09.09.2020 - 02:46:22 :: 03:07:43 ::'    <<== 1. Instanz
; Total Commander Ultima Prime: '[2] Total Commander Ultima Prime 7.3 :: CPU: 022% (3,2 GHz) :: RAM: 078% (6,0 GB) :: C: 50% :: 09.09.2020 - 02:46:22 :: 03:07:43 ::' <<== 2. Instanz
; Notepad++                   : 'F:\Eigene Dateien\TxT\ToDo.txt - Notepad++'
; SciTE                       : 'C:\Program Files (x86)\AutoIt3\Include\Misc.au3 - SciTE [20 von 20]'

;~ _WinGetHandle('^(\[\d+\])? Total Commander Ultima Prime.*', 'TTOTAL_CMD', 1) ; Titel beginnt bei der ersten Instanz mit einem Leerzeichen, bei weiteren mit '[n] '!
;~ _WinGetHandle('^(\[\d+\])? Total Commander Ultima Prime.*', 'TTOTAL_CMD')
;~ _WinGetHandle('.+( - Notepad++)', 'Notepad++')
;~ _WinGetHandle('.+( - SciTE).*', 'SciTEWindow')
;~ _WinGetHandle('.+( - SciTE).*', 'SciTE Window') ; Fehler, weil $sClassName falsch
;~ _WinGetHandle('.+( - SciTE).*')

Func _WinGetHandle($sTitle, $sClassName = '', $iInstance = -1) ; -1 = alle suchen (Array, wenn mehr als 1 Treffer), 1 = nur zuletzt aktives
	Local $sPattern, $hWnd, $aWnd[0], $sFullTitle, $iLoop = $iInstance

	_Memo('> _WinGetHandle("' & $sTitle & '", "' & $sClassName & '", ' & $iInstance & ')' & @CRLF)
	If $iInstance < 1 Then $iInstance = 1

	While 1
		$sPattern = '[REGEXPTITLE:' & $sTitle & ($sClassName ? '; CLASS:' & $sClassName : '') & '; INSTANCE:' & $iInstance & ']'
		_Memo('+ $sPattern      = ' & $sPattern & @CRLF)
		$hWnd = WinGetHandle($sPattern)
		_Memo((IsHWnd($hWnd) ? '- ' : '! ') & '$hWnd          = ' & $hWnd & @CRLF)
		If Not IsHWnd($hWnd) Then ExitLoop
		_ArrayAdd($aWnd, $hWnd)
		If $sClassName = '' Then $sClassName = _WinAPI_GetClassName($hWnd)
		_Memo('- $sClassName    = ' & $sClassName & @CRLF)
		Local $sFullTitle = WinGetTitle($hWnd)
		_Memo('- $sFullTitle    = ' & $sFullTitle & @CRLF)
		If $iLoop > 0 Then ExitLoop
		$iInstance += 1
	WEnd
	_Memo($g_sSpacer & @CRLF & @CRLF)
	If UBound($aWnd) > 1 Then _ArrayDisplay($aWnd, '$aWnd', '', 0, Default, $sClassName)
	Return UBound($aWnd) > 1 ? $aWnd : IsHWnd($hWnd) ? $hWnd : SetError(1)
EndFunc   ;==>_WinGetHandle

Func _Memo($sText)
	If IsHWnd($g_hEdit) Then
		_GUICtrlEdit_AppendText($g_hEdit, $sText)
	Else
		$g_sMemoBuffer &= $sText
	EndIf
EndFunc

Func _Exit()
	_Crypt_Shutdown() ; Shutdown the crypt library.
EndFunc
