#include-once
#include <EditConstants.au3>
#include <File.au3>
#include <FileConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiImageList.au3>
#include <GuiListView.au3>
#include <GuiTreeView.au3>
#include <ListViewConstants.au3>
#include <SendMessage.au3>
#include <StructureConstants.au3>
#include <TreeViewConstants.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>

Global $hSelectFileOrFolder_Folder, $aSelectFileOrFolder_Language, $cSelectFileOrFolder_DummyFolder, $cSelectFileOrFolder_Path, $fSelectFileOrFolder_Open
Global Const $tagSHFILEINFO = 'ptr hIcon; int iIcon; DWORD dwAttributes; CHAR szDisplayName[255]; CHAR szTypeName[80];'
Global Const $SHGFI_USEFILEATTRIBUTES = 0x10
Global Const $SHGFI_SYSICONINDEX = 0x4000
Global Const $SHGFI_SMALLICON = 0x1
Global Const $SHGFI_LARGEICON = 0x0

;===============================================================================
; Name:             : _SelectFileOrFolder([$sMsg][,$sStartFolder][,$iOptions][,$fBigIcons][,$iLanguage][,$iLeft][,$iTop][,$iWidth][,$iHeight][,$hParent])
; Description       : Öffnet ein Auswahlfenster, in dem man eine Datei oder ein Verzeichnis auswählen kann
; Parameter(s)      : $sMsg = Eine Nachricht, die dem Benutzer angezeigt wird
;                     $sStartFolder = Startverzeichnis, welches beim öffnen automatisch angezeigt wird
;                     $iOptions = [0] -> Dateien und Ordner; [1] -> Dateien und Ordner, aber Mehrfachauswahl bei Dateien; [2] -> nur Ordner
;                     $fBigIcons = TRUE -> große Icons, FALSE -> kleine Icons
;                     $iLanguage = 0 -> deutsch, 1 -> englisch
;                     $iLeft/$iTop = Linke, obere Ecke des Fensters, -1 = zentriert
;                     $iWidth = Breite des Fensters
;                     $iHeight = Höhe des Fensters
;                     $hParent = Das Handle eines anderen, zuvor erstellten Fensters. Das Auswahlfenster wird dann ein Child davon
; Requirement       : siehe obige Includes und die globalen Variablen
; Return Value(s)   : bei [Ok] ist @error = 0 und es wird der ausgewählte Pfad (Verzeichnis oder Datei/en) als Array ($array[0] = Anzahl) zurückgegeben.
;                     Wurde nichts ausgewählt ist @error = 2 und die Rückgabe ein Leerstring
;                     bei [Cancel] ist @error = 1 und die Rückgabe ein Leerstring
; Author(s)         : Oscar (www.autoit.de)
; Example           : Ja
;===============================================================================
Func _SelectFileOrFolder($sMsg = 'Please select a file or folder...', $sStartFolder = '', $iOptions = 1, $fBigIcons = True, $iLanguage = 1, $iLeft = -1, $iTop = -1, $iWidth = 800, $iHeight = 600, $hParent = '')
	If $iLeft = -1 Or $iLeft = Default Then $iLeft = Default
	If $iTop = -1 Or $iTop = Default Then $iTop = Default
	If $iWidth = -1 Or $iWidth = Default Then $iWidth = 800
	If $iHeight = -1 Or $iHeight = Default Then $iHeight = 600
	Local $aStartFolder[1] = [0]
	If FileExists($sStartFolder) Then
		If StringRight($sStartFolder, 1) <> '\' Then $sStartFolder &= '\'
		$aStartFolder = StringSplit(StringTrimRight($sStartFolder, 1), '\')
	EndIf
	$fSelectFileOrFolder_Open = False
	_SelectLanguage($iLanguage)
	Local Const $sDelim = '\', $sDelim1 = '|'
	Local $cFiles, $iFileMode = BitOR($LVS_SHOWSELALWAYS, $LVS_SINGLESEL), $iFolderSize = 320
	Local $hItem, $sPath, $aFileList, $sReturn = '', $sHeader = $aSelectFileOrFolder_Language[2]
	If BitAND($iOptions, 1) Then $iFileMode = $LVS_SHOWSELALWAYS
	If BitAND($iOptions, 2) Then $iFolderSize = 780
	Local $iOldMode = Opt('GUIOnEventMode', 0)
	Local $iOldSeparator = Opt('GUIDataSeparatorChar', '|')
	Local $hGui = GUICreate($aSelectFileOrFolder_Language[0], 800, 600, -1, -1, BitOR($WS_BORDER, $WS_CAPTION, $WS_SIZEBOX), Default, $hParent)
	GUISetIcon('shell32.dll', 23, $hGui)
	GUICtrlCreateLabel($sMsg, 20, 10, 760, 20)
	GUICtrlSetResizing(-1, $GUI_DOCKLEFT + $GUI_DOCKRIGHT + $GUI_DOCKTOP + $GUI_DOCKHEIGHT)
	GUICtrlSetFont(-1, 12, 400, 2, 'Arial', 5)
	GUICtrlCreateGroup($aSelectFileOrFolder_Language[1], 10, 44, 780, 50)
	GUICtrlSetResizing(-1, $GUI_DOCKHCENTER + $GUI_DOCKTOP + $GUI_DOCKHEIGHT)
	GUICtrlSetFont(-1, 9, 400, 0, 'Verdana', 5)
	$cSelectFileOrFolder_Path = GUICtrlCreateInput('', 20, 60, 760, 25, BitOR($ES_LEFT, $ES_AUTOHSCROLL, $ES_READONLY))
	GUICtrlSetResizing(-1, $GUI_DOCKHCENTER + $GUI_DOCKTOP + $GUI_DOCKHEIGHT)
	GUICtrlSetFont(-1, 10, 400, 0, 'Arial', 5)
	GUICtrlSetBkColor(-1, 0xF8F8F8)
	GUICtrlCreateGroup('', -99, -99, 1, 1)
	Local $cFolder = GUICtrlCreateTreeView(10, 100, $iFolderSize, 460, BitOR($TVS_HASBUTTONS, $TVS_HASLINES, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS), $WS_EX_CLIENTEDGE)
	GUICtrlSetFont(-1, 10, 400, 0, 'Arial', 5)
	GUICtrlSetResizing(-1, $GUI_DOCKHCENTER + $GUI_DOCKTOP + $GUI_DOCKBOTTOM)
	If Not BitAND($iOptions, 2) Then
		$cFiles = GUICtrlCreateListView($sHeader, 340, 100, 450, 460, $iFileMode)
		GUICtrlSetResizing(-1, $GUI_DOCKHCENTER + $GUI_DOCKTOP + $GUI_DOCKBOTTOM)
	EndIf
	Local $cNewFolder = GUICtrlCreateButton($aSelectFileOrFolder_Language[3], 10, 570, 140, 22)
	GUICtrlSetResizing(-1, $GUI_DOCKSIZE + $GUI_DOCKLEFT + $GUI_DOCKBOTTOM)
	GUICtrlSetState(-1, $GUI_DISABLE)
	Local $cOk = GUICtrlCreateButton($aSelectFileOrFolder_Language[4], 650, 570, 60, 22)
	GUICtrlSetResizing(-1, $GUI_DOCKSIZE + $GUI_DOCKRIGHT + $GUI_DOCKBOTTOM)
	Local $cCancel = GUICtrlCreateButton($aSelectFileOrFolder_Language[5], 720, 570, 70, 22)
	GUICtrlSetResizing(-1, $GUI_DOCKSIZE + $GUI_DOCKRIGHT + $GUI_DOCKBOTTOM)
	$cSelectFileOrFolder_DummyFolder = GUICtrlCreateDummy()
	$hSelectFileOrFolder_Folder = GUICtrlGetHandle($cFolder)
	Local $hFiles = GUICtrlGetHandle($cFiles), $aColWidth[5] = [208, 60, 100, 120, 40]
	For $i = 0 To 4
		_GUICtrlListView_SetColumnWidth($hFiles, $i, $aColWidth[$i])
	Next
	_GUICtrlListView_JustifyColumn($hFiles, 2, 1)
	Local $iFilesCount
	Local $hImage = _GUIImageList_Create(16 + (16 * $fBigIcons), 16 + (16 * $fBigIcons), 5, 1, 11)
	_GUIImageList_AddIcon($hImage, 'shell32.dll', 3, $fBigIcons) ; Verzeichnis-Icon
	_GUIImageList_AddIcon($hImage, 'shell32.dll', 110, $fBigIcons) ; Verzeichnis-Icon mit Haken
	_GUIImageList_AddIcon($hImage, 'shell32.dll', 1, $fBigIcons) ; Datei-Icon
	_GUIImageList_AddIcon($hImage, 'shell32.dll', 5, $fBigIcons) ; Diskette
	_GUIImageList_AddIcon($hImage, 'shell32.dll', 7, $fBigIcons) ; Wechseldatenträger
	_GUIImageList_AddIcon($hImage, 'shell32.dll', 8, $fBigIcons) ; Festplatte
	_GUIImageList_AddIcon($hImage, 'shell32.dll', 11, $fBigIcons) ; CDROM
	_GUIImageList_AddIcon($hImage, 'shell32.dll', 12, $fBigIcons) ; RAM-Disk
	_GUIImageList_AddIcon($hImage, 'shell32.dll', 9, $fBigIcons) ; Netzwerklaufwerk
	_GUIImageList_AddIcon($hImage, 'shell32.dll', 53, $fBigIcons) ; Unbekannt
	_GUIImageList_AddIcon($hImage, 'shell32.dll', 15, $fBigIcons) ; Computer
	_GUICtrlTreeView_SetNormalImageList($hSelectFileOrFolder_Folder, $hImage)
	_GUICtrlTreeView_SetHeight($hSelectFileOrFolder_Folder, 20 + (20 * $fBigIcons))
	If Not BitAND($iOptions, 2) Then _GUICtrlListView_SetImageList($cFiles, _GUIImageList_GetSystemImageList($fBigIcons), 1)
	GUISetState()
	WinMove($hGui, '', $iLeft, $iTop, $iWidth, $iHeight)
	Local $aDrives = DriveGetDrive('ALL'), $iLWindex, $hRoot, $hComputer
	ToolTip($aSelectFileOrFolder_Language[6], Default, Default, $aSelectFileOrFolder_Language[7], 1)
	$hRoot = _GUICtrlTreeView_Add($hSelectFileOrFolder_Folder, 0, $aSelectFileOrFolder_Language[8], 10, 10)
	_GUICtrlTreeView_BeginUpdate($hSelectFileOrFolder_Folder)
	Local $ahDrives[$aDrives[0]]
	For $i = 1 To $aDrives[0]
		$iLWindex = 0
		Switch DriveGetType($aDrives[$i])
			Case 'Fixed'
				$iLWindex = 5
			Case 'CDROM'
				$iLWindex = 6
			Case 'RAMDisk'
				$iLWindex = 7
			Case 'NETWORK'
				$iLWindex = 8
			Case 'Removable'
				$iLWindex = 4
				If StringLeft($aDrives[$i], 2) = 'a:' Or StringLeft($aDrives[$i], 2) = 'b:' Then $iLWindex = 3
			Case Else
				$iLWindex = 9
		EndSwitch
		$ahDrives[$i - 1] = _GUICtrlTreeView_AddChild($hSelectFileOrFolder_Folder, $hRoot, StringUpper($aDrives[$i]), $iLWindex, $iLWindex)
		If DriveStatus($aDrives[$i]) = 'READY' Then
			_ReadFolder($hSelectFileOrFolder_Folder, $ahDrives[$i - 1], $aDrives[$i])
		EndIf
	Next
	Local $hFoundItem = 0, $sFoundPath = '', $hFirstChild, $hChild
	GUIRegisterMsg($WM_NOTIFY, '_SelectFileOrFolder_WM_NOTIFY')
	If $sStartFolder <> '' Then
		For $i = 1 To $aStartFolder[0]
			$hFoundItem = _GUICtrlTreeView_FindChild($hSelectFileOrFolder_Folder, $aStartFolder[$i], $hFoundItem)
			_SendMessage($hSelectFileOrFolder_Folder, $TVM_EXPAND, $TVE_EXPAND, $hFoundItem, 0, 'wparam', 'handle')
		Next
		_GUICtrlTreeView_SelectItem($hSelectFileOrFolder_Folder, $hFoundItem, $TVGN_CARET)
		_GUICtrlTreeView_SelectItem($hSelectFileOrFolder_Folder, $hFoundItem, $TVGN_FIRSTVISIBLE)
		GUICtrlSendToDummy($cSelectFileOrFolder_DummyFolder)
	Else
		_SendMessage($hSelectFileOrFolder_Folder, $TVM_EXPAND, $TVE_EXPAND, $hRoot, 0, 'wparam', 'handle')
	EndIf
	$fSelectFileOrFolder_Open = True
	ToolTip('')
	_GUICtrlTreeView_EndUpdate($hSelectFileOrFolder_Folder)
	While True
		Switch GUIGetMsg()
			Case $GUI_EVENT_CLOSE, $cCancel
				GUIRegisterMsg($WM_NOTIFY, '')
				GUIDelete($hGui)
				Opt('GUIOnEventMode', $iOldMode)
				Opt('GUIDataSeparatorChar', $iOldSeparator)
				ToolTip('')
				Return SetError(1, 0, '')
			Case $cOk
				$sPath = GUICtrlRead($cSelectFileOrFolder_Path) & '\'
				$sReturn = $sPath
				If _GUICtrlListView_GetSelectedCount($hFiles) > 0 Then
					$aSelIndices = StringSplit(ControlListView($hGui, '', $hFiles, 'GetSelected', 1), '|')
					$sReturn = ''
					For $i = 1 To $aSelIndices[0]
						$aItems = _GUICtrlListView_GetItemTextArray($hFiles, $aSelIndices[$i])
						If $aItems[1] <> '' Then $sReturn &= $sPath & $aItems[1] & '.' & $aItems[2] & '|'
					Next
					$sReturn = StringTrimRight($sReturn, 1)
				EndIf
				GUIRegisterMsg($WM_NOTIFY, '')
				GUIDelete($hGui)
				Opt('GUIOnEventMode', $iOldMode)
				Opt('GUIDataSeparatorChar', $iOldSeparator)
				ToolTip('')
				If $sPath = '\' Then Return SetError(2, 0, '')
				Return SetError(0, 0, StringSplit($sReturn, '|'))
			Case $cNewFolder
				Local $sNewFolder = InputBox($aSelectFileOrFolder_Language[0], $aSelectFileOrFolder_Language[3] & ':', '', '', 320, 130, Default, Default, 0, $hGui)
				If Not @error And $sNewFolder <> '' Then
					$hItem = _GUICtrlTreeView_GetSelection($hSelectFileOrFolder_Folder)
					$sPath = StringReplace(_GUICtrlTreeView_GetTree($hSelectFileOrFolder_Folder, $hItem), $sDelim1, $sDelim)
					$sPath = StringRegExpReplace($sPath, '(?i).*([[:alpha:]]\:.*)', '$1')
					If StringRight($sPath, 1) <> '\' Then $sPath &= '\'
					Local $aDelChar = StringSplit('< > ? " : | \ / *', ' ')
					For $i = 1 To $aDelChar[0]
						$sNewFolder = StringReplace($sNewFolder, $aDelChar[$i], '')
					Next
					If DirCreate($sPath & $sNewFolder) Then _GUICtrlTreeView_AddChild($hSelectFileOrFolder_Folder, $hItem, $sNewFolder, 0, 1)
				EndIf
			Case $cSelectFileOrFolder_DummyFolder
				$hItem = _GUICtrlTreeView_GetSelection($hSelectFileOrFolder_Folder)
				$sPath = StringReplace(_GUICtrlTreeView_GetTree($hSelectFileOrFolder_Folder, $hItem), $sDelim1, $sDelim)
				$sPath = StringRegExpReplace($sPath, '(?i).*([[:alpha:]]\:.*)', '$1')
				If $sPath = _GUICtrlTreeView_GetText($hSelectFileOrFolder_Folder, $hRoot) Then
					_GUICtrlListView_DeleteAllItems($hFiles)
					$sPath = ''
					GUICtrlSetState($cNewFolder, $GUI_DISABLE)
					_GuiCtrlSetPath($cSelectFileOrFolder_Path, $sPath)
					ContinueLoop
				EndIf
				GUICtrlSetState($cNewFolder, $GUI_ENABLE)
				_GuiCtrlSetPath($cSelectFileOrFolder_Path, $sPath)
				ToolTip($aSelectFileOrFolder_Language[6], Default, Default, $aSelectFileOrFolder_Language[7], 1)
				If Not BitAND($iOptions, 2) Then
					_GUICtrlListView_BeginUpdate($hFiles)
					_GUICtrlListView_DeleteAllItems($hFiles)
					If StringRight($sPath, 1) <> '\' Then $sPath &= '\'
					If DriveStatus(StringLeft($sPath, 2)) = 'READY' Then
						$iFilesCount = 0
						$aFiles = _FileListToArray($sPath, '*', 1)
						If Not @error Then
							Local $aItems[$aFiles[0]][6]
							_GUICtrlListView_SetItemCount($hFiles, $aFiles[0])
							For $i = 1 To $aFiles[0]
								$sAttr = StringRegExpReplace(FileGetAttrib($sPath & $aFiles[$i]), '[NDOCT]', '')
								$aDate = FileGetTime($sPath & $aFiles[$i], 0, 0)
								$sDate = $aDate[2] & '.' & $aDate[1] & '.' & $aDate[0] & ' ' & $aDate[3] & ':' & $aDate[4] & ':' & $aDate[5]
								$iSize = FileGetSize($sPath & $aFiles[$i])
								$sName = StringRegExpReplace($aFiles[$i], '(.*)\..*', '$1')
								$sExt = StringRegExpReplace($aFiles[$i], '.*\.(.*)', '$1')
								If $sExt = $aFiles[$i] Then $sExt = ''
								$aItems[$iFilesCount][0] = _GUIImageList_GetFileIconIndex($sPath & $aFiles[$i], $fBigIcons)
								$aItems[$iFilesCount][1] = $sName
								$aItems[$iFilesCount][2] = $sExt
								$aItems[$iFilesCount][3] = _StringAddThousandsSep($iSize)
								$aItems[$iFilesCount][4] = $sDate
								$aItems[$iFilesCount][5] = $sAttr
								$iFilesCount += 1
							Next
							If $iFilesCount > 0 Then
								ReDim $aItems[$iFilesCount][6]
								_GUICtrlListView_AddArrayEx($cFiles, $aItems)
							EndIf
						EndIf
					EndIf
					_GUICtrlListView_EndUpdate($hFiles)
				EndIf
				ToolTip('')
		EndSwitch
	WEnd
EndFunc   ;==>_SelectFileOrFolder

Func _GUICtrlTreeView_FindChild($hWnd, $sPath, $hChild = 0)
	$hChild = _GUICtrlTreeView_GetFirstChild($hWnd, $hChild)
	If _GUICtrlTreeView_GetText($hWnd, $hChild) = $sPath Then Return $hChild
	Do
		$hChild = _GUICtrlTreeView_GetNextChild($hWnd, $hChild)
		If _GUICtrlTreeView_GetText($hWnd, $hChild) = $sPath Then Return $hChild
	Until Not $hChild
	Return 0
EndFunc   ;==>_GUICtrlTreeView_FindChild

; Bei dieser Version von _GUICtrlListView_AddArray kann man auch den Image-Index angeben
Func _GUICtrlListView_AddArrayEx($hWnd, ByRef $aItems)
	Local $fUnicode, $tItem, $pItem, $tBuffer, $pBuffer, $iLastItem
	$fUnicode = _GUICtrlListView_GetUnicodeFormat($hWnd)
	$tItem = DllStructCreate($tagLVITEM)
	$pItem = DllStructGetPtr($tItem)
	If $fUnicode Then
		$tBuffer = DllStructCreate('wchar Text[4096]')
	Else
		$tBuffer = DllStructCreate('char Text[4096]')
	EndIf
	$pBuffer = DllStructGetPtr($tBuffer)
	DllStructSetData($tItem, 'Mask', BitOR($LVIF_TEXT, $LVIF_IMAGE)) ; <- $LVIF_IMAGE hinzugefügt
	DllStructSetData($tItem, 'Text', $pBuffer)
	DllStructSetData($tItem, 'TextMax', 4096)
	$iLastItem = _GUICtrlListView_GetItemCount($hWnd)
	For $i = 0 To UBound($aItems) - 1
		DllStructSetData($tItem, 'Item', $i + $iLastItem)
		DllStructSetData($tItem, 'SubItem', 0)
		DllStructSetData($tItem, 'Image', $aItems[$i][0]) ; <- Den Image-Index als Element 0 im Array
		DllStructSetData($tBuffer, 'Text', $aItems[$i][1])
		If $fUnicode Then
			GUICtrlSendMsg($hWnd, $LVM_INSERTITEMW, 0, $pItem)
		Else
			GUICtrlSendMsg($hWnd, $LVM_INSERTITEMA, 0, $pItem)
		EndIf
		For $j = 2 To UBound($aItems, 2) - 1
			DllStructSetData($tItem, 'SubItem', $j - 1)
			DllStructSetData($tBuffer, 'Text', $aItems[$i][$j])
			If $fUnicode Then
				GUICtrlSendMsg($hWnd, $LVM_SETITEMW, 0, $pItem)
			Else
				GUICtrlSendMsg($hWnd, $LVM_SETITEMA, 0, $pItem)
			EndIf
		Next
	Next
	$tItem = 0
	$tBuffer = 0
EndFunc   ;==>_GUICtrlListView_AddArrayEx

; Author: progandy (www.autoit.de)
Func _GUIImageList_GetSystemImageList($bLargeIcons = False)
	Local $dwFlags, $hIml, $FileInfo = DllStructCreate($tagSHFILEINFO)
	$dwFlags = BitOR($SHGFI_USEFILEATTRIBUTES, $SHGFI_SYSICONINDEX)
	If Not ($bLargeIcons) Then
		$dwFlags = BitOR($dwFlags, $SHGFI_SMALLICON)
	EndIf
;~    '// Load the image list - use an arbitrary file extension for the
;~    '// call to SHGetFileInfo (we don't want to touch the disk, so use
;~    '// FILE_ATTRIBUTE_NORMAL && SHGFI_USEFILEATTRIBUTES).
	$hIml = _WinAPI_SHGetFileInfo(".txt", $FILE_ATTRIBUTE_NORMAL, _
			DllStructGetPtr($FileInfo), DllStructGetSize($FileInfo), $dwFlags)
	Return $hIml
EndFunc   ;==>_GUIImageList_GetSystemImageList

; Author: progandy (www.autoit.de)
Func _WinAPI_SHGetFileInfo($pszPath, $dwFileAttributes, $psfi, $cbFileInfo, $uFlags)
	Local $return = DllCall("shell32.dll", "dword_ptr", "SHGetFileInfo", "str", $pszPath, "DWORD", $dwFileAttributes, "ptr", $psfi, "UINT", $cbFileInfo, "UINT", $uFlags)
	If @error Then Return SetError(@error, 0, 0)
	Return $return[0]
EndFunc   ;==>_WinAPI_SHGetFileInfo

; Author: progandy (www.autoit.de)
Func _GUIImageList_GetFileIconIndex($sFileSpec, $bLargeIcons = False, $bForceLoadFromDisk = False)
	Local $dwFlags, $FileInfo = DllStructCreate($tagSHFILEINFO)
	$dwFlags = $SHGFI_SYSICONINDEX
	If $bLargeIcons Then
		$dwFlags = BitOR($dwFlags, $SHGFI_LARGEICON)
	Else
		$dwFlags = BitOR($dwFlags, $SHGFI_SMALLICON)
	EndIf
;~ ' We choose whether to access the disk or not. If you don't
;~ ' hit the disk, you may get the wrong icon if the icon is
;~ ' not cached. But the speed is very good!
	If Not $bForceLoadFromDisk Then $dwFlags = BitOR($dwFlags, $SHGFI_USEFILEATTRIBUTES)
;~ ' sFileSpec can be any file. You can specify a
;~ ' file that does not exist and still get the
;~ ' icon, for example sFileSpec = "C:\PANTS.DOC"
	Local $lR = _WinAPI_SHGetFileInfo( _
			$sFileSpec, $FILE_ATTRIBUTE_NORMAL, DllStructGetPtr($FileInfo), DllStructGetSize($FileInfo), _
			$dwFlags _
			)
	If ($lR = 0) Then
		Return SetError(1, 0, -1)
	Else
		Return DllStructGetData($FileInfo, "iIcon")
	EndIf
EndFunc   ;==>_GUIImageList_GetFileIconIndex

; #FUNCTION# ====================================================================================================================
; Name...........: _StringAddThousandsSep
; Description ...: Returns the original numbered string with the Thousands delimiter inserted.
; Syntax.........: _StringAddThousandsSep($sString[, $sThousands = -1[, $sDecimal = -1]])
; Parameters ....: $sString    - The string to be converted.
;                  $sThousands - Optional: The Thousands delimiter
;                  $sDecimal   - Optional: The decimal delimiter
; Return values .: Success - The string with Thousands delimiter added.
; Author ........: SmOke_N (orignal _StringAddComma
; Modified.......: Valik (complete re-write, new function name)
; ===============================================================================================================================
Func _StringAddThousandsSep($sString, $sThousands = -1, $sDecimal = -1)
	If $sString = '-' Then Return $sString ; This Line is only for FileCommander
	Local $sResult = "" ; Force string
	Local $rKey = "HKCU\Control Panel\International"
	If $sDecimal = -1 Then $sDecimal = RegRead($rKey, "sDecimal")
	If $sThousands = -1 Then $sThousands = RegRead($rKey, "sThousand")
	Local $aNumber = StringRegExp($sString, "(\D?\d+)\D?(\d*)", 1) ; This one works for negatives.
	If UBound($aNumber) = 2 Then
		Local $sLeft = $aNumber[0]
		While StringLen($sLeft)
			$sResult = $sThousands & StringRight($sLeft, 3) & $sResult
			$sLeft = StringTrimRight($sLeft, 3)
		WEnd
		$sResult = StringTrimLeft($sResult, StringLen($sThousands)) ; Strip leading thousands separator
		If $aNumber[1] <> "" Then $sResult &= $sDecimal & $aNumber[1]
	EndIf
	Return $sResult
EndFunc   ;==>_StringAddThousandsSep

Func _SelectFileOrFolder_WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
	Local $hItem, $hChild, $sPath, $tNMTREEVIEW = DllStructCreate($tagNMTREEVIEW, $ilParam)
	Local Const $sDelim = '\', $sDelim1 = '|'
	If DllStructGetData($tNMTREEVIEW, 'hWndFrom') = $hSelectFileOrFolder_Folder Then
		Switch DllStructGetData($tNMTREEVIEW, 'Code')
			Case $NM_CLICK
				GUICtrlSendToDummy($cSelectFileOrFolder_DummyFolder)
			Case $TVN_ITEMEXPANDINGA, $TVN_ITEMEXPANDINGW
				Switch DllStructGetData($tNMTREEVIEW, 'Action')
					Case $TVE_EXPAND
						$hItem = DllStructGetData($tNMTREEVIEW, 'NewhItem')
						If _GUICtrlTreeView_GetText($hSelectFileOrFolder_Folder, $hItem) = $aSelectFileOrFolder_Language[8] Then Return $GUI_RUNDEFMSG
						If _GUICtrlTreeView_GetExpanded($hSelectFileOrFolder_Folder, $hItem) Then Return $GUI_RUNDEFMSG
						_GUICtrlTreeView_SelectItem($hSelectFileOrFolder_Folder, $hItem, $TVGN_CARET)
						$hChild = _GUICtrlTreeView_GetFirstChild($hSelectFileOrFolder_Folder, $hItem)
						If Not $hChild Then Return $GUI_RUNDEFMSG
						ToolTip($aSelectFileOrFolder_Language[6], Default, Default, $aSelectFileOrFolder_Language[7], 1)
						If $fSelectFileOrFolder_Open Then _GUICtrlTreeView_BeginUpdate($hSelectFileOrFolder_Folder)
						_GUICtrlTreeView_DeleteChildren($hSelectFileOrFolder_Folder, $hChild)
						$sPath = StringReplace(_GUICtrlTreeView_GetTree($hSelectFileOrFolder_Folder, $hChild), $sDelim1, $sDelim)
						$sPath = StringRegExpReplace($sPath, '(?i).*([[:alpha:]]\:.*)', '$1')
						_ReadFolder($hSelectFileOrFolder_Folder, $hChild, $sPath)
						Do
							$hChild = _GUICtrlTreeView_GetNextChild($hSelectFileOrFolder_Folder, $hChild)
							If Not $hChild Then ExitLoop
							_GUICtrlTreeView_DeleteChildren($hSelectFileOrFolder_Folder, $hChild)
							$sPath = StringReplace(_GUICtrlTreeView_GetTree($hSelectFileOrFolder_Folder, $hChild), $sDelim1, $sDelim)
							$sPath = StringRegExpReplace($sPath, '(?i).*([[:alpha:]]\:.*)', '$1')
							_ReadFolder($hSelectFileOrFolder_Folder, $hChild, $sPath)
						Until False
						If $fSelectFileOrFolder_Open Then _GUICtrlTreeView_EndUpdate($hSelectFileOrFolder_Folder)
						ToolTip('')
					Case $TVE_COLLAPSE
						$hItem = DllStructGetData($tNMTREEVIEW, 'NewhItem')
						If _GUICtrlTreeView_GetText($hSelectFileOrFolder_Folder, $hItem) = $aSelectFileOrFolder_Language[8] Then Return $GUI_RUNDEFMSG
						_GUICtrlTreeView_SelectItem($hSelectFileOrFolder_Folder, $hItem, $TVGN_CARET)
						Local $sPath = StringReplace(_GUICtrlTreeView_GetTree($hSelectFileOrFolder_Folder, $hItem), $sDelim1, $sDelim)
						$sPath = StringRegExpReplace($sPath, '(.+\\).+', '$1')
						$sPath = StringRegExpReplace($sPath, '(?i).*([[:alpha:]]\:.*)', '$1')
						If StringLen($sPath) < 3 Then $sPath = ''
						_GuiCtrlSetPath($cSelectFileOrFolder_Path, $sPath)
				EndSwitch
		EndSwitch
	EndIf
	Return $GUI_RUNDEFMSG
EndFunc   ;==>_SelectFileOrFolder_WM_NOTIFY

Func _ReadFolder($hFolder, $hItem, $sPath)
	Local Const $sDelim = '\', $sDelim1 = '|'
	Local $hSearch, $sFile
	$hSearch = FileFindFirstFile($sPath & $sDelim & '*')
	If $hSearch = -1 Then Return True
	Do
		$sFile = FileFindNextFile($hSearch)
		If @error Then ExitLoop
		If @extended And Not _IsReparsePoint($sPath & $sDelim & $sFile) Then _GUICtrlTreeView_AddChild($hFolder, $hItem, $sFile, 0, 1)
	Until False
	FileClose($hSearch)
EndFunc   ;==>_ReadFolder

Func _IsReparsePoint($FLS) ; coded by progandy
	Local $DA = DllCall('kernel32.dll', 'dword', 'GetFileAttributesW', 'wstr', $FLS)
	If @error Then Return SetError(1, @error, False)
	Return BitAND($DA[0], 1024) = 1024
EndFunc   ;==>_IsReparsePoint

Func _GuiCtrlSetPath($nID, $sPath, $iFit = 0)
	; coded by funkey
	; 2011, Nov 24th
	Local $hCtrl = GUICtrlGetHandle($nID)
	Local $hDC = _WinAPI_GetDC($hCtrl)
	Local $tPath = DllStructCreate("char[260]")
	Local $pPath = DllStructGetPtr($tPath)
	DllStructSetData($tPath, 1, $sPath)
	Local $hFont = _SendMessage($hCtrl, 49, 0, 0, 0, "wparam", "lparam", "hwnd")
	Local $hFont_old = _WinAPI_SelectObject($hDC, $hFont)
	Local $aPos = ControlGetPos($hCtrl, "", "")
	DllCall("Shlwapi.dll", "BOOL", "PathCompactPath", "handle", $hDC, "ptr", $pPath, "int", $aPos[2] - $iFit)
	_WinAPI_SelectObject($hDC, $hFont_old)
	_WinAPI_DeleteDC($hDC)
	GUICtrlSetData($nID, DllStructGetData($tPath, 1))
	Return DllStructGetData($tPath, 1)
EndFunc   ;==>_GuiCtrlSetPath

Func _SelectLanguage($iLanguage)
	Switch $iLanguage
		Case 0 ; Deutsch
			Local $aLanguage[9] = ['Datei- / Verzeichnisauswahl', 'Pfad:', 'Dateiname|Erw.|Größe|Datum|Attr.', 'Neuen Ordner erstellen', 'Ok', 'Abbrechen', 'Bitte warten...', 'Lese Verzeichnis', 'Computer']
		Case Else ; Englisch
			Local $aLanguage[9] = ['File / Folder Select', 'Path:', 'Filename|Ext.|Size|Date|Attr.', 'Create New Folder', 'Ok', 'Cancel', 'Please wait...', 'Read directory', 'Computer']
	EndSwitch
	$aSelectFileOrFolder_Language = $aLanguage
EndFunc   ;==>_SelectLanguage

