Что нового

многократная отправка в буфер обмена названий большого количества файлов

Автор
A

Alexey

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

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

тему помечаю решённой, но буду время от времени в неё заходить - вдруг вопрос с u-torrent'ом кто-нибудь сможет решить (ещё раз вкратце суть - нужно сделать так, чтобы файлы определённых расширений перестали отображаться в окне содержимого torrent-файла)
 
Автор
A

Alexey

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

CreatoR

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

Код:
#include <Array.au3>

Global $aIncludeFilesMask = StringSplit(".torrent", "|") ;Разрешённые расширения файлов
Global $iShowInvalidExtsMessage = 1 ;Показывать сообщение о неподдерживаемых расширении файлов
Global $iClipPutInterval = 1000 ;Время ожидания (в миллисекундах) между отправкой файла в буфер обмена

$hExplorer = WinGetHandle("[CLASS:ExplorerWClass]")
If @error Then $hExplorer = WinGetHandle("[CLASS:CabinetWClass]")

$aSelected_Files = _ExplorerGetSelectedItems($hExplorer)
If @error Then Exit MsgBox(48, "Error", "It seems that there is no selected files, but also it can be an internal function error.")

Dim $aDroppedFiles[$aSelected_Files[0][0]+1]

For $i = 1 To $aSelected_Files[0][0]
	$aDroppedFiles[0] += 1
	$aDroppedFiles[$aDroppedFiles[0]] = $aSelected_Files[$i][2]
Next

$sNotValidExtPath = ""
_ArraySort($aDroppedFiles, 1, 1)

For $i = 1 To UBound($aDroppedFiles)-1
	If _DroppedFileIsValidExt($aDroppedFiles[$i]) Then
		ClipPut(StringRegExpReplace($aDroppedFiles[$i], '^.*\\|\.[^\.]*$', ''))
		
		If $iClipPutInterval Then
			Sleep($iClipPutInterval)
		EndIf
	Else
		$sNotValidExtPath &= $aDroppedFiles[$i] & @CRLF
	EndIf
Next

If $iShowInvalidExtsMessage And $sNotValidExtPath <> "" Then
	MsgBox(262144+48, "Attention!", "Ther are selected file(s) with non valid extension/attribute:" & @CRLF & @CRLF & $sNotValidExtPath)
EndIf

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

Func _DroppedFileIsValidExt($sPath)
    For $i = 1 To $aIncludeFilesMask[0]
        If StringRegExp($sPath, '(?i)\Q' & $aIncludeFilesMask[$i] & '\E$') Or StringInStr(FileGetAttrib($sPath), $aIncludeFilesMask[$i]) Then
            Return True
        EndIf
    Next
    
    Return False
EndFunc
 
Автор
A

Alexey

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

- не работает, если запускать из SciTE. выдаёт "Ther are selected file(s) with non valid extension/attribute: \0"
- работает, если запускать скомпилированный .exe

(в $iClipPutInterval в итоге поставил 500 - даже при 200 бывают ошибки)

добавлено позже
заметил досадный нюанс. к примеру, есть файлы:
File 1.torrent
File 2.torrent
File 4.torrent
File ( 3 ).torrent
именно в таком порядке они отображаются в проводнике. но в буфер они добавляются в очерёдности:
File 4
File 2
File 1
File ( 3 )
а ведь очерёдность должна быть:
File ( 3 )
File 4
File 2
File 1

(проверил, в предыдущем варианте скрипта всё тоже самое)
 

CreatoR

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

очерёдность должна быть
Не совсем. _ArraySort сортирует по величине значения символов (по их Dec-коду), логики там особо нет. Таким образом, символ скобки «(» меньше любого числового символа, в этом можно убедиться посмотрев таблицу символов в справке.
 
Автор
A

Alexey

Новичок
Сообщения
171
Репутация
0
естественно при условий что файлы выделенный в этот момент
да, выделены (как при запуске .exe, так и при выборе tools - go в SciTE Script Editor)

очерёдность должна быть
имелось в виду, что в контексте поставленной задачи очерёдность должна быть чёткой, именно как в проводнике (но только с конца по начáло)
¿получается, windows explorer и _ArraySort сортируют некоторые символы по-разному? конечно, придётся смириться с этим, если решения нет (хорошо хоть, у меня в подавляющем большинстве случаев это не играет роли)

к слову, иногда поведение проводника мне не видится совсем уж ясным. к примеру:
данные 4 файла он сортирует так:
(.torrent
1.torrent
2.torrent
3.torrent

а другие похожие 4 файла вот так:
a1.torrent
a2.torrent
a3.torrent
a(.torrent
почему-то при добавлении одной и той же буквы меняется сортировка относительно цифр и скобки
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Alexey [?]
при выборе tools - go в SciTE
А если нажать на F5? (тоже самое, но возможно проблема из за менню).

имелось в виду, что в контексте поставленной задачи очерёдность должна быть чёткой, именно как в проводнике
Я знаю что имелось в виду :smile:

получается, windows explorer и _ArraySort сортируют некоторые символы по-разному?
Нет, в первом списке нет сортировки (там где 1, 2, 4, ( 3 )), функция сортирует этот список и ей не важно каков там порядок. Если нужно в таком же порядке, то не нужно использовать _ArraySort, если нужно просто перевернуть порядок, то массив нужно перечитать сс конца к началу.

данные 4 файла он сортирует так
Всё верно - круглая скобка в списке символов стоит раньше чем числа.

а другие похожие 4 файла вот так
Опять всё верно - сначала сортируется по первому символу («a»).
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Вот что нужно если я не ошибаюсь:

Код:
....

For $i = $aSelected_Files[0][0] To 1 Step -1
    $aDroppedFiles[0] += 1
    $aDroppedFiles[$aDroppedFiles[0]] = $aSelected_Files[$i][2]
Next

$sNotValidExtPath = ""
;_ArraySort($aDroppedFiles, 1, 1)

...
 
Автор
A

Alexey

Новичок
Сообщения
171
Репутация
0
А если нажать на F5? (тоже самое, но возможно проблема из за менню)
и tools - go, и F5 одинаково выдают ошибку
могу лишь предположить, что по какой-то причине это происходит из-за того, что при запуске .exe активным окном является проводник, а при запуске из SciTE активным окном является всё же SciTE. файлы выделены в обоих случаях, но в первом это выделение активно, а во втором - нет

а другие похожие 4 файла вот так
Опять всё верно - сначала сортируется по первому символу («a»)
вот этого я как раз понять никак пока не могу. ну сортируется по первому символу "а", но ведь все 4 названия одинаково начинаются с этого символа, значит, чтобы отсортировать, нужно далее смотреть на вторые символы, а они ничем не отличаются от первого варианта

Вот что нужно если я не ошибаюсь
заменил стрóки 15-21 новым вариантом - теперь в буфер добавляется как надо. спасибо за помощь
 

CreatoR

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

Вот пример показывающий как это происходит в сортировке массива:

Код:
$a = Asc("a") 		;Величина символа "a"
$1 = Asc("1") 		;Величина символа "1"
$2 = Asc("2") 		;Величина символа "2"
$3 = Asc("3") 		;Величина символа "3"
$Brkt = Asc("(") 	;Величина символа "("

ConsoleWrite($a + $1 & @LF) ;Величина всех символов вместе ("a1")
ConsoleWrite($a + $2 & @LF) ;Величина всех символов вместе ("a2")
ConsoleWrite($a + $3 & @LF) ;Величина всех символов вместе ("a3")
ConsoleWrite($a + $Brkt & @LF) ;Величина всех символов вместе ("a(")


и сортировка по массиву:

Код:
#include <Array.au3>

Dim $aArr[4] = ["a1", "a2", "a3", "a("]
_ArraySort($aArr)
_ArrayDisplay($aArr)


результат:
Код:
a(
a1
a2
a3

очень странно...

P.S
Возможно у Windows своя таблица символов :laugh:
 

axlwor

Скриптер
Сообщения
657
Репутация
147
оффтоп, конечно.. но..
А зачем все это нужно? Для обучения autoit или есть прикладное применение?
PS. 3 раза прочел тему но так и не понял что хотят получить :'( :beer:
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Верх