Что нового

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

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 713
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
 

Vlasssov

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

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 713
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 473
Репутация
2 403
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.
 
Автор
A

Alexey

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

Тестировалось только на XP
другого не держим
 

CreatoR

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


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

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

Yashied

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

:whistle:

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

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


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

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8 473
Репутация
2 403
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 473
Репутация
2 403
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
А что показывает это (при выделенных папках)
всё по-прежнему, выделение сохраняется

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


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

CreatoR

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

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

Alexey

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

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

CreatoR

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

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