; http://autoit-script.ru/index.php?topic=3725.0
#Include <GUIConstantsEx.au3>
#Include <GUIImageList.au3>
#Include <GUITreeView.au3>
#Include <TreeViewConstants.au3>
#Include <WindowsConstants.au3>
#Include <WinAPIEx.au3>
Opt('MustDeclareVars', 1)
Global $hForm, $hImageList, $hTreeView, $hIcon, $hSelect = 0, $hInput, $Input, $Dummy
Global $tSHSII, $Index, $Stock[3], $Count = 0, $sPath, $sRoot = @HomeDrive
Global $Cache[101][3] = [[0]], $Link[101][2] = [[0]]
$hForm = GUICreate('MyGUI', 600, 600)
$Input = GUICtrlCreateInput('', 20, 20, 560, 19)
$hInput = GUICtrlGetHandle(-1)
GUICtrlSetState(-1, $GUI_DISABLE)
;~$hTreeView = _GUICtrlTreeView_Create($hForm, 20, 50, 560, 530, BitOR($TVS_HASBUTTONS, $TVS_HASLINES, $TVS_LINESATROOT, $TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS), $WS_EX_CLIENTEDGE)
;~_GUICtrlTreeView_SetHeight($hTreeView, 18)
GUICtrlCreateTreeView(20, 50, 560, 526, -1, $WS_EX_CLIENTEDGE)
$hTreeView = GUICtrlGetHandle(-1)
$Dummy = GUICtrlCreateDummy()
$hImageList = _GUIImageList_Create(_WinAPI_GetSystemMetrics($SM_CXSMICON), _WinAPI_GetSystemMetrics($SM_CYSMICON), 5, 1)
If _WinAPI_GetVersion() >= '6.0' Then
	_WinAPI_SetWindowTheme($hTreeView, 'Explorer')
	$Stock[0] = $SIID_DOCNOASSOC
	$Stock[1] = $SIID_FOLDER
	$Stock[2] = $SIID_FOLDEROPEN
	For $i = 0 To 2
		$tSHSII = _WinAPI_ShellGetStockIconInfo($Stock[$i], BitOR($SHGSI_ICON, $SHGSI_SMALLICON))
		$hIcon = DllStructGetData($tSHSII, 'hIcon')
		_GUIImageList_ReplaceIcon($hImageList, -1, $hIcon)
		_WinAPI_DestroyIcon($hIcon)
	Next
Else
	$Stock[0] = 0
	$Stock[1] = 3
	$Stock[2] = 4
	For $i = 0 To 2
		_GUIImageList_AddIcon($hImageList, @SystemDir & '\shell32.dll', $Stock[$i])
	Next
EndIf
If _WinAPI_GetVersion() >= '6.1' Then
	Dim $hIcon[3]
	$hIcon[0] = _GUIImageList_GetIcon($hImageList, 1)
	$hIcon[1] = _WinAPI_ExtractIcon(@SystemDir & '\ntshrui.dll', 3, 1)
	$hIcon[2] = _WinAPI_AddIconOverlay($hIcon[0], $hIcon[1])
	_GUIImageList_ReplaceIcon($hImageList, -1, $hIcon[2])
	$hIcon[2] = _WinAPI_AddIconTransparency($hIcon[2], 50, 1)
	_GUIImageList_ReplaceIcon($hImageList, -1, $hIcon[2])
	For $i = 0 To 2
		_WinAPI_DestroyIcon($hIcon[$i])
	Next
Else
	$hIcon = _GUIImageList_GetIcon($hImageList, 1)
	_GUIImageList_ReplaceIcon($hImageList, -1, $hIcon)
	$hIcon = _WinAPI_AddIconTransparency($hIcon, 50, 1)
	_GUIImageList_ReplaceIcon($hImageList, -1, $hIcon)
	_WinAPI_DestroyIcon($hIcon)
EndIf
_GUICtrlTreeView_SetNormalImageList($hTreeView, $hImageList)
_GUICtrlTreeView_SetUnicodeFormat($hTreeView)
$sRoot = StringRegExpReplace(FileGetLongName($sRoot), '\\+\Z', '')
$sPath = StringRegExpReplace($sRoot, '^.*\\', '')
If StringInStr($sPath, ':') Then
	$sRoot &= '\'
	$sPath &= '\'
EndIf
If _WinAPI_PathIsDirectory($sRoot) Then
	$Index = _TVAddIcon($hTreeView, $sRoot)
	If Not _TVIsEmpty($sRoot) Then
		_GUICtrlTreeView_AddChild($hTreeView, _GUICtrlTreeView_AddChild($hTreeView, 0, $sPath, $Index, $Index), '', 0, 0)
	Else
		Switch @error
			Case 0 ; OK
				_GUICtrlTreeView_AddChild($hTreeView, 0, $sPath, $Index, $Index)
			Case 1 ; Access denied
				If StringInStr(FileGetAttrib($sRoot), 'H') Then
					$Index = 4
				Else
					$Index = 3
				EndIf
				_GUICtrlTreeView_AddChild($hTreeView, 0, $sPath, $Index, $Index)
			Case Else
		EndSwitch
	EndIf
EndIf
GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')
GUISetState()
_GUICtrlTreeView_Expand($hTreeView, _GUICtrlTreeView_GetFirstItem($hTreeView))
While 1
	Switch GUIGetMsg()
		Case $GUI_EVENT_CLOSE
			Exit
		Case $Dummy
			GUISetCursor(1, 1)
			_TVUpdate($hTreeView, GUICtrlRead($Dummy))
			GUISetCursor(2, 0)
	EndSwitch
WEnd
Func _TVAddIcon($hTV, $sPath, $fOpen = 0)
	Local $hIL, $hIcon = 0, $Hidden, $ID, $Index, $Item = 0
	Local $hImageList = _GUICtrlTreeView_GetNormalImageList($hTV)
	Local $Flags = BitOR($SHGFI_SMALLICON, $SHGFI_SYSICONINDEX)
	Local $tSHFI = DllStructCreate($tagSHFILEINFO)
	Local $Attrib = FileGetAttrib($sPath)
	If $fOpen Then
		$Flags = BitOR($SHGFI_OPENICON, $Flags)
	EndIf
	If StringInStr($Attrib, 'D') Then
		$hIL = _WinAPI_ShellGetFileInfo($sPath, $Flags, 0, $tSHFI)
		If Not $hIL Then
			If $fOpen Then
				Return 2
			Else
				Return 1
			EndIf
		EndIf
	Else
		$hIL = _WinAPI_ShellGetFileInfo($sPath, BitOR($SHGFI_ICON, $SHGFI_OVERLAYINDEX, $SHGFI_USEFILEATTRIBUTES, $Flags), 0, $tSHFI)
		If $hIL Then
			$hIcon = DllStructGetData($tSHFI, 'hIcon')
		ELse
			Return 0
		EndIf
	EndIf
	$Index = DllStructGetData($tSHFI, 'iIcon')
	If (Not _WinAPI_PathIsRoot($sPath)) And (StringInStr($Attrib, 'H')) Then
		$Hidden = 1
		$ID = 2
	Else
		$Hidden = 0
		$ID = 1
	EndIf
	For $i = 1 To $Cache[0][0]
		If $Cache[$i][0] = $Index Then
			$Item = $i
			ExitLoop
		EndIf
	Next
	If $Item Then
		If $Cache[$Item][$ID] <> -1 Then
			If $hIcon Then
				_WinAPI_DestroyIcon($hIcon)
			EndIf
			Return $Cache[$Item][$ID]
		EndIf
	Else
		$Cache[0][0] += 1
		If $Cache[0][0] > UBound($Cache) - 1 Then
			ReDim $Cache[$Cache[0][0] + 100][3]
		EndIf
		$Cache[$Cache[0][0]][0] = $Index
		$Cache[$Cache[0][0]][1] = -1
		$Cache[$Cache[0][0]][2] = -1
		$Item = $Cache[0][0]
	EndIf
	If Not $hIcon Then
		$hIcon = DllCall('comctl32.dll', 'handle', 'ImageList_GetIcon', 'handle', $hIL, 'int', _WinAPI_LoWord($Index), 'uint', _WinAPI_HiWord($Index))
		If (Not @error) And ($hIcon[0]) Then
			$hIcon = $hIcon[0]
		Else
			Return 0
		EndIf
	EndIf
	If $Hidden Then
		$hIcon = _WinAPI_AddIconTransparency($hIcon, 50, 1)
		If Not $hIcon Then
			Return 0
		EndIf
	EndIf
	$Index = _GUIImageList_ReplaceIcon($hImageList, -1, $hIcon)
	_WinAPI_DestroyIcon($hIcon)
	If $Index = -1 Then
		Return 0
	EndIf
	$Cache[$Item][$ID] = $Index
	Return $Index
EndFunc   ;==>_TVAddIcon
Func _TVGetPath($hTV, $hItem, $sRoot)
	Local $Path = ''
	For $i = 1 To $Link[0][0]
		If $Link[$i][0] = $hItem Then
			$Path = $Link[$i][1]
			ExitLoop
		EndIf
	Next
	If Not $Path Then
		$Path = StringRegExpReplace(_GUICtrlTreeView_GetTree($hTV, $hItem), '([|]+)|(\\[|])', '\\')
		If Not $Path Then
			Return ''
		EndIf
	EndIf
	If Not StringInStr($Path, ':') Then
		Return StringRegExpReplace($sRoot, '(\\[^\\]*(\\|)+)\Z', '\\') & $Path
	EndIf
	Return $Path
EndFunc   ;==>_TVGetPath
Func _TVIsEmpty($sPath)
	Local $hSearch, $Result = 1
	$hSearch = FileFindFirstFile($sPath & '\*')
	If $hSearch = -1 Then
		If @error Then
			Return 1
		Else
			If _WinAPI_PathIsDirectory($sPath) Then
				Return SetError(1, 0, 1)
			Else
				Return SetError(2, 0, 1)
			EndIf
		EndIf
	Else
		If True Then
			$Result = 0
		Else
			While 1
				FileFindNextFile($hSearch)
				If @error Then
					ExitLoop
				EndIf
				If @extended Then
					$Result = 0
					ExitLoop
				EndIf
			WEnd
		EndIf
	EndIf
	FileClose($hSearch)
	Return $Result
EndFunc   ;==>_TVIsEmpty
Func _TVSetPath($hTV, $hItem, $sRoot)
	GUICtrlSetData($Input, _WinAPI_PathCompactPath($hInput, _TVGetPath($hTV, $hItem, $sRoot), 554))
	$hSelect = $hItem
EndFunc   ;==>_TVSetPath
Func _TVUpdate($hTV, $hItem)
	Local $Path = StringRegExpReplace(_TVGetPath($hTV, $hItem, $sRoot), '\\+\Z', '')
	Local $hSearch, $File, $Index
;~	_WinAPI_LockWindowUpdate($hTV)
	_GUICtrlTreeView_Delete($hTV, _GUICtrlTreeView_GetFirstChild($hTV, $hItem))
	$hSearch = FileFindFirstFile($Path & '\*')
	If $hSearch = -1 Then
		If @error Then
		Else
			If _WinAPI_PathIsDirectory($Path) Then
				If StringInStr(FileGetAttrib($Path), 'H') Then
					$Index = 4
				Else
					$Index = 3
				EndIf
				_GUICtrlTreeView_SetSelectedImageIndex($hTV, $hItem, $Index)
				_GUICtrlTreeView_SetImageIndex($hTV, $hItem, $Index)
			Else
				_GUICtrlTreeView_Delete($hTV, $hItem)
;				_WinAPI_LockWindowUpdate(0)
				Return 0
			EndIf
		EndIf
	Else
		While 1
			$File = FileFindNextFile($hSearch)
			If @error Then
				ExitLoop
			EndIf
			If @extended Then
				$Index = _TVAddIcon($hTV, $Path & '\' & $File)
				If Not _TVIsEmpty($Path & '\' & $File) Then
					_GUICtrlTreeView_AddChild($hTV, _GUICtrlTreeView_AddChild($hTV, $hItem, $File, $Index, $Index), '', 0, 0)
				Else
					Switch @error
						Case 0 ; OK
							_GUICtrlTreeView_AddChild($hTV, $hItem, $File, $Index, $Index)
						Case 1 ; Access denied
							If StringInStr(FileGetAttrib($Path & '\' & $File), 'H') Then
								$Index = 4
							Else
								$Index = 3
							EndIf
							_GUICtrlTreeView_AddChild($hTV, $hItem, $File, $Index, $Index)
						Case Else
					EndSwitch
				EndIf
			EndIf
		WEnd
		FileClose($hSearch)
	EndIf
	If True Then
		$hSearch = FileFindFirstFile($Path & '\*')
		If $hSearch = -1 Then
		Else
			While 1
				$File = FileFindNextFile($hSearch)
				If @error Then
					ExitLoop
				EndIf
				If Not @extended Then
					$Index = _TVAddIcon($hTV, $Path & '\' & $File)
					Switch StringRegExpReplace($File, '^.*\.', '')
						Case 'pif', 'lnk', 'url'
							$Link[0][0] += 1
							If $Link[0][0] > UBound($Link) - 1 Then
								ReDim $Link[$Link[0][0] + 100][2]
							EndIf
							$Link[$Link[0][0]][0] = _GUICtrlTreeView_AddChild($hTV, $hItem,  StringRegExpReplace($File, '\.[^.]*\Z', ''), $Index, $Index)
							$Link[$Link[0][0]][1] = $Path & '\' & $File
						Case Else
							_GUICtrlTreeView_AddChild($hTV, $hItem, $File, $Index, $Index)
					EndSwitch
				EndIf
			WEnd
			FileClose($hSearch)
		EndIf
	EndIf
	_GUICtrlTreeView_EnsureVisible($hTV, _GUICtrlTreeView_GetLastChild($hTV, $hItem))
	_GUICtrlTreeView_EnsureVisible($hTV, $hItem)
	_WinAPI_LockWindowUpdate(0)
	Return 1
EndFunc   ;==>_TVUpdate
#Region API Functions
Func _WinAPI_AddIconOverlay($hIcon, $hOverlay)
	Local $tSIZE, $Ret, $hIL, $hResult = 0
	$tSIZE = _WinAPI_GetIconDimension($hIcon)
	If @error Then
		Return SetError(1, 0, 0)
	EndIf
	$hIL = DllCall('comctl32.dll', 'ptr', 'ImageList_Create', 'int', DllStructGetData($tSIZE, 1), 'int', DllStructGetData($tSIZE, 1), 'uint', 0x0021, 'int', 2, 'int', 2)
	If (@error) Or (Not $hIL[0]) Then
		Return SetError(2, 0, 0)
	EndIf
	Do
		$Ret = DllCall('comctl32.dll', 'int', 'ImageList_ReplaceIcon', 'ptr', $hIL[0], 'int', -1, 'ptr', $hIcon)
		If (@error) Or ($Ret[0] = -1) Then
			ExitLoop
		EndIf
		$Ret = DllCall('comctl32.dll', 'int', 'ImageList_ReplaceIcon', 'ptr', $hIL[0], 'int', -1, 'ptr', $hOverlay)
		If (@error) Or ($Ret[0] = -1) Then
			ExitLoop
		EndIf
		$Ret = DllCall('comctl32.dll', 'int', 'ImageList_SetOverlayImage', 'ptr', $hIL[0], 'int', 1, 'int', 1)
		If (@error) Or (Not $Ret[0]) Then
			ExitLoop
		EndIf
		$Ret = DllCall('comctl32.dll', 'ptr', 'ImageList_GetIcon', 'ptr', $hIL[0], 'int', 0, 'uint', 0x00000100)
		If (@error) Or (Not $Ret[0]) Then
			ExitLoop
		EndIf
		$hResult = $Ret[0]
	Until 1
	DllCall('comctl32.dll', 'int', 'ImageList_Destroy', 'ptr', $hIL[0])
	If Not $hResult Then
		Return SetError(3, 0, 0)
	EndIf
	Return $hResult
EndFunc   ;==>_WinAPI_AddIconOverlay
Func _WinAPI_AddIconTransparency($hIcon, $iPercent = 50, $fDelete = 0)
	Local $tICONINFO, $tBITMAP, $W, $H, $Ret, $iByte, $tBits, $pBits, $hBitmap[2], $hResult = 0
	$tICONINFO = DllStructCreate($tagICONINFO)
	$Ret = DllCall('user32.dll', 'int', 'GetIconInfo', 'ptr', $hIcon, 'ptr', DllStructGetPtr($tICONINFO))
	If (@error) Or (Not $Ret[0]) Then
		Return SetError(1, 0, 0)
	EndIf
	For $i = 0 To 1
		$hBitmap[$i] = DllStructGetData($tICONINFO, $i + 4)
	Next
	Do
		$tBITMAP = DllStructCreate($tagBITMAP)
		If Not _WinAPI_GetObject($hBitmap[1], DllStructGetSize($tBITMAP), DllStructGetPtr($tBITMAP)) Then
			ExitLoop
		EndIf
		$W = DllStructGetData($tBITMAP, 'bmWidth')
		$H = DllStructGetData($tBITMAP, 'bmHeight')
		$iByte = $W * $H * 4
		$tBits = DllStructCreate('byte[' & $iByte & ']')
		$pBits = DllStructGetPtr($tBits)
		If _WinAPI_GetBitmapBits($hBitmap[1], $iByte, $pBits) <> $iByte Then
			ExitLoop
		EndIf
		For $i = 1 To $iByte Step 4
			DllStructSetData($tBits, 1, DllStructGetData($tBits, 1, $i + 3) * $iPercent / 100, $i + 3)
		Next
		_WinAPI_DeleteObject($hBitmap[1])
		$hBitmap[1] = _WinAPI_CreateBitmap($W, $H, 1, 32, $pBits)
		If $hBitmap[1] Then
			$hResult = _WinAPI_CreateIconIndirect($hBitmap[1], $hBitmap[0])
		EndIf
	Until 1
	For $i = 0 To 1
		If $hBitmap[$i] Then
			_WinAPI_DeleteObject($hBitmap[$i])
		EndIf
	Next
	If Not $hResult Then
		Return SetError(1, 0, 0)
	EndIf
	If $fDelete Then
		_WinAPI_DestroyIcon($hIcon)
	EndIf
	Return $hResult
EndFunc   ;==>_WinAPI_AddIconTransparency
Func _WinAPI_ExtractIcon($sIcon, $iIndex, $fSmall = 0)
	Local $pLarge, $pSmall, $tPtr = DllStructCreate('ptr')
	If $fSmall Then
		$pLarge = 0
		$pSmall = DllStructGetPtr($tPtr)
	Else
		$pLarge = DllStructGetPtr($tPtr)
		$pSmall = 0
	Endif
	Local $Ret = DllCall('shell32.dll', 'uint', 'ExtractIconExW', 'wstr', $sIcon, 'int', $iIndex, 'ptr', $pLarge, 'ptr', $pSmall, 'uint', 1)
	If (@error) Or (Not $Ret[0]) Then
		Return SetError(1, 0, 0)
	EndIf
	Return DllStructGetData($tPtr, 1)
EndFunc   ;==>_WinAPI_ExtractIcon
Func _WinAPI_LockWindowUpdate($hWnd)
	Local $Ret = DllCall('user32.dll', 'int', 'LockWindowUpdate', 'hwnd', $hWnd)
	If (@error) Or (Not $Ret[0]) Then
		Return SetError(1, 0, 0)
	EndIf
	Return 1
EndFunc   ;==>_WinAPI_LockWindowUpdate
Func _WinAPI_PathIsRoot($sPath)
	Local $Ret = DllCall('shlwapi.dll', 'int', 'PathIsRootW', 'wstr', $sPath)
	If @error Then
		Return SetError(1, 0, 0)
	EndIf
	Return $Ret[0]
EndFunc   ;==>_WinAPI_PathIsRoot
#EndRegion API Functions
#Region Windows Message Functions
Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
	Local $tNMTREEVIEW = DllStructCreate($tagNMTREEVIEW, $lParam)
	Local $hItem = DllStructGetData($tNMTREEVIEW, 'NewhItem')
	Local $iState = DllStructGetData($tNMTREEVIEW, 'NewState')
	Local $hTV = DllStructGetData($tNMTREEVIEW, 'hWndFrom')
	Local $ID = DllStructGetData($tNMTREEVIEW, 'Code')
	Local $Index, $Path
	Switch $hTV
		Case $hTreeView
			Switch $ID
				Case $TVN_ITEMEXPANDINGW
					If (Not BitAND($iState, $TVIS_EXPANDED)) And (Not _GUICtrlTreeView_ExpandedOnce($hTV, $hItem)) Then
						_WinAPI_LockWindowUpdate($hTV)
						$Count += 1
					EndIf
				Case $TVN_ITEMEXPANDEDW
					$Path = _TVGetPath($hTV, $hItem, $sRoot)
					If _WinAPI_PathIsDirectory($Path) Then
						If Not BitAND($iState, $TVIS_EXPANDED) Then
							$Index = _TVAddIcon($hTV, $Path)
						Else
							$Index = _TVAddIcon($hTV, $Path, 1)
							If Not _GUICtrlTreeView_ExpandedOnce($hTV, $hItem) Then
								GUICtrlSendToDummy($Dummy, $hItem)
								$Count -=1
							EndIf
						EndIf
						_GUICtrlTreeView_SetSelectedImageIndex($hTV, $hItem, $Index)
						_GUICtrlTreeView_SetImageIndex($hTV, $hItem, $Index)
					Else
						_GUICtrlTreeView_Delete($hTV, $hItem)
						If BitAND($iState, $TVIS_SELECTED) Then
							_TVSetPath($hTV, _GUICtrlTreeView_GetSelection($hTV), $sRoot)
						EndIf
					EndIf
					If $Count Then
						_WinAPI_LockWindowUpdate(0)
						$Count -= 1
					EndIf
				Case $TVN_SELCHANGEDW
					If BitAND($iState, $TVIS_SELECTED) Then
						If Not FileExists(_TVGetPath($hTV, $hItem, $sRoot)) Then
							_GUICtrlTreeView_Delete($hTV, $hItem)
							For $i = 1 To $Link[0][0]
								If $Link[$i][0] = $hItem Then
									For $j = $i To $Link[0][0] - 1
										For $k = 0 To 1
											$Link[$j][$k] =  $Link[$j + 1][$k]
										Next
									Next
									ReDim $Link[$Link[0][0]][2]
									$Link[0][0] -= 1
									ExitLoop
								EndIf
							Next
							$hItem = _GUICtrlTreeView_GetSelection($hTV)
						EndIf
						If $hItem <> $hSelect Then
							_TVSetPath($hTV, $hItem, $sRoot)
						EndIf
					EndIf
			EndSwitch
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY
#EndRegion Windows Message Functions