Что нового

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

Alexey

Новичок
Сообщения
171
Репутация
0
Версия AutoIt: 3.3.0.0

Описание:
1) допустим, в проводнике в какой-то папке выделено 500 под-папок. я эти 500 перетаскиваю в окно скрипта
2) скрипт снимает выделение с тех из них, которые не имеют вложенных папок

Примечания: то есть, остаться выделенными должны только папки с под-папками
 
Автор
A

Alexey

Новичок
Сообщения
171
Репутация
0
тема всё ещё актуальна :(

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

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Такой вариант устроит ?
Код:
#region *** INCLUDES ***
#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
#include <File.au3>
#include <GuiTreeView.au3>
#include <TreeViewConstants.au3>
#include <GuiListView.au3>
#EndRegion

$hGUI=GUICreate("Test",830,800)
GUISetBkColor(0xD3DAED)
$hTreeView    = GUICtrlCreateTreeView (10, 35, 400, 640 , -1 , $WS_EX_CLIENTEDGE+$TVS_SINGLEEXPAND)
_GUICtrlTreeView_SetBkColor         ($hTreeView , 0xDBDBDB )
GUICtrlSetFont                      ($hTreeView , 8.25 , 204 , 0 , "MS Shell Dlg")
_GUICtrlTreeView_SetTextColor       ($hTreeView , 0x541414 )
$hListView = GUICtrlCreateListView( "", 420, 35, 400, 640,$LVS_SHOWSELALWAYS)
 _GUICtrlListView_AddColumn($hListView, "Folders", 300)    

$btExit = GUICtrlCreateButton("Exit", 720, 740, 100, 30)

GUIRegisterMsg( $WM_NOTIFY , "WM_NOTIFY" )

GUISetState   ()

DrivesTreeView($hTreeView,"ALL");

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE,$btExit
			Exit
	EndSwitch	
WEnd

;============================================
Func DrivesTreeView($hTV, $sType= "FIXED")
	$aDisk=DriveGetDrive($sType)
	_GUICtrlTreeView_BeginUpdate($hTV)
	_GUICtrlTreeView_DeleteAll($hTV)
	For $i=1 To UBound($aDisk)-1
		$aDisk[$i]=StringUpper ( $aDisk[$i] )
		$hItem= GUICtrlCreateTreeViewItem($aDisk[$i], $hTV)
		_GUICtrlTreeView_SetIcon($hTV,$hItem, "shell32.dll",7)
	Next
	_GUICtrlTreeView_EndUpdate($hTV)	
EndFunc
;==============================================
Func TreeViewUpdate($hTV,$hLV,$hItem=-1)
	If $hItem=0 Then Return 0
	$sFullName=StringReplace(_GUICtrlTreeView_GetTree($hTreeView, $hItem) ,'|','\')
	If _GUICtrlTreeView_GetChildren($hTV, $hItem) = False Then
	If Not StringInStr(FileGetAttrib (  $sFullName ),"D")Then Return $sFullName
	$aFolderList = _FileListToArray($sFullName, '*', 2)
	_GUICtrlListView_DeleteAllItems(GUICtrlGetHandle($hListView))
	For $i = 1 To UBound($aFolderList) - 1
		$hChild= _GUICtrlTreeView_AddChild($hTV,$hItem,  $aFolderList[$i])
		_GUICtrlTreeView_SetIcon($hTV, $hChild, "shell32.dll",3)
		_GUICtrlListView_AddItem($hLV, $aFolderList[$i])
		$aFolderList1 = _FileListToArray($sFullName & "\" &  $aFolderList[$i], '*', 2)
		If IsArray($aFolderList1) Then _GUICtrlListView_SetItemSelected($hLV,$i-1)
	Next
	_GUICtrlTreeView_Expand($hTV, $hItem)
	EndIf
	Return $sFullName
EndFunc
;==============================================
Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
;==================================================================    
	#forceref $hWnd, $iMsg, $iwParam
	Global $hClickedItemTV
	Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR;, $hWndTreeView,$hWndListView
	$hWndTreeView = $hTreeView
	If Not IsHWnd($hTreeView) Then $hWndTreeView = GUICtrlGetHandle($hTreeView)
	$tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
	$hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
	$iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
	$iCode = DllStructGetData($tNMHDR, "Code")
   
	Switch $hWndFrom
		Case $hWndTreeview
			Switch $iCode
				Case $NM_CLICK ; The user has clicked the left mouse button within the control
					Local $tPOINT = DllStructCreate("int X;int Y")
					DllStructSetData($tPOINT, "X", MouseGetPos(0))
					DllStructSetData($tPOINT, "Y", MouseGetPos(1))
					DllCall("user32.dll", "int", "ScreenToClient", _
						"hwnd", $hWndTreeview, _
						"ptr", DllStructGetPtr($tPOINT)) 
					Local $iX = DllStructGetData($tPOINT, "X")
					Local $iY = DllStructGetData($tPOINT, "Y")
					$hClickedItemTV = _GUICtrlTreeView_HitTestItem($hWndTreeview, $iX, $iY)
					$sFolderPatch=TreeViewUpdate($hWndTreeview,$hListView, $hClickedItemTV)		
			EndSwitch
		EndSwitch 
	Return $GUI_RUNDEFMSG
EndFunc ; ===> WM_NOTIFY
 
Автор
A

Alexey

Новичок
Сообщения
171
Репутация
0
gregaz,
я признателен тебе за участие в теме, но такой вариант совсем не подходит (поскольку после снятия выделения скриптом мне нужно вручную совершать действия в проводнике над теми папками, которые сохранили выделение)
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Alexey, здесь проблема в получении полного пути к директории, с которой связана выбранная папка. Какой вид обычно у твоих папок? Лучше выложи скриншот, а там посмотрим.
 
Автор
A

Alexey

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

кстати, возможно, в качестве ориентира для решения данной темы поможет отлично работающий скрипт (от `p r o x y), написанный по моей просьбе и выложенный на ру-борд год назад
вкратце его суть - в проводнике выделены папки, я их закидываю в окно скрипта, который переименовывает только подходящие под определённые условия папки
насколько понимаю, постановки задач весьма схожи, поэтому и выкладываю тот скрипт:

Код:
Opt('GUIOnEventMode',       1)
Opt('MustDeclareVars',      1)
Opt('TrayIconDebug',        1)
 
#include <GuiConstantsEx.au3>
#include <GuiImageList.au3>
#Include <GuiListView.au3>
#Include <WinAPI.au3>
#include <WindowsConstants.au3>
 
HotKeySet('!{ESC}', '_Pro_Exit'); Alt+ESC - закрыть скрипт
 
Global  Const $WM_DROPFILES = 0x0233
Global  Const $sKey = 'HKEY_CURRENT_USER\Software\Drag Helper'
 
Global  $hMainWin, $hFullPath, $hSavePos, $hSaveSize, $hList
Local   $hImage
 
Global  $fFullPath  = RegRead($sKey, 'Full path')
Global  $fSavePos   = RegRead($sKey, 'Save pos')
Global  $fSaveSize  = RegRead($sKey, 'Save size')
 
Local   $iWidth     = RegRead($sKey, 'Width')
Local   $iHeight    = RegRead($sKey, 'Height')
Local   $iX         = RegRead($sKey, 'X')
Local   $iY         = RegRead($sKey, 'Y')
 
If $fFullPath == '' Then
    $fFullPath = 0
    RegWrite($sKey, 'Full path', 'REG_DWORD', $fFullPath)
EndIf
If $fSavePos == '' Then
    $fSavePos = 1
    RegWrite($sKey, 'Save pos',  'REG_DWORD', $fSavePos)
EndIf
If $fSaveSize == '' Then
    $fSaveSize = 1
    RegWrite($sKey, 'Save size', 'REG_DWORD', $fSaveSize)
EndIf
 
If $iWidth == '' OR $iWidth < 265 Then
    $iWidth = 265
    RegWrite($sKey, 'Width',  'REG_DWORD', $iWidth)
EndIf
If $iHeight == '' OR $iHeight < 220 Then
    $iHeight = 220
    RegWrite($sKey, 'Height', 'REG_DWORD', $iHeight)
EndIf
If $iX == '' Then
    $iX = 100
    RegWrite($sKey, 'X', 'REG_DWORD', $iX)
EndIf
If $iY == '' Then
    $iY = 100
    RegWrite($sKey, 'Y', 'REG_DWORD', $iY)
EndIf
 
$hMainWin = GUICreate('Drag Helper', $iWidth, $iHeight, $iX, $iY, $WS_OVERLAPPEDWINDOW, BitOR($WS_EX_ACCEPTFILES, $WS_EX_TOPMOST))
    GUISetOnEvent($GUI_EVENT_CLOSE, '_Pro_Exit')
 
GUICtrlCreateButton('Clear', 206, 10, 50, 20)
    GUICtrlSetResizing(-1, $GUI_DOCKALL)
        GUICtrlSetOnEvent(-1, '_Clear')
 
$hFullPath = GUICtrlCreateCheckbox('Показывать полный адрес папок', 10, 10, 195, 20)
    GUICtrlSetResizing(-1, $GUI_DOCKALL)
    If $fFullPath Then GUICtrlSetState(-1, $GUI_CHECKED)
        GUICtrlSetOnEvent(-1, '_FullPath')
 
$hSavePos  = GUICtrlCreateCheckbox('Сохранять позицию', 10, 30, 120, 20)
    GUICtrlSetResizing(-1, $GUI_DOCKALL)
    If $fSavePos Then GUICtrlSetState(-1, $GUI_CHECKED)
        GUICtrlSetOnEvent(-1, '_SavePos')
 
$hSaveSize = GUICtrlCreateCheckbox('Сохранять размер',  142, 30, 115, 20)
    GUICtrlSetResizing(-1, $GUI_DOCKALL)
    If $fSaveSize Then GUICtrlSetState(-1, $GUI_CHECKED)
        GUICtrlSetOnEvent(-1, '_SaveSize')
 
$hList = GUICtrlCreateListView('Результаты обработки', 10, 55, $iWidth-20, $iHeight-65)
    GUICtrlSetResizing(-1, $GUI_DOCKBORDERS)
    _GUICtrlListView_SetColumnWidth($hList, 0, 800)
 
$hImage = _GUIImageList_Create()
    _GUIImageList_Add($hImage, _GUICtrlListView_CreateSolidBitMap($hList, 0xFF0000, 16, 16))
    _GUIImageList_Add($hImage, _GUICtrlListView_CreateSolidBitMap($hList, 0x00FF00, 16, 16))
    _GUICtrlListView_SetImageList($hList, $hImage, 1)
 
GUICtrlSetState($hList,       $GUI_FOCUS)
GUIRegisterMsg($WM_DROPFILES, 'WM_DROPFILES')
GUIRegisterMsg($WM_NCHITTEST, 'WM_NCHITTEST')
GUIRegisterMsg($WM_MOVE,      'WM_MOVE')
GUIRegisterMsg($WM_SIZE,      'WM_SIZE')
GUISetState()
 
Func WM_DROPFILES($hWnd, $msg, $wParam, $lParam)
    Local $tBuffer = DllStructCreate('char[256]')
    Local $iString, $sDir, $sDirTo, $hSearch, $sFile
    Local $aRet = DllCall('shell32.dll', 'int', 'DragQueryFile', 'int', $wParam, 'int', -1, 'ptr', 0, 'int', 0)
 
;~  If $aRet[0] > 0 Then _GUICtrlListView_DeleteAllItems($hList)
 
    For $i = 0 To $aRet[0] - 1
        DllCall('shell32.dll', 'int', 'DragQueryFile', 'int', $wParam, 'int', $i, 'ptr', DllStructGetPtr($tBuffer), 'int', DllStructGetSize($tBuffer))
        $sDir = DllStructGetData($tBuffer, 1)
 
        If StringInStr(FileGetAttrib($sDir), 'D') Then
            $hSearch = FileFindFirstFile($sDir & '\*.*')
            If @error == -1 Then ContinueLoop
            Dim $iFile1 = 0, $iFile2 = 0, $iFile3 = 0
            While 1
                $sFile = FileFindNextFile($hSearch)
                If @error Then ExitLoop
                $sFile = StringRegExpReplace($sFile, '.*\.(.+)$', '\1')
                Switch $sFile
                    Case 'cue'
                        $iFile1 += 1
                    Case 'ape'
                        $iFile2 += 1
                    Case 'flac'
                        $iFile2 += 1
                    Case 'wv'
                        $iFile2 += 1
                    Case Else
                        $iFile3 += 1
                EndSwitch
            WEnd
            FileClose($hSearch)
            If $iFile1 == 1 AND $iFile2 == 1 AND $iFile3 == 0 Then
                $iFile1 = 1
            Else
                $sDirTo = StringRegExpReplace($sDir, '(.+\\)(.+)$', '\1' & '_\2')
                DirMove($sDir, $sDirTo)
                $sDir = $sDirTo
                $iFile1 = 0
            EndIf
            If NOT $fFullPath Then $sDir = StringRegExpReplace($sDir, '.+\\(.+)$', '\1')
            GUICtrlCreateListViewItem('  ' & $sDir, $hList)
            _GUICtrlListView_SetItemImage($hList, _GUICtrlListView_GetItemCount($hList)-1, $iFile1)
        EndIf
    Next
 
    DllCall('shell32.dll', 'none', 'DragFinish', 'int', $wParam)
    Return $GUI_RUNDEFMSG
EndFunc
 
Func WM_NCHITTEST($hWnd, $Msg, $wParam, $lParam)
    Local $iProc = DllCall('user32.dll', 'int', 'DefWindowProc', 'hwnd', $hWnd, 'int', $Msg, 'wparam', $wParam, 'lparam', $lParam)
    If $iProc[0] = $HTCLIENT Then Return $HTCAPTION
    Return $GUI_RUNDEFMSG
EndFunc
 
Func WM_MOVE($hWnd, $Msg, $wParam, $lParam)
    If NOT $fSavePos OR BitAnd(WinGetState($hMainWin), 16) OR BitAnd(WinGetState($hMainWin), 32) Then Return
    Local $aWinPos = WinGetPos($hMainWin)
    RegWrite($sKey, 'X', 'REG_DWORD', $aWinPos[0])
    RegWrite($sKey, 'Y', 'REG_DWORD', $aWinPos[1])
EndFunc
 
Func WM_SIZE($hWnd, $Msg, $wParam, $lParam)
    If NOT $fSaveSize OR BitAnd(WinGetState($hMainWin), 16) OR BitAnd(WinGetState($hMainWin), 32) Then Return
    RegWrite($sKey, 'Width',  'REG_DWORD', _WinAPI_LoWord($lParam))
    RegWrite($sKey, 'Height', 'REG_DWORD', _WinAPI_HiWord($lParam))
EndFunc
 
Func _FullPath()
    $fFullPath = BitAND(1, GUICtrlRead($hFullPath))
    RegWrite($sKey, 'Full path', 'REG_DWORD', $fFullPath)
EndFunc
Func _SavePos()
    $fSavePos = BitAND(1, GUICtrlRead($hSavePos))
    RegWrite($sKey, 'Save pos', 'REG_DWORD', $fSavePos)
EndFunc
Func _SaveSize()
    $fSaveSize = BitAND(1, GUICtrlRead($hSaveSize))
    RegWrite($sKey, 'Save size', 'REG_DWORD', $fSaveSize)
EndFunc
 
Func _Clear()
    _GUICtrlListView_DeleteAllItems($hList)
EndFunc
 
While 1
    Sleep(10)
WEnd
 
Func _Pro_Exit()
    Exit
EndFunc
 

vcomp71

Осваивающий
Сообщения
431
Репутация
25
А если их скопировать в буфер и после разобрать по составляющим? Ну в Проводнике сгенерировать копку, по которой выделение копируется в буфер, получается список папок, и потом уже проверяется в каких из них есть подпапки. Задача средней трудоемкости, сразу вот так скрипт выложит не могу, но идею подсказать могу.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Vlasssov сказал(а):
А если их скопировать в буфер и после разобрать по составляющим? Ну в Проводнике сгенерировать копку, по которой выделение копируется в буфер, получается список папок, и потом уже проверяется в каких из них есть подпапки. Задача средней трудоемкости, сразу вот так скрипт выложит не могу, но идею подсказать могу.

Первым делом нужно получить полный путь к текущей папке.
 

SECTOR

Продвинутый
Сообщения
399
Репутация
59
Путь к текущей папке я получаю так:
Код:
#include <WinAPI.au3>
#include <Misc.au3>

Sleep(2000)
MsgBox(0,"",ExplorerGetPath())

Func ExplorerGetPath($hWin="[ACTIVE]")

Local $handle = WinGetHandle($hWin)
Local $class = _WinAPI_GetClassName($handle)
Local $path = 0
Local $regread = RegRead("HKU\S-1-5-21-1275210071-1078145449-1644491937-500\Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState\","FullPathAddress")

Switch $class
	Case "Progman"
		$path = @DesktopDir
	Case "CabinetWClass"
		If $regread = 0x00000000 Then
			RegWrite("HKU\S-1-5-21-1275210071-1078145449-1644491937-500\Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState\","FullPathAddress","REG_DWORD",0x00000001)
			ControlSend($handle,"","SysListView321","{F5}")
			$path = StringSplit(WinGetText($handle),@CRLF)
			If IsArray($path) Then $path = $path[1]
			RegWrite("HKU\S-1-5-21-1275210071-1078145449-1644491937-500\Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState\","FullPathAddress","REG_DWORD",$regread)
		Else
			$path = WinGetTitle($handle)
		EndIf
EndSwitch

If Not FileExists($path) Then $path = __GetPathFromTempFile($handle)

Return $path

EndFunc

Func __GetPathFromTempFile($CabinetWClass)

$RegExp_Path = "(.*)\\([^\\].+)"
$TempFile = "~_AU3Temp_"&Random(1,9999,1)&".tmp"
$path = 0

$temp = @TempDir&"\"&$TempFile
If FileExists($temp) Then FileDelete($temp) 
FileWrite($temp,"Temp File :)")
Sleep(10)
_ClipPutFile($temp)
Sleep(10)

$ListView = ControlGetHandle($CabinetWClass,"","SysListView32")
ControlSend($CabinetWClass,"",$ListView,"+{INS}")
Sleep(100)

ControlSend($CabinetWClass,"",$ListView,"^{INS}")
Sleep(50)
$tpath = ClipGet()
If FileExists($tpath) Then
	FileDelete($tpath)
	ControlSend($CabinetWClass,"",$ListView,"{F5}")
	$path = StringRegExpReplace($tpath,$RegExp_Path,"\1")
EndIf

FileDelete($temp)

Return $path

EndFunc

Давно уже писал, но вроде работает :smile:
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
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_SHOW, $hGUI)

While 1
    $nMsg = GUIGetMsg()

    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $GUI_EVENT_DROPPED
            _ClearSelection()
    EndSwitch
WEnd

Func _ClearSelection()
	$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
            _FileListToArray($aSelected_Files[$i][2], "*", 2)
        EndIf
        
        If $aSelected_Files[$i][1] = 0 Or @error = 4 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


P.S
Тестировалось только на XP.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Alexey [?]
ничего не происходит, все закинутые папки сохраняют выделение
Они точно пустые, возможно в них скрытые файлы есть?


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

Только сейчас обратил внимание:
[?]
скрипт снимает выделение с тех из них, которые не имеют вложенных папок

Поправил скрипт.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Я вот только одного не пойму, зачем нужна вся эта возня с DropFiles, когда есть функция _GetWindowsExplorerPath(). Вся проблема в этой задачке, как раз была в получении полного пути к активной папке. Проще ведь снимать выделение по горячей клавише...

:whistle:

А так хороший пример.

OffTopic:
Жаль, что WideBoyDixon ушел с оф. форума, хорошие примеры писал в свое время.


В Windows Vista/7 это не будет работать, т.к. там нет ни 'SysListView32', ни CWM_GETPATH. Вот такие вот дела.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Yashied [?]
зачем нужна вся эта возня с DropFiles
Так попросил автор темы, т.ч это не ко мне :smile:

Проще ведь снимать выделение по горячей клавише...
Конечно:

Код:
#NoTrayIcon
#include <File.au3>

HotKeySet("^+s", "_ClearSelection")
HotKeySet("^+e", "_Exit")

While 1
    Sleep(10)
WEnd

Func _ClearSelection()
	$sCabinetWClass = "[CLASS:CabinetWClass]"
	$aSelected_Files = _ExplorerGetSelectedItems($sCabinetWClass)
	
	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
			_FileListToArray($aSelected_Files[$i][2], "*", 2)
		EndIf
		
		If $aSelected_Files[$i][1] = 0 Or @error = 4 Then
			ControlListView($sCabinetWClass, "", "SysListView321", "DeSelect", $aSelected_Files[$i][0])
		EndIf
	Next
EndFunc

Func _Exit()
	Exit
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($sCabinetWClass="[CLASS:CabinetWClass]")
    Local $aRetInfo[1][1]
    Local $aIndexes, $iIndex, $iCount, $sSelected, $sSelected_Path
    Local $hSearch, $sCurrentFile
    
    $sSelected_Path = _GetWindowsExplorerPath(WinGetHandle($sCabinetWClass))
    $sSelected_Path = StringRegExpReplace($sSelected_Path, "\\+$", "")
    $aIndexes = StringSplit(ControlListView($sCabinetWClass, "", "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($sCabinetWClass, "", "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



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

А для совместимости с Vista/7 можно попробовать вот такой “жёсткий” метод:

Код:
Func _GetWindowsExplorerPath($hWnd)
	Local $sRet, $sWinClass, $iTimer
	
	$sRet = ControlGetText($hWnd, "", "Edit1")
	$sWinClass = WinGetClassList($hWnd)
	
	If Not StringInStr($sWinClass, "ComboBoxEx") Or Not FileExists($sRet) Then
		WinActivate($hWnd)
		ControlSend($hWnd, "", "", "{ALT}{RIGHT 2}{DOWN}{RIGHT}{DOWN}{ENTER}")
		
		$iTimer = TimerInit()
		
		While Not FileExists($sRet)
			If TimerDiff($iTimer) >= 5000 Then
				ExitLoop
			EndIf
			
			$sRet = ControlGetText($hWnd, "", "Edit1")
		WEnd
		
		WinActivate($hWnd)
		ControlSend($hWnd, "", "", "{ALT}{RIGHT 2}{DOWN}{RIGHT}{DOWN}{ENTER}")
	EndIf
	
	Return $sRet
EndFunc
 
Автор
A

Alexey

Новичок
Сообщения
171
Репутация
0
[quote author=CreatoR]
Они точно пустые, возможно в них скрытые файлы есть?
[/quote]
точно. я специально создал тестовую папку, содержащую 8 под-папок, 5 из которых тоже содержат по одной под-папке
никаких файлов нигде нет вообще - я их в тест не включаю, поскольку, в моём понимании, скрипту должно быть без разницы, есть ли какие-то вложенные файлы, или нет

[quote author=CreatoR]
Поправил скрипт.
[/quote]
всё равно пока не работает - выделение всех восьми вышеупомянутых папок остаётся

[quote author=Yashied]
зачем нужна вся эта возня с DropFiles ... Проще ведь снимать выделение по горячей клавише
[/quote]
да, по горячей клавише почти всегда всё проще (к слову, я их себе понастраивал не один десяток), но не в этот раз
в случае удачного исхода скриптом из этой темы буду пользоваться периодически, но не ежедневно. соответственно, в памяти мне лишний процесс, ждущий нажатия на свой hot-key, ни к чему. я просто как обычно назначу сочетание клавиш (на вызов скомпилированного exe-файла) и буду его нажимать, когда потребуется
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Alexey [?]
выделение всех восьми вышеупомянутых папок остаётся
А что показывает это (при выделенных папках):

Код:
#include <Array.au3>

$aSelected_Files = _ExplorerGetSelectedItems()
_ArrayDisplay($aSelected_Files)

;[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($sCabinetWClass="[CLASS:CabinetWClass]")
    Local $aRetInfo[1][1]
    Local $aIndexes, $iIndex, $iCount, $sSelected, $sSelected_Path
    Local $hSearch, $sCurrentFile
    
    $sSelected_Path = _GetWindowsExplorerPath(WinGetHandle($sCabinetWClass))
    $sSelected_Path = StringRegExpReplace($sSelected_Path, "\\+$", "")
    $aIndexes = StringSplit(ControlListView($sCabinetWClass, "", "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($sCabinetWClass, "", "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


И ещё, это обычная папка проводника?
Скрин всё таки можно увидеть (с выделением)?


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

Alexey [?]
я просто как обычно назначу сочетание клавиш (на вызов скомпилированного exe-файла) и буду его нажимать, когда потребуется
Ну тогда зачем делать окошко для перетаскивания, пусть скрипт сразу обрабатывает выделенные папки.
 
Автор
A

Alexey

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

И ещё, это обычная папка проводника?
Скрин всё таки можно увидеть (с выделением)?
обычные папки. вот скрин:

ss-2010.08.11.png

Ну тогда зачем делать окошко для перетаскивания, пусть скрипт сразу обрабатывает выделенные папки
просто мне удобнее и привычнее с окном. к тому же это безопаснее (если нечаянно нажимается другая соседняя комбинация клавиш я всегда могу всё отменить, не потеряв выделения папок)
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Alexey [?]
всё по-прежнему, выделение сохраняется
Этот пример ничего не делает, он должен был вывести список выделенных файлов.

обычные папки. вот скрин
Это не обычная папка, там проводник с другим классом (ExplorerWClass), пример поправил снова (первый).
 
Автор
A

Alexey

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

по-видимому, скрипт не видит разницы между папками и файлами и его нужно поправить так, чтобы он не обращал внимания на файлы, а проверял лишь наличие под-папок
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Alexey [?]
скрипт не видит разницы между папками и файлами
Видит, я 10 раз проверял скрипт с разными папками... скрипт точно взят отсюда?

Для ясности, скрипт не проверяет рекурсивно каталоги, только то что находится на первом уровне подкаталога.
 
Верх