Что нового

[Файловая система] выделение папок в зависимости от наличия в них под-папок

Автор
A

Alexey

Новичок
Сообщения
171
Репутация
0
скрипт точно взят отсюда?
точно

скрипт не проверяет рекурсивно каталоги, только то что находится на первом уровне подкаталога
хорошо, давай попробуем разобраться. вот ещё один скрин с результатом работы последнего скрипта:
ss-2010.08.12-12.26.12.png
папки folder 1a и folder 18b содержат по одному файлу Текстовый документ.txt

и проблема в том, что данные 2 папки скрипт оставляет выделенными, хотя под-папок в них нет
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
Alexey [?]
данные 2 папки скрипт оставляет выделенными, хотя под-папок в них нет
Очень странно.

Попробуем следющий подход.
Запустите этот скрипт, он сам создаст структуру каталогов во временной папке и откроет её выделив все папки, далее он произведёт попытку сняти выделения, остаться выделенными должны быть только каталоги folder_3 по folder_7, т.к они содержат подкаталоги:

Код:
#include <File.au3>

For $i = 1 To 10
	DirCreate(@TempDir & '\~Test\folder_' & $i)
	
	If $i >= 3 And $i <= 7 Then
		DirCreate(@TempDir & '\~Test\folder_' & $i & '\sub_folder')
	EndIf
Next

FileWrite(@TempDir & '\~Test\folder_2\some_file.txt', '')
FileWrite(@TempDir & '\~Test\folder_8\some_file.txt', '')

Run('explorer ' & @TempDir & '\~Test')
WinWait('~Test')

_ExplorerSelectAll()

MsgBox(262144+64, 'Title', 'Теперь мы снимаем выделение...', 3)

WinActivate('~Test')
_ExplorerClearSelection()

If MsgBox(262144+36, 'Title', 'Должны были остаться выделенными только папки от folder_3 до folder_7' & @CRLF & 'Сработало?') = 6 Then
	ShellExecute('http://autoit-script.ru/index.php/topic,2352.0.html')
Else
	MsgBox(48, 'Title', 'Странно...')
	ShellExecute('http://autoit-script.ru/index.php?action=post;topic=2352.0;num_replies=20')
EndIf

DirRemove(@TempDir & '\~Test', 1)

Func _ExplorerSelectAll()
	$hExplorer = WinGetHandle("[CLASS:ExplorerWClass]")
    If @error Then $hExplorer = WinGetHandle("[CLASS:CabinetWClass]")
	
	ControlListView($hExplorer, "", "SysListView321", "SelectAll")
EndFunc

Func _ExplorerClearSelection()
    $hExplorer = WinGetHandle("[CLASS:ExplorerWClass]")
    If @error Then $hExplorer = WinGetHandle("[CLASS:CabinetWClass]")
    
    $aSelected_Files = _ExplorerGetSelectedItems($hExplorer)
    
    If @error Then
        MsgBox(48, "Error", "It seems that there is no selected files, but also it can be an internal function error.")
        Return
    EndIf
    
    For $i = 1 To $aSelected_Files[0][0]
        If $aSelected_Files[$i][1] = 1 Then
            $aFiles = _FileListToArray($aSelected_Files[$i][2], "*", 2)
        EndIf
        
        If $aSelected_Files[$i][1] = 0 Or UBound($aFiles) <= 1 Then
            ControlListView($hExplorer, "", "SysListView321", "DeSelect", $aSelected_Files[$i][0])
        EndIf
    Next
EndFunc

;[0][0] = Total items count
;[N][0] = Selected element Index
;[N][1] = Selected element is Directory
;[N][2] = Selected element string (full path to the file/dir)
Func _ExplorerGetSelectedItems($hWnd="[CLASS:CabinetWClass]")
    Local $aRetInfo[1][1]
    Local $aIndexes, $iIndex, $iCount, $sSelected, $sSelected_Path
    Local $hSearch, $sCurrentFile
    
    If Not IsHWnd($hWnd) Then
        $hWnd = WinGetHandle($hWnd)
    EndIf
    
    $sSelected_Path = _GetWindowsExplorerPath($hWnd)
    $sSelected_Path = StringRegExpReplace($sSelected_Path, "\\+$", "")
    $aIndexes = StringSplit(ControlListView($hWnd, "", "SysListView321", "GetSelected", 1), "|")
    
    If $aIndexes[1] = "" Then
        Return SetError(1, 0, 0)
    EndIf
    
    Dim $aRetInfo[$aIndexes[0]+1][3]
    
    For $i = 1 To $aIndexes[0]
        $sSelected = ControlListView($hWnd, "", "SysListView321", "GetText", $aIndexes[$i])
        $sCurrentFile = $sSelected_Path & "\" & $sSelected
        
        If Not FileExists($sCurrentFile) Then ;Search the extension for file...
            $hSearch = FileFindFirstFile($sCurrentFile & ".*")
            
            If $hSearch <> -1 Then
                $sCurrentFile = $sSelected_Path & "\" & FileFindNextFile($hSearch)
                FileClose($hSearch)
            EndIf
        EndIf
        
        $aRetInfo[0][0] += 1
        $aRetInfo[$aRetInfo[0][0]][0] = $aIndexes[$i] ;Index
        $aRetInfo[$aRetInfo[0][0]][1] = Number(StringInStr(FileGetAttrib($sCurrentFile), "D") > 0) ;Is Directory
        $aRetInfo[$aRetInfo[0][0]][2] = $sCurrentFile ;Selected file / dir
    Next
    
    If $aRetInfo[0][0] = 0 Then
        Return SetError(2, 0, 0)
    EndIf
    
    ReDim $aRetInfo[$aRetInfo[0][0]+1][3]
    Return $aRetInfo
EndFunc

; ==================================================================================================
; Func _GetWindowsExplorerPath($hWnd)
;
; Function to get the path currently being explored by a Windows Explorer window
;
; $hWnd = Handle to the Windows Explorer window
;
; Returns:
;   Success: String - Path being explored by this window
;   Failure: "" empty string, with @error set:
;      @error = 1 = This is not a valid explorer window
;      @error = 2 = DLL call error, use _WinAPI_GetLastError()
;
; Author: WideBoyDixon
; ==================================================================================================
Func _GetWindowsExplorerPath($hWnd)
    Local $pv, $pidl, $return = "", $ret, $hMem, $pid, $folderPath = DllStructCreate("char[260]"), $className
    Local $bPIDL = False
    Local Const $CWM_GETPATH = 0x400 + 12;

    ; Check the classname of the window first
    $className = DllCall("user32.dll", "int", "GetClassName", "hwnd", $hWnd, "str", "", "int", 4096)
    If @error Then Return SetError(2, 0, "")
    If ($className[2] <> "ExploreWClass" And $className[2] <> "CabinetWClass") Then Return SetError(1, 0, "")
    
    ; Retrieve the process ID for our process
    $pid = DllCall("kernel32.dll", "int", "GetCurrentProcessId")
    If @error Then Return SetError(2, 0, "")

    ; Send the CWM_GETPATH message to the window
    $hMem = DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hWnd, "int", $CWM_GETPATH, "wparam", $pid[0], "lparam", 0) 
    If @error Then Return SetError(2, 0, "")
    If $hMem[0] = 0 Then Return SetError(1, 0, "")
    
    ; Lock the shared memory
    $pv = DllCall("shell32.dll", "ptr", "SHLockShared", "uint", $hMem[0], "uint", $pid[0])
    If @error Then Return SetError(2, 0, "")
    If $pv[0] Then
        $pidl = DllCall("shell32.dll", "ptr", "ILClone", "uint", $pv[0]) ; Clone the PIDL
        If @error Then Return SetError(2, 0, "")
        $bPIDL = True
        DllCall("shell32.dll", "int", "SHUnlockShared", "uint", $pv) ; Unlock the shared memory
    EndIf
    DllCall("shell32.dll", "int", "SHFreeShared", "uint", $hMem, "uint", $pid) ; Free the shared memory
    
    If $bPIDL Then
        ; Retrieve the path from the PIDL
        $ret = DllCall("shell32.dll", "int", "SHGetPathFromIDList", "ptr", $pidl[0], "ptr", DllStructGetPtr($folderPath))
        If (@error = 0) And ($ret[0] <> 0) Then $return = DllStructGetData($folderPath, 1) ; Retrieve the value
        DllCall("shell32.dll", "none", "ILFree", "ptr", $pidl[0]) ; Free up the PIDL that we cloned
        Return SetError(0, 0, $return) ; Success
    EndIf
    
    Return SetError(2, 0, "") ; Failed a WinAPI call
EndFunc



Добавлено:
Сообщение автоматически объединено:

Нашёл проблему!
Я не обратил внимание на «Версия AutoIt: 3.3.0.0». Там была бага с функцией _FileListToArray, скрипт поправил (пока только тестовый, последний).
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,323
CreatoR [?]
он сам создаст структуру каталогов во временной папке и откроет её выделив все папки, далее он произведёт попытку сняти выделения, остаться выделенными должны быть только каталоги folder_3 по folder_7
У меня все так и произошло .
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,323
CreatoR,
Понял. Когда отправлял свое сообщение, добавление не видел. :IL_AutoIt_1:
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
Alexey [?]
так и получилось
Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <StaticConstants.au3>
#include <File.au3>

$hGUI = GUICreate("Drop GUI", 200, 200, -1, -1, -1, BitOR($WS_EX_ACCEPTFILES, $WS_EX_TOPMOST))
GUICtrlCreateLabel("Drop Files Here", 0, 0, 200, 200, BitOR($SS_CENTER, $SS_CENTERIMAGE))
GUICtrlSetState(-1, $GUI_DROPACCEPTED)
GUISetState(@SW_SHOWNOACTIVATE, $hGUI)

While 1
	$nMsg = GUIGetMsg()

	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
		Case $GUI_EVENT_DROPPED
			_ExplorerClearFoldersSelection(1)
	EndSwitch
WEnd

Func _ExplorerClearFoldersSelection($iEmptyFoldersMode = 1)
	$hExplorer = WinGetHandle("[CLASS:ExplorerWClass]")
	If @error Then $hExplorer = WinGetHandle("[CLASS:CabinetWClass]")
	
    $aSelected_Files = _ExplorerGetSelectedItems($hExplorer)
    
    If @error Then
        MsgBox(48, "Error", "It seems that there is no selected files, but also it can be an internal function error.")
        Return
    EndIf
    
    For $i = 1 To $aSelected_Files[0][0]
		Switch $iEmptyFoldersMode
			Case 1 ;Clear only if the folder does not include subfolders
				If $aSelected_Files[$i][1] = 1 Then
					$aFiles = _FileListToArray($aSelected_Files[$i][2], "*", 2)
				EndIf
				
				If $aSelected_Files[$i][1] = 0 Or UBound($aFiles) <= 1 Then
					ControlListView($hExplorer, "", "SysListView321", "DeSelect", $aSelected_Files[$i][0])
				EndIf
			Case 2 ;Clear only if the folder is completely empty.
				If $aSelected_Files[$i][1] = 0 Or _WinAPI_PathIsDirectoryEmpty($aSelected_Files[$i][2]) Then
					ControlListView($hExplorer, "", "SysListView321", "DeSelect", $aSelected_Files[$i][0])
				EndIf
		EndSwitch
    Next
EndFunc

Func _ExplorerSelectAll()
	$hExplorer = WinGetHandle("[CLASS:ExplorerWClass]")
    If @error Then $hExplorer = WinGetHandle("[CLASS:CabinetWClass]")
	
	ControlListView($hExplorer, "", "SysListView321", "SelectAll")
EndFunc

;[0][0] = Total items count
;[N][0] = Selected element Index
;[N][1] = Selected element is Directory
;[N][2] = Selected element string (full path to the file/dir)
Func _ExplorerGetSelectedItems($hWnd="[CLASS:CabinetWClass]")
    Local $aRetInfo[1][1]
    Local $aIndexes, $iIndex, $iCount, $sSelected, $sSelected_Path
    Local $hSearch, $sCurrentFile
    
	If Not IsHWnd($hWnd) Then
		$hWnd = WinGetHandle($hWnd)
	EndIf
	
    $sSelected_Path = _GetWindowsExplorerPath($hWnd)
    $sSelected_Path = StringRegExpReplace($sSelected_Path, "\\+$", "")
    $aIndexes = StringSplit(ControlListView($hWnd, "", "SysListView321", "GetSelected", 1), "|")
    
    If $aIndexes[1] = "" Then
        Return SetError(1, 0, 0)
    EndIf
    
    Dim $aRetInfo[$aIndexes[0]+1][3]
    
    For $i = 1 To $aIndexes[0]
        $sSelected = ControlListView($hWnd, "", "SysListView321", "GetText", $aIndexes[$i])
        $sCurrentFile = $sSelected_Path & "\" & $sSelected
        
        If Not FileExists($sCurrentFile) Then ;Search the extension for file...
            $hSearch = FileFindFirstFile($sCurrentFile & ".*")
            
            If $hSearch <> -1 Then
                $sCurrentFile = $sSelected_Path & "\" & FileFindNextFile($hSearch)
                FileClose($hSearch)
            EndIf
        EndIf
        
        $aRetInfo[0][0] += 1
        $aRetInfo[$aRetInfo[0][0]][0] = $aIndexes[$i] ;Index
        $aRetInfo[$aRetInfo[0][0]][1] = Number(StringInStr(FileGetAttrib($sCurrentFile), "D") > 0) ;Is Directory
        $aRetInfo[$aRetInfo[0][0]][2] = $sCurrentFile ;Selected file / dir
    Next
    
    If $aRetInfo[0][0] = 0 Then
        Return SetError(2, 0, 0)
    EndIf
    
    ReDim $aRetInfo[$aRetInfo[0][0]+1][3]
    Return $aRetInfo
EndFunc

; ==================================================================================================
; Func _GetWindowsExplorerPath($hWnd)
;
; Function to get the path currently being explored by a Windows Explorer window
;
; $hWnd = Handle to the Windows Explorer window
;
; Returns:
;   Success: String - Path being explored by this window
;   Failure: "" empty string, with @error set:
;      @error = 1 = This is not a valid explorer window
;      @error = 2 = DLL call error, use _WinAPI_GetLastError()
;
; Author: WideBoyDixon
; ==================================================================================================
Func _GetWindowsExplorerPath($hWnd)
    Local $pv, $pidl, $return = "", $ret, $hMem, $pid, $folderPath = DllStructCreate("char[260]"), $className
    Local $bPIDL = False
    Local Const $CWM_GETPATH = 0x400 + 12;

    ; Check the classname of the window first
    $className = DllCall("user32.dll", "int", "GetClassName", "hwnd", $hWnd, "str", "", "int", 4096)
    If @error Then Return SetError(2, 0, "")
    If ($className[2] <> "ExploreWClass" And $className[2] <> "CabinetWClass") Then Return SetError(1, 0, "")
    
    ; Retrieve the process ID for our process
    $pid = DllCall("kernel32.dll", "int", "GetCurrentProcessId")
    If @error Then Return SetError(2, 0, "")

    ; Send the CWM_GETPATH message to the window
    $hMem = DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hWnd, "int", $CWM_GETPATH, "wparam", $pid[0], "lparam", 0) 
    If @error Then Return SetError(2, 0, "")
    If $hMem[0] = 0 Then Return SetError(1, 0, "")
    
    ; Lock the shared memory
    $pv = DllCall("shell32.dll", "ptr", "SHLockShared", "uint", $hMem[0], "uint", $pid[0])
    If @error Then Return SetError(2, 0, "")
    If $pv[0] Then
        $pidl = DllCall("shell32.dll", "ptr", "ILClone", "uint", $pv[0]) ; Clone the PIDL
        If @error Then Return SetError(2, 0, "")
        $bPIDL = True
        DllCall("shell32.dll", "int", "SHUnlockShared", "uint", $pv) ; Unlock the shared memory
    EndIf
    DllCall("shell32.dll", "int", "SHFreeShared", "uint", $hMem, "uint", $pid) ; Free the shared memory
    
    If $bPIDL Then
        ; Retrieve the path from the PIDL
        $ret = DllCall("shell32.dll", "int", "SHGetPathFromIDList", "ptr", $pidl[0], "ptr", DllStructGetPtr($folderPath))
        If (@error = 0) And ($ret[0] <> 0) Then $return = DllStructGetData($folderPath, 1) ; Retrieve the value
        DllCall("shell32.dll", "none", "ILFree", "ptr", $pidl[0]) ; Free up the PIDL that we cloned
        Return SetError(0, 0, $return) ; Success
    EndIf
    
    Return SetError(2, 0, "") ; Failed a WinAPI call
EndFunc

; #FUNCTION# ====================================================================================================================
; Name...........: _WinAPI_PathIsDirectoryEmpty
; Description....: Determines whether a specified path is an empty directory.
; Syntax.........: _WinAPI_PathIsDirectoryEmpty ( $sPath )
; Parameters.....: $sPath  - The path to be tested.
; Return values..: Success - 1 - The path is an empty directory.
;                            0 - Otherwise.
;                  Failure - 0 and sets the @error flag to non-zero.
; Author.........: Yashied
; Modified.......:
; Remarks........: None
; Related........:
; Link...........: @@MsdnLink@@ PathIsDirectoryEmpty
; Example........: Yes
; ===============================================================================================================================
Func _WinAPI_PathIsDirectoryEmpty($sPath)
	Local $Ret = DllCall('shlwapi.dll', 'int', 'PathIsDirectoryEmptyW', 'wstr', $sPath)
	If @error Then
		Return SetError(1, 0, 0)
	EndIf
	Return $Ret[0]
EndFunc
 
Автор
A

Alexey

Новичок
Сообщения
171
Репутация
0
CreatoR, благодарю за помощь :smile:
в принципе, работает как надо. разве что пара не особо понятных моментов несколько портит впечатление:

1) скрипт не каждый раз реагирует на закидывание папок. где-то в двух случаях из трёх всё выделяется правильно, где-то в трети случаях - ничего не происходит (то есть, выделение всех папок остаётся); внятной закономерности не уловил

2) скрипт почти каждый раз грузится до пяти секунд (сначала мгновенно появляется ненужная мне иконка в трэе и лишь спустя время - само окно). впрочем, в редких случаях наблюдается нормальный, молниеносный запуск. и дело явно не только в этом конкретном скрипте - раньше я подобное изредка ужé наблюдал

ещё пара совсем пустяковых вопросов:
- в строке GUISetState я убрал символы NOACTIVATE. мне так удобнее, но не затронет ли это что-либо в скрипте, ничего из-за этого менять не требуется?
- нужна ли самая последняя пустая строка? более чем уверен, что нет, но почему бы не уточнить? ;)
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
Alexey [?]
скрипт не каждый раз реагирует на закидывание папок
У меня н получилось это воспроизвести. И я вам всё же советую не использовать перетаскивание, пусть скрипт при запуске сразу снимает выделение.

скрипт почти каждый раз грузится до пяти секунд
У вас видимо что-то с системой, и ещё, не помешало бы обновить версию AutoIt до 3.3.6.1.

сначала мгновенно появляется ненужная мне иконка
На будущее - о таких деталях нужно писать в первом сообщений ;) иконка убирается добавлением #NoTrayIcon в начало скрипта.

в строке GUISetState я убрал символы NOACTIVATE. мне так удобнее, но не затронет ли это что-либо в скрипте, ничего из-за этого менять не требуется?
Нет, это я при тестирований забыл это убрать, @SW_SHOW это обычное отображение окна.

нужна ли самая последняя пустая строка?
Нет конечно, а что, так сильно мешает? :smile:
 
Автор
A

Alexey

Новичок
Сообщения
171
Репутация
0
У вас видимо что-то с системой
не буду утверждать, что дело не в системе, но вот что заметил - из разных четырёх имеющихся у меня скриптов 2 запускаются мгновенно, другие 2 - с задержкой. на всякий случай вот они:

1-й (без задержки). скрипт - в этой теме:
http://autoit-script.ru/index.php/topic,2099.0.html

2-й (без задержки). скрипт - в ответе № 5 данной темы

3-й (с задержкой). скрипт - в этой теме:
http://autoit-script.ru/index.php/topic,194.0.html

4-й (в основном с задержкой) - в ответе № 26 данной темы
не помешало бы обновить версию AutoIt до 3.3.6.1
обновляться рано или поздно придётся. но ведь всё то немногое, чем я располагаю, написано для 3.3.0.0. неужели с этими старыми au3-файлами не будет никаких проблем на новой версии ?
У меня н получилось это воспроизвести. И я вам всё же советую не использовать перетаскивание, пусть скрипт при запуске сразу снимает выделение
уговорил :smile: готов попробовать вариант без перетаскивания
(как это будет выглядеть, скрипт будет самовыгружаться после проделанной работы ?)
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
Alexey [?]
на всякий случай вот они
У всех скриптов которые с задержкой, имеется GUI с возможностью перетаскивания файлов, возможно проблема именно в этом ;)

неужели с этими старыми au3-файлами не будет никаких проблем на новой версии ?
Вполне могут быть проблемы, какие именно читаем тут.

готов попробовать вариант без перетаскивания
Ну собственно всё что требуется это убрать часть с GUI и цикл, и сразу вызывать функцию:

Код:
#include <File.au3>

_ExplorerClearFoldersSelection(1)


;Тут следует поместить все функций, т.е содержимое скрипта начиная со строки ниже и до конца:
Func _ExplorerClearFoldersSelection($iEmptyFoldersMode = 1)


скрипт будет самовыгружаться после проделанной работы ?
Да.
 
Автор
A

Alexey

Новичок
Сообщения
171
Репутация
0
всё-таки значительная нестабильность варианта с GUI подталкивает ещё раз попытаться сделать вариант без перетаскивания (пару недель назад я пробовал его осуществить, но не получилось, поэтому временно отложил)

Ну собственно всё что требуется это убрать часть с GUI и цикл, и сразу вызывать функцию
Код:
#include <File.au3>

_ExplorerClearFoldersSelection(1)

Func _ExplorerClearFoldersSelection($iEmptyFoldersMode = 1)
    $hExplorer = WinGetHandle("[CLASS:ExplorerWClass]")
    If @error Then $hExplorer = WinGetHandle("[CLASS:CabinetWClass]")
   
    $aSelected_Files = _ExplorerGetSelectedItems($hExplorer)
   
    If @error Then
        MsgBox(48, "Error", "It seems that there is no selected files, but also it can be an internal function error.")
        Return
    EndIf
   
    For $i = 1 To $aSelected_Files[0][0]
        Switch $iEmptyFoldersMode
            Case 1 ;Clear only if the folder does not include subfolders
                If $aSelected_Files[$i][1] = 1 Then
                    $aFiles = _FileListToArray($aSelected_Files[$i][2], "*", 2)
                EndIf
               
                If $aSelected_Files[$i][1] = 0 Or UBound($aFiles) <= 1 Then
                    ControlListView($hExplorer, "", "SysListView321", "DeSelect", $aSelected_Files[$i][0])
                EndIf
            Case 2 ;Clear only if the folder is completely empty.
                If $aSelected_Files[$i][1] = 0 Or _WinAPI_PathIsDirectoryEmpty($aSelected_Files[$i][2]) Then
                    ControlListView($hExplorer, "", "SysListView321", "DeSelect", $aSelected_Files[$i][0])
                EndIf
        EndSwitch
    Next
EndFunc

Func _ExplorerSelectAll()
    $hExplorer = WinGetHandle("[CLASS:ExplorerWClass]")
    If @error Then $hExplorer = WinGetHandle("[CLASS:CabinetWClass]")
   
    ControlListView($hExplorer, "", "SysListView321", "SelectAll")
EndFunc

;[0][0] = Total items count
;[N][0] = Selected element Index
;[N][1] = Selected element is Directory
;[N][2] = Selected element string (full path to the file/dir)
Func _ExplorerGetSelectedItems($hWnd="[CLASS:CabinetWClass]")
    Local $aRetInfo[1][1]
    Local $aIndexes, $iIndex, $iCount, $sSelected, $sSelected_Path
    Local $hSearch, $sCurrentFile
   
    If Not IsHWnd($hWnd) Then
        $hWnd = WinGetHandle($hWnd)
    EndIf
   
    $sSelected_Path = _GetWindowsExplorerPath($hWnd)
    $sSelected_Path = StringRegExpReplace($sSelected_Path, "\\+$", "")
    $aIndexes = StringSplit(ControlListView($hWnd, "", "SysListView321", "GetSelected", 1), "|")
   
    If $aIndexes[1] = "" Then
        Return SetError(1, 0, 0)
    EndIf
   
    Dim $aRetInfo[$aIndexes[0]+1][3]
   
    For $i = 1 To $aIndexes[0]
        $sSelected = ControlListView($hWnd, "", "SysListView321", "GetText", $aIndexes[$i])
        $sCurrentFile = $sSelected_Path & "\" & $sSelected
       
        If Not FileExists($sCurrentFile) Then ;Search the extension for file...
            $hSearch = FileFindFirstFile($sCurrentFile & ".*")
           
            If $hSearch <> -1 Then
                $sCurrentFile = $sSelected_Path & "\" & FileFindNextFile($hSearch)
                FileClose($hSearch)
            EndIf
        EndIf
       
        $aRetInfo[0][0] += 1
        $aRetInfo[$aRetInfo[0][0]][0] = $aIndexes[$i] ;Index
        $aRetInfo[$aRetInfo[0][0]][1] = Number(StringInStr(FileGetAttrib($sCurrentFile), "D") > 0) ;Is Directory
        $aRetInfo[$aRetInfo[0][0]][2] = $sCurrentFile ;Selected file / dir
    Next
   
    If $aRetInfo[0][0] = 0 Then
        Return SetError(2, 0, 0)
    EndIf
   
    ReDim $aRetInfo[$aRetInfo[0][0]+1][3]
    Return $aRetInfo
EndFunc

; ==================================================================================================
; Func _GetWindowsExplorerPath($hWnd)
;
; Function to get the path currently being explored by a Windows Explorer window
;
; $hWnd = Handle to the Windows Explorer window
;
; Returns:
;   Success: String - Path being explored by this window
;   Failure: "" empty string, with @error set:
;      @error = 1 = This is not a valid explorer window
;      @error = 2 = DLL call error, use _WinAPI_GetLastError()
;
; Author: WideBoyDixon
; ==================================================================================================
Func _GetWindowsExplorerPath($hWnd)
    Local $pv, $pidl, $return = "", $ret, $hMem, $pid, $folderPath = DllStructCreate("char[260]"), $className
    Local $bPIDL = False
    Local Const $CWM_GETPATH = 0x400 + 12;

    ; Check the classname of the window first
    $className = DllCall("user32.dll", "int", "GetClassName", "hwnd", $hWnd, "str", "", "int", 4096)
    If @error Then Return SetError(2, 0, "")
    If ($className[2] <> "ExploreWClass" And $className[2] <> "CabinetWClass") Then Return SetError(1, 0, "")
   
    ; Retrieve the process ID for our process
    $pid = DllCall("kernel32.dll", "int", "GetCurrentProcessId")
    If @error Then Return SetError(2, 0, "")

    ; Send the CWM_GETPATH message to the window
    $hMem = DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hWnd, "int", $CWM_GETPATH, "wparam", $pid[0], "lparam", 0)
    If @error Then Return SetError(2, 0, "")
    If $hMem[0] = 0 Then Return SetError(1, 0, "")
   
    ; Lock the shared memory
    $pv = DllCall("shell32.dll", "ptr", "SHLockShared", "uint", $hMem[0], "uint", $pid[0])
    If @error Then Return SetError(2, 0, "")
    If $pv[0] Then
        $pidl = DllCall("shell32.dll", "ptr", "ILClone", "uint", $pv[0]) ; Clone the PIDL
        If @error Then Return SetError(2, 0, "")
        $bPIDL = True
        DllCall("shell32.dll", "int", "SHUnlockShared", "uint", $pv) ; Unlock the shared memory
    EndIf
    DllCall("shell32.dll", "int", "SHFreeShared", "uint", $hMem, "uint", $pid) ; Free the shared memory
   
    If $bPIDL Then
        ; Retrieve the path from the PIDL
        $ret = DllCall("shell32.dll", "int", "SHGetPathFromIDList", "ptr", $pidl[0], "ptr", DllStructGetPtr($folderPath))
        If (@error = 0) And ($ret[0] <> 0) Then $return = DllStructGetData($folderPath, 1) ; Retrieve the value
        DllCall("shell32.dll", "none", "ILFree", "ptr", $pidl[0]) ; Free up the PIDL that we cloned
        Return SetError(0, 0, $return) ; Success
    EndIf
   
    Return SetError(2, 0, "") ; Failed a WinAPI call
EndFunc

; #FUNCTION# ====================================================================================================================
; Name...........: _WinAPI_PathIsDirectoryEmpty
; Description....: Determines whether a specified path is an empty directory.
; Syntax.........: _WinAPI_PathIsDirectoryEmpty ( $sPath )
; Parameters.....: $sPath  - The path to be tested.
; Return values..: Success - 1 - The path is an empty directory.
;                            0 - Otherwise.
;                  Failure - 0 and sets the @error flag to non-zero.
; Author.........: Yashied
; Modified.......:
; Remarks........: None
; Related........:
; Link...........: @@MsdnLink@@ PathIsDirectoryEmpty
; Example........: Yes
; ===============================================================================================================================
Func _WinAPI_PathIsDirectoryEmpty($sPath)
    Local $Ret = DllCall('shlwapi.dll', 'int', 'PathIsDirectoryEmptyW', 'wstr', $sPath)
    If @error Then
        Return SetError(1, 0, 0)
    EndIf
    Return $Ret[0]
EndFunc


запускаю tools - go при выделенных папках в проводнике, и ничего не происходит. начáло именно такое должно быть ?
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
Alexey [?]
запускаю tools - go при выделенных папках в проводнике, и ничего не происходит
А если просто запустить скрипт, из SciTE к примеру?
 
Автор
A

Alexey

Новичок
Сообщения
171
Репутация
0
А если просто запустить скрипт, из SciTE к примеру?
именно так и делал, запускал SciTE Script Editor, открывал последний отредактированный вариант скрипта, в меню выбирал Tools - Go. и ничего не происходило (лишь на пол-секунды мелькал значок Auto It в области уведомлений)

но только что решил попробовать Tools - Compile, повесил на этот созданный exe-файл свой hot-key - и всё заработало
я так и не понял, почему из двух, казалось бы, одинаковых вариантов первый не работает вообще, второй же - идеально. впрочем, главное, что получилось. CreatoR, ещё раз спасибо :smile: так действительно удобнее, гораздо надёжнее, да и выглядит теперь это прямо как встроенная функция проводника

- если папок совсем немного, то exe-файл, выполняя работу, даже не успевает появиться в диспетчере задач; при этом загрузка ЦП на пару секунд возрастает с 2 % до почти 20
- если папок 100-200, загрузка ЦП на пару секунд возрастает с 2 % до 42
по всей видимости, всё это нормально - выложил на всякий случай
 
Верх