Я уже забыл, верхнее меню это что у нас?Orion9 писал(а):будь я на вашем месте, я сделал бы верхнее меню
Autorun
Модераторы: Avada, CaptainFlint, Nik, d-view, Моторокер
Это то, к чему Гислер за 30 лет не сделал никакого GUI, хотя именно это нужно было делать в первую очередь, а не отмазываться от пользователя неудобным меню "Запуск", которое, как выяснилось, имеет еще и кривую многоязычную поддержку, исправлять которую он теперь не желает. Как-то так.AkulaBig писал(а):Я уже забыл, верхнее меню это что у нас?
Думал, что еще не скоро возьмусь за Autorun, но понадобилась одна фича, над которой сейчас работаю. Простенький монитор каталога, чтобы отслеживал изменения и сообщал об удаленных файлах в реальном времени. Попутно сделал кнопку для подсчета времени воспроизведения в каталоге. Что-то подобное делает плагин MediaTime. При желании можно полностью заменить его функционал, если не устраивает одиночное нажатие кнопки:
[cut]TOTALCMD#BAR#DATA
62013
%COMMANDER_EXE%
Подсчёт времени воспроизведения
-1
[/cut]
[cut]
Код: Выделить всё
RegisterCommand 62013 "DurationInfo"
Func DurationInfo(lParam)
Local name = RequestCopyDataInfo("SN")
Local file = RequestCopyDataInfo("SP") & RequestCopyDataInfo("SN")
If Not FileExist(file) Then
ShowHint("Файл не существует " & file)
Return
Endif
Local obj = Plugin("TCMediaInfo")
If ERROR <> 0 Then
ShowHint("TCMediaInfo plugin error " & ERROR)
Return
Endif
Local s = 0
If Not StrPos(FileGetAttr(file), "D") Then
obj.FileName = file
s = obj.GetValue(0) # duration
ShowHint("Файл: " & name & auCRLF & "Длительность: " & s)
Free(obj)
Return
Endif
Local i, out, files = 0, aFiles = List(), seconds = 0
ShowHint("Подсчёт времени")
# загрузка файлов в массив
ProcessExecGetOutput /OEM out %COMSPEC% "/c dir /s /b *.*" %"file"
aFiles.Text = out
# ShowHint("Обработка " & aFiles.Count & " элементов")
For i = 0 To aFiles.Count - 1
obj.FileName = aFiles[i]
s = obj.GetValue(0,2) # duration -> seconds
If s > 0 Then
seconds += s
files += 1
EndIf
Next
Free(obj)
Local day = Floor(seconds / 86400)
Local hour = Floor((seconds - (day * 86400)) / 3600)
Local min = Floor(((seconds - (day * 86400)) - (hour * 3600)) / 60)
Local sec = seconds - (day * 86400 + hour * 3600 + min * 60)
Local total = StrFormat("%02d:%02d:%02d:%02d",day,hour,min,sec)
ShowHint("Каталог: " & name & auCRLF & _
"Элементов: " & aFiles.Count & auCRLF & _
"Обработано: " & files & auCRLF & _
"Секунд: " & seconds & auCRLF & _
"Минут: " & Round(seconds / 60, 2) & auCRLF & _
"Часов: " & Round(seconds / 3600, 2) & auCRLF & _
"Суток: " & Round(seconds / 86400, 2) & auCRLF & _
"Длительность: " & total)
EndFuncФункция полностью завязана на плагин TCMediaInfo и его поля, хотя, конечно, можно было и через DllCall сделать, но использование объекта Plugin сводит весь код на Autorun до смешных нескольких строк.
У меня наоборот, что-то возникло желание переделать пользовательские колонки на Dll, отказавшись от TCMediaInfo. Его использовать только как листер-плагин. Как-бы в моем понимании это даст какую-то упорядоченность.Orion9 писал(а):Функция полностью завязана на плагин TCMediaInfo и его поля, хотя, конечно, можно было и через DllCall сделать
Только вот навряд-ли Autorun выдержит еще полей 30. Думаю в данном случае как-раз попробовать использовать файл типа hint.txt или массив значений.
Имхо, TCMediaInfo один из лучших плагинов, не понятно, зачем от него отказываться. Я наоборот хотел с ним лучше разобраться, т.к. он у меня в подвисшем состоянии остался.AkulaBig писал(а):отказавшись от TCMediaInfo
Да поля-то он, наверное, выдержит, только все-равно не понятно, зачем заменять один плагин другим. В скорости, например, от этого вряд ли получится выиграть, я как раз в этом убедился сейчас.AkulaBig писал(а):Только вот навряд-ли Autorun выдержит еще полей 30.
Пришлось переделать функцию подсчета, убрав из неё получение списка через ProcessExecGetOutput, т.к. этот вариант не работает с UNC-путями. Попутно сделал вызов через DllCall и расширил функционал. Сейчас вызов с ALT делает подсчет через плагин TCMediaInfo.wdx, а простой вызов через MediaInfo.dll. Поскольку MediaInfo.dll обрабатывает все файлы (даже те, которые не-медиа, что замедляет работу), пришлось добавить фильтр. При включеном CapsLock фильтр отключается. Вызов с CTRL ограничивает глубину каталога до первого уповня. SHIFT - выводит в окно отладчика информацию о пропущенных элементах.
[cut]
Код: Выделить всё
RegisterCommand 62013 "Duration"
Func Duration(lParam)
RunThread DurationInfo
EndFunc
Func DurationInfo()
Local T1 = GetUptime()
Local b_Ctrl = IsPressed(0x11), b_Shift = IsPressed(0x10), b_Alt = IsPressed(0x12)
Local b_Caps = BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1)
Local name = RequestCopyDataInfo("SN")
Local file = RequestCopyDataInfo("SP") & name
If Not FileExist(file) Then
ShowHint("Файл не существует " & file)
Return
Endif
Local hMI = 0
Static sLib = "MediaInfo" & (auX64 ? "" : "_i386") & ".dll", _
hLib = DllCall("LoadLibrary", "wstr", COMMANDER_PATH & "\Ini\Tools\Libs" & sLib, "ptr")
Static sExt = ".aac .ac3 .aif .aiff .aifc .afc .ape .au .snd .cda .dsf .dts .dtswav .dtshd .dtsma .eac3 .flac .fla _
.m1a .m2a .mka .mpa .mp1 .mp2 .mp3 .mp4 .m4a .m4b .m4r .mod .mpc .mp+ .mpp .ogg .ogg .oga .ogx .ogg _
.ra .spx .opus .qoa .svx .8svx .tak .tta .wav .wave .w64 .bwf .rf64 .wma .wv .avi .wmv .wmp .wm .asf _
.mpg .mpeg .mpe .m1v .m2v .mpv2 .mp2v .ts .tp .tpr .trp .vob .ifo .ogm .ogv .mp4 .m4v .m4p .m4b .3gp _
.3gpp .3g2 .3gp2 .mkv .rm .ram .rmvb .rpm .flv .swf .mov .qt .amr .nsv .dpg .m2ts .m2t .mts .dvr-ms _
.k3g .skm .evo .nsr .amv .divx .webm .wtv .f4v .mxf"
If Not b_Alt Then
If hLib = 0 Then
ShowHint("Error LoadLibrary " & sLib)
Return
EndIf
hMI = DllCall(sLib & '\MediaInfo_New', "Ptr")
If hMI = 0 Then
ShowHint("MediaInfo failed to create new object")
Return
Endif
Else
Local obj = Plugin("TCMediaInfo")
If ERROR <> 0 Then
ShowHint("TCMediaInfo plugin error " & ERROR)
Return
Endif
EndIf
Local s = 0
If Not StrPos(FileGetAttr(file), "D") Then
If b_Alt Then
obj.FileName = file
s = obj.GetValue(0) # duration
Free(obj)
Else
If DllCall(sLib & '\MediaInfo_Open', 'ptr', hMI, "wstr", file, "uint") <> 1 Then
Return ShowHint("MediaInfo_Open failed to open file " & file)
EndIf
s = DllCall(sLib & '\MediaInfo_Get', _
'ptr', hMI, "int", 0, "int", 0, "wstr", "Duration/String3", "int", 1, "int", 0, "wstr")
EndIf
Return ShowHint("Файл: " & name & auCRLF & "Длительность: " & s)
Endif
Local i, out, dirs = 0, files = 0, errs = 0, aFiles = List(), seconds = 0
Local depth = (b_Ctrl ? 1 : 0)
ShowHint("Depth: " & depth & auCRLF & _
"CapsLock: " & (b_Caps ? "yes" : "no") & auCRLF & _
(b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"Подсчёт времени")
b_Win = false
# загрузка файлов в массив
If b_Win Then
#ProcessExecGetOutput /OEM out %COMSPEC% "/c dir /s /b *.*" %"file"
#aFiles.Text = out
Else
ListDirectory(file, aFiles, depth)
EndIf
# ShowHint("Обработка " & aFiles.Count & " элементов")
For i = 0 To aFiles.Count - 1
If StrPos(FileGetAttr(aFiles[i]), "D") Then
dirs += 1
If b_Shift Then OutputDebugString("Duration:Directory:" & aFiles[i])
Continue
EndIf
If b_Alt Then
obj.FileName = aFiles[i]
s = obj.GetValue(0,3) # duration -> milliseconds
Else
ext = FileGetExt(aFiles[i])
If Not b_Caps Then
If Not StrPos(sExt, '.' & ext) Then
If b_Shift Then OutputDebugString("Duration:Filter:" & aFiles[i])
Continue
EndIf
EndIf
If DllCall(sLib & '\MediaInfo_Open', 'ptr', hMI, "wstr", aFiles[i], "uint") <> 1 Then
errs += 1
If b_Shift Then OutputDebugString("Duration:Error:" & aFiles[i])
Continue
EndIf
s = DllCall(sLib & '\MediaInfo_Get', _
'ptr', hMI, "int", 0, "int", 0, "wstr", "Duration", "int", 1, "int", 0, "wstr")
EndIf
If s > 0 Then
seconds += s
files += 1
Else
If b_Shift Then OutputDebugString("Duration:Empty:" & aFiles[i])
EndIf
If IsPressed(0x11) And IsPressed(0x12) Then
ShowHint((b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"CapsLock: " & (b_Caps ? "yes" : "no") & auCRLF & _
"Depth: " & depth & auCRLF & _
"File: " & i & " of " & aFiles.Count & auCRLF & _
aFiles[i])
EndIf
Next
If b_Alt Then Free(obj)
If hMI <> 0 Then DllCall(sLib & '\MediaInfo_Delete', "Ptr", hMI)
seconds = Floor(seconds / 1000)
Local day = Floor(seconds / 86400)
Local hour = Floor((seconds - (day * 86400)) / 3600)
Local min = Floor(((seconds - (day * 86400)) - (hour * 3600)) / 60)
Local sec = seconds - (day * 86400 + hour * 3600 + min * 60)
Local total = StrFormat("%02d:%02d:%02d:%02d",day,hour,min,sec)
ShowHint("Папка: " & name & auCRLF & _
"Каталогов: " & dirs & auCRLF & _
"Элементов: " & aFiles.Count & auCRLF & _
"Обработано: " & files & auCRLF & _
"Ошибки DLL: " & errs & auCRLF & _
"Секунд: " & seconds & auCRLF & _
"Минут: " & Round(seconds / 60, 2) & auCRLF & _
"Часов: " & Round(seconds / 3600, 2) & auCRLF & _
"Суток: " & Round(seconds / 86400, 2) & auCRLF & _
"Длительность: " & total & auCRLF & _
"Powered by " & (b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"Время операции: " & Round(GetUptime() - T1, 3))
Free(aFiles)
EndFunc
Func ListDirectory(sPath, ByRef aList, nDepth = 1)
Local sFile, nAttr
Local ffd = Buffer(604)
Local hf = DllCall("FindFirstFileW", "wstr", sPath & "\*.*", "ptr", ffd.Ptr)
If hf <> 0 then
While True
sFile = ffd.GetStr(44) # cFileName
nAttr = ffd.GetNum(0, "dword") # dwFileAttributes
If BitAND(nAttr, 16) Then
If Not ((sFile = ".") Or (sFile = "..")) Then
aList.Add(sPath & "" & sFile)
If nDepth <> 1 Then
ListDirectory(sPath & "" & sFile, aList, nDepth - 1)
EndIf
EndIf
Else
aList.Add(sPath & "" & sFile)
Endif
If DllCall("FindNextFileW", "handle", hf, "ptr", ffd.Ptr) = 0 Then Break
Wend
DllCall("FindClose", "handle", hf)
Endif
Free(ffd)
EndFuncВ этом все и дело. Если зайдете в его тему, увидите, что мы там обсуждали некоторые проблемы. Не все гладко с файлом настройки. Вот и получается, что либо там разбираться с настройками, либо здесь пойти по уже проторенной дорожке. Ну а листер-плагину TCMediaInfo альтернативы нет.Orion9 писал(а):он у меня в подвисшем состоянии остался
Так ведь плагин TCMediaInfo и есть проторенная дорожка. Вопрос здесь больше в изучении самой MediaInfo.dll и её возможностей, чтобы лучше понимать что и в каких случаях выводить. А для этого придётся глубже копнуть в форматы файлов и их устройство, а не только в изучение настроек XML.AkulaBig писал(а):либо там разбираться с настройками, либо здесь пойти по уже проторенной дорожке
Откинул меня подсчёт времени воспроизведения, но вроде доделал как надо, хотя нужно больше тестов. Сейчас повторное нажатие на кнопку прерывает операцию, как и комбинация Win + ESC. Зажатие CTRL + ALT во время подсчёта показывает прогресс операции в подсказке. Обнаружил одну неприятную проблему. MediaInfo.dll может зависнуть на некоторых файлах и повесить ТС. Пока мне попался один такой файл, который нормально проигрывается, но видимо с тегами что-то не так. Foobar при проверке целостности пишет: Warning: Multiple ID3v2 tags encountered, item decoded with minor problems. Программа Mp3Tag пишет: ID3v2.3 ERROR: MP3 header parse error. В остальном проблем больше не заметил. Последняя версия кнопки:
[cut]
Код: Выделить всё
RegisterCommand 62013 "Duration"
Global MI_DURATION = 0, MI_BREAK = false
Func Duration(lParam)
If MI_DURATION > 0 Then
MI_BREAK = true
Sleep(250)
Return
EndIf
RunThread DurationInfo
EndFunc
Func DurationInfo()
Local T1 = GetUptime(), T2 = 0
Local b_Ctrl = IsPressed(0x11), b_Shift = IsPressed(0x10), b_Alt = IsPressed(0x12)
Local b_Caps = BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1)
Local name = RequestCopyDataInfo("SN")
Local file = RequestCopyDataInfo("SP") & name
If Not FileExist(file) Then
ShowHint("Файл не существует " & file)
Return
Endif
Local hMI = 0
Static sLib = "MediaInfo" & (auX64 ? "" : "_i386") & ".dll", _
hLib = DllCall("LoadLibrary", "wstr", COMMANDER_PATH & "\Ini\Tools\Libs" & sLib, "ptr")
Static sExt = ".aac .ac3 .aif .aiff .aifc .afc .ape .au .snd .cda .dsf .dts .dtswav .dtshd .dtsma .eac3 _
.flac .fla .m1a .m2a .mka .mpa .mp1 .mp2 .mp3 .mp4 .m4a .m4b .m4r .mod .mpc .mp+ .mpp _
.oga .ogx .ogg .ra .spx .opus .qoa .svx .8svx .tak .tta .wav .wave .w64 .bwf .rf64 .wma .wv _
.avi .wmv .wmp .wm .asf .mpg .mpeg .mpe .m1v .m2v .mpv2 .mp2v .ts .tp .tpr .trp .vob .ifo _
.ogm .ogv .mp4 .m4v .m4p .m4b .3gp .3gpp .3g2 .3gp2 .mkv .rm .ram .rmvb .rpm .flv .swf .mov _
.qt .amr .nsv .dpg .m2ts .m2t .mts .dvr-ms .k3g .skm .evo .nsr .amv .divx .webm .wtv .f4v .mxf"
If Not b_Alt Then
If hLib = 0 Then
ShowHint("Error LoadLibrary " & sLib)
Return
EndIf
hMI = DllCall(sLib & '\MediaInfo_New', "Ptr")
If hMI = 0 Then
ShowHint("MediaInfo.dll failed to create new object")
Return
Endif
Else
Local obj = Plugin("TCMediaInfo")
If ERROR <> 0 Then
ShowHint("TCMediaInfo.wdx plugin error " & ERROR)
Return
Endif
EndIf
Local s = 0
If Not StrPos(FileGetAttr(file), "D") Then
If b_Alt Then
obj.FileName = file
s = obj.GetValue(0) # duration
Free(obj)
Else
If DllCall(sLib & '\MediaInfo_Open', 'ptr', hMI, "wstr", file, "uint") <> 1 Then
Return ShowHint("MediaInfo.dll failed to open file " & file)
EndIf
s = DllCall(sLib & '\MediaInfo_Get', _
'ptr', hMI, "int", 0, "int", 0, "wstr", "Duration/String3", "int", 1, "int", 0, "wstr")
EndIf
Return ShowHint("Файл: " & name & auCRLF & "Длительность: " & s)
Endif
ShowHint("Загрузка")
MI_BREAK = false
MI_DURATION = 1
Local i, out, dirs = 0, files = 0, errs = 0, aFiles = List(), seconds = 0, b_Hint = 0
Local depth = (b_Ctrl ? 1 : 0)
b_Win = false
# загрузка файлов в массив
If b_Win Then
#ProcessExecGetOutput /OEM out %COMSPEC% "/c dir /s /b *.*" %"file"
#aFiles.Text = out
Else
ListDirectory(file, aFiles, depth)
EndIf
If aFiles.Count > 1 Then
ShowHint("Depth: " & depth & auCRLF & _
"CapsLock: " & (b_Caps ? "Yes" : "No") & auCRLF & _
(b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"Элементов: " & aFiles.Count & auCRLF & _
"Подсчёт времени...")
EndIf
For i = 0 To aFiles.Count - 1
#OutputDebugString("Duration:File:" & aFiles[i])
If StrPos(FileGetAttr(aFiles[i]), "D") Then
dirs += 1
If b_Shift Then OutputDebugString("Duration:Directory:" & aFiles[i])
Continue
EndIf
If b_Alt Then
obj.FileName = aFiles[i]
s = obj.GetValue(0,3) # duration -> milliseconds
Else
ext = FileGetExt(aFiles[i])
If Not b_Caps Then
If Not StrPos(sExt, '.' & ext) Then
If b_Shift Then OutputDebugString("Duration:Filter:" & aFiles[i])
Continue
EndIf
EndIf
If DllCall(sLib & '\MediaInfo_Open', 'ptr', hMI, "wstr", aFiles[i], "uint") <> 1 Then
errs += 1
If b_Shift Then OutputDebugString("Duration:Error:" & aFiles[i])
Continue
EndIf
s = DllCall(sLib & '\MediaInfo_Get', _
'ptr', hMI, "int", 0, "int", 0, "wstr", "Duration", "int", 1, "int", 0, "wstr")
EndIf
If s > 0 Then
seconds += s
files += 1
Else
If b_Shift Then OutputDebugString("Duration:Empty:" & aFiles[i])
EndIf
If MI_BREAK = true Or (IsPressed (0x11) And IsPressed (0x1B)) Then
ShowHint("Операция прервана")
Sleep(700)
Break
EndIf
If IsPressed(0x11) And IsPressed(0x12) Then
b_Hint += 1
If Round(GetUptime() - T2, 0) > 500 Then
ShowHint( _
(b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"CapsLock: " & (b_Caps ? "Yes" : "No") & auCRLF & _
"Depth: " & depth & auCRLF & _
"File: " & i & " of " & aFiles.Count _
)
T2 = GetUptime()
EndIf
Else
If b_Hint > 0 Then
b_Hint = 0
ShowHint("Depth: " & depth & auCRLF & _
"CapsLock: " & (b_Caps ? "Yes" : "No") & auCRLF & _
(b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"Элементов: " & aFiles.Count & auCRLF & _
"Подсчёт времени...")
EndIf
EndIf
Next
If b_Alt Then Free(obj)
If hMI <> 0 Then DllCall(sLib & '\MediaInfo_Delete', "Ptr", hMI)
MI_BREAK = false
MI_DURATION = 0
seconds = Floor(seconds / 1000)
Local day = Floor(seconds / 86400)
Local hour = Floor((seconds - (day * 86400)) / 3600)
Local min = Floor(((seconds - (day * 86400)) - (hour * 3600)) / 60)
Local sec = seconds - (day * 86400 + hour * 3600 + min * 60)
Local total = StrFormat("%02d:%02d:%02d:%02d",day,hour,min,sec)
ShowHint("Папка: " & name & auCRLF & _
"Каталогов: " & dirs & auCRLF & _
"Элементов: " & aFiles.Count & auCRLF & _
"Обработано: " & files & auCRLF & _
"Ошибки DLL: " & errs & auCRLF & _
"Секунд: " & seconds & auCRLF & _
"Минут: " & Round(seconds / 60, 2) & auCRLF & _
"Часов: " & Round(seconds / 3600, 2) & auCRLF & _
"Суток: " & Round(seconds / 86400, 2) & auCRLF & _
"Время: " & Chr(0x2211) & " "& total & auCRLF & _
"Powered by " & (b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"Время операции: " & Round(GetUptime() - T1, 3))
Free(aFiles)
EndFunc
Func ListDirectory(sPath, ByRef aList, nDepth = 1)
Local sFile, nAttr
Local ffd = Buffer(604)
Local hf = DllCall("FindFirstFileW", "wstr", sPath & "\*.*", "ptr", ffd.Ptr)
If hf <> 0 then
While True
sFile = ffd.GetStr(44) # cFileName
nAttr = ffd.GetNum(0, "dword") # dwFileAttributes
If BitAND(nAttr, 16) Then
If Not ((sFile = ".") Or (sFile = "..")) Then
aList.Add(sPath & "" & sFile)
If nDepth <> 1 Then
ListDirectory(sPath & "" & sFile, aList, nDepth - 1)
EndIf
EndIf
Else
aList.Add(sPath & "" & sFile)
Endif
If DllCall("FindNextFileW", "handle", hf, "ptr", ffd.Ptr) = 0 Then Break
Wend
DllCall("FindClose", "handle", hf)
Endif
Free(ffd)
EndFuncКопай, не копай. Раз тэги заполняют люди, все равно не угадаешь с заполненными полями. Собственно ведь поля тэгов для всех этих расширений одинаковы.Orion9 писал(а):придётся глубже копнуть в форматы файлов и их устройство
Дак это еще один язык программирования нестандартный. Получается язык Autorun надо изучить и язык TCMediaInfo. Для молодых и умных может и нет проблем. А у нас время ограничено. Не очень интересно этим заниматься.Orion9 писал(а):а не только в изучение настроек XML
MediaInfo.dll больше, чем просто тэги. Гораздо важнее техническая информация, которую дает эта библиотека. И если задача просто вывести некоторые поля из MediaInfo.dll, то, думаю, TCMediaInfo.wdx вполне для этого достаточно. А то, что там используется свой язык, так это только гибкости добавляет, на мой взгляд.AkulaBig писал(а):Собственно ведь поля тэгов для всех этих расширений одинаковы
Все, готов монитор. Очень простенький, конечно, но зато рабочий.
Отдельный модуль:
[cut="Monitor.aucfg"]
Код: Выделить всё
Global DIR_MONITOR1 = "D:\Temp\Test"
Global DIR_MONITOR2 = COMMANDER_PATH & "\Ini"
Global DIR_MONITOR3 = "\\Server\Share\Test"
RegisterCommand 81000 "DirMonitorCmd"
RegisterCommand 81001 "DirMonitorMenu"
Func DirMonitorCmd(lParam)
DirMonitor(DIR_MONITOR1, 0)
EndFunc
Func DirMonitor(FolderName, FolderDepth)
Local sLog, sChanges, sOps
# счётчик, лог, снимок, каталог
Static c = 0, sLogFile = TEMP & "\tc_dir_monitor.log", _
sMenuFile = TEMP & "\tc_dir_changes.log", _
sSnapFile = TEMP & "\tc_dir_snap.lst", sDir = FolderName
# список файлов и сохраненный список
Static aFiles = List(), aSnap = List()
# список новых и удаленных файлов
Static aNewFiles = List(), aDelFiles = List()
c += 1
# смена каталога в текущей сессии
If sDir <> FolderName Then
c = 1
sDir = FolderName
aSnap.Count = 0
aFiles.Count = 0
aNewFiles.Count = 0
aDelFiles.Count = 0
EndIf
# первый запуск монитора
If c = 1 Then
sLog &= auCRLF & auCRLF
sLog &= LogFormat(1, "Мониторинг каталога " & sDir)
If FileExist(sSnapFile) Then
sLog &= LogFormat(1, "Загрузка снимка " & sSnapFile)
aSnap.LoadFromFile(sSnapFile)
# проверка снимка
If aSnap.Count > 0 And Not StrPos(aSnap[0], sDir) Then
sLog &= LogFormat(1, "Снимок не содержит предыдущих записей")
aSnap.Count = 0
Endif
If aSnap.Count > 0 Then
sLog &= LogFormat(1, "Снимок загружен: " & aSnap.Count & " элементов")
EndIf
Else
sLog &= LogFormat(1, "Снимок не обнаружен")
EndIf
Endif
sLog &= LogFormat(1, "Проверка N " & c)
# каталог не доступен
If Not FileExist(sDir) Then
sLog &= LogFormat(1, "Каталог не доступен.")
Return
Endif
Local out
# загрузка файлов в массив
aFiles.Count = 0
ListDirectory(sDir, aFiles, FolderDepth)
sLog &= LogFormat(1, "Файлы взяты в массив: " & aFiles.Count & " элементов")
# каталог пустой
If aFiles.Count = 0 Or Not StrPos(aFiles[0], sDir) Then
sLog &= LogFormat(1, "Каталог не содержит записей.")
Endif
# обработка предыдущего списка
Local a = 0, d = 0
If aSnap.Count > 0 Then
For i = 0 To aSnap.Count - 1
If aFiles.IndexOf(aSnap[i]) = -1 Then
aDelFiles.Add(aSnap[i])
sLog &= LogFormat(1, "Файл удален " & aSnap[i])
d += 1
sChanges &= LogFormat(1, " [-] " & FileGetName(aSnap[i]))
sOps &= FileGetName(aSnap[i]) & auCRLF
EndIf
Next
For i = 0 To aFiles.Count - 1
If aSnap.IndexOf(aFiles[i]) = -1 Then
aNewFiles.Add(aFiles[i])
sLog &= LogFormat(1, "Файл добавлен " & aFiles[i])
a += 1
sChanges &= LogFormat(1, " [+] " & FileGetName(aFiles[i]))
sOps &= FileGetName(aFiles[i]) & auCRLF
EndIf
Next
EndIf
# новое состояние списка
aSnap = aFiles.Clone()
aSnap.SaveToFile(TEMP & "\tc_dir_snap.lst")
# фиксирование изменений
If a > 0 Or d > 0 Then
FileAppend(sMenuFile, sChanges)
Local sMsg
If d > 0 Then sMsg &= LogFormat(0, "Удалено: " & d)
If a > 0 Then sMsg &= LogFormat(0, "Добавлено: " & a)
sMsg &= sOps
sLog &= LogFormat(1, "Изменения в каталоге:")
sLog &= LogFormat(1, "Удалено: " & d)
sLog &= LogFormat(1, "Добавлено: " & a)
NotifyInfoMessage(0, sMsg, "Монитор каталога", NIIF_INFO)
Else
sLog &= LogFormat(1, "Нет изменений в каталоге")
Endif
FileAppend(sLogFile, sLog)
EndFunc
Func LogFormat(DateTime, LogText)
Local txt
Switch DateTime
Case 0
txt = StrFormat("%s\r\n", LogText)
Case 1
txt = StrFormat("%s %s %s\r\n", Date(), Time(), LogText)
Case 2
txt = StrFormat("%s %s\r\n", Date(), LogText)
Case 3
txt = StrFormat("%s %s\t%s\r\n", Date(), Time(), LogText)
Else
txt = StrFormat("%s %s\r\n", Time(), LogText)
EndSwitch
Return txt
EndFunc
#RunThread ThreadDirMonitor
Func ThreadDirMonitor()
While 1
#Sleep(180*60*1000)
Sleep(5000)
DirMonitor(DIR_MONITOR1, 0)
Wend
EndFunc
Func DirMonitorMenu(lParam)
ShowPopupMenu /D /F "CreateDirMonitorMenu"
EndFunc
Func CreateDirMonitorMenu()
Local txt, ops
Local buf = FileRead(TEMP & "\tc_dir_changes.log")
If buf <> "" Then
Local aLog = List(), i = 0, j, date = Date()
aLog.Text = buf
For j = aLog.Count - 1 To 0 Step -1
i += 1
ops &= 'MENUITEM "' & aLog[j] & '", ' & _
(StrPos(aLog[j], date) > 0 ? "em_dir_monitor_new" : "em_dir_monitor_old") & auCRLF
If i > 20 Then Break
Next
Free(aLog)
Else
ops = 'MENUITEM "Empty", 100000'
EndIf
txt = 'MENUITEM "Журнал монитора...", em_dir_monitor_log' & auCRLF & _
'MENUITEM "Журнал операций...", em_dir_monitor_ops' & auCRLF & _
'MENUITEM SEPARATOR' & auCRLF
txt &= ops & auCRLF
txt &= 'MENUITEM SEPARATOR' & auCRLF
txt &= 'MENUITEM "Перейти к файлу монитора...", em_dir_monitor_2log' & auCRLF
txt &= 'MENUITEM "Перейти к файлу операций...", em_dir_monitor_2ops' & auCRLF
Return txt
EndFuncДополнительные функции:
[cut="ListDirectory"]
Код: Выделить всё
Func ListDirectory(sPath, ByRef aList, nDepth = 1)
Local sFile, nAttr
Local ffd = Buffer(604)
Local hf = DllCall("FindFirstFileW", "wstr", sPath & "\*.*", "ptr", ffd.Ptr)
If hf <> 0 then
While True
sFile = ffd.GetStr(44) # cFileName
nAttr = ffd.GetNum(0, "dword") # dwFileAttributes
If BitAND(nAttr, 16) Then
If Not ((sFile = ".") Or (sFile = "..")) Then
aList.Add(sPath & "" & sFile)
If nDepth <> 1 Then
ListDirectory(sPath & "" & sFile, aList, nDepth - 1)
EndIf
EndIf
Else
aList.Add(sPath & "" & sFile)
Endif
If DllCall("FindNextFileW", "handle", hf, "ptr", ffd.Ptr) = 0 Then Break
Wend
DllCall("FindClose", "handle", hf)
Endif
Free(ffd)
EndFunc[cut="NotifyInfoMessage"]
Код: Выделить всё
# иконки окна уведомлений
Const NIIF_NONE = 0x00000000, _
NIIF_INFO = 0x00000001, _
NIIF_WARNING = 0x00000002, _
NIIF_ERROR = 0x00000003, _
NIIF_USER = 0x00000004
# без звука
Const NIIF_NOSOUND = 0x00000010
# большая иконка
Const NIIF_LARGE_ICON = 0x00000020
# сообщения окна уведомлений
Const NIN_BALLOONSHOW = 0x402, _
NIN_BALLOONHIDE = 0x403, _
NIN_BALLOONTIMEOUT = 0x404, _
NIN_BALLOONUSERCLICK = 0x405, _
NIN_POPUPOPEN = 0x406, _
NIN_POPUPCLOSE = 0x407
# флаги структуры
Const NIF_MESSAGE = 0x00000001, _
NIF_ICON = 0x00000002, _
NIF_TIP = 0x00000004, _
NIF_STATE = 0x00000008, _
NIF_INFO = 0x00000010
SetMessageAction /P 99998 TrayNotifyInfo
# служебная иконка
Func TrayNotifyInfo(hWnd, uMsg, wParam, lParam)
# освобождение невидимой иконки
If lParam = NIN_BALLOONUSERCLICK or lParam = NIN_BALLOONTIMEOUT Then
NotifyIcon("delete", 1010)
EndIf
EndFunc
Func NotifyInfoMessage(Icon, InfoText, InfoTitle = "Autorun", InfoType = 0)
Local dwFlags = 0
Local buf = Buffer(auPtrSize = 4 ? 956 : 976)
Local hIco = 0, tc = COMMANDER_PATH & "\TOTALCMD.EXE"
hIco = DllCall("shell32\ExtractIconW", "ptr", AUTORUN_TCHANDLE, "wstr", tc, "uint", 0, "ptr")
If Icon Then
dwFlags = BitOR(NIF_MESSAGE, NIF_ICON, NIF_INFO)
Else
dwFlags = BitOR(NIF_MESSAGE, NIF_STATE, NIF_ICON, NIF_INFO)
Endif
buf.Zero()
If auX64 Then
buf.SetNum(0, "dword", buf.size)
buf.SetNum(8, "hwnd", AUTORUN_TCHANDLE)
buf.SetNum(16, "uint", 1010, _
"uint", dwFlags, _
"uint", 99998)
buf.SetNum(32, "ptr", hIco)
buf.SetNum(296, "dword", 1, _
"dword", 1)
Else
buf.SetNum(0, "dword", buf.size, _
"hwnd", AUTORUN_TCHANDLE, _
"uint", 1010, _
"uint", dwFlags, _
"uint", 99998, _
"ptr", hIco) )
buf.SetNum(280, "dword", 1, _
"dword", 1)
EndIf
Local offset = (auX64 ? 40 : 24) + 256 + 4 + 4
buf.SetStr(StrLeft(InfoText, 199) & Chr(0), offset)
If StrLen(InfoTitle) > 0 Then
buf.SetStr(StrLeft(InfoTitle, 47) & Chr(0), offset + 512 + 4)
EndIf
If InfoType > 0 Then
buf.SetNum(offset + 512 + 4 + 128, "dword", InfoType)
EndIf
Local Result = DllCall("Shell32.dll\Shell_NotifyIconW", "uint", 0, "ptr", buf.ptr)
If hIco > 0 Then DllCall("DestroyIcon", "ptr", hIco)
Free(buf)
Return Result
EndFuncПоследняя функция используется для показа системных сообщений без отображения значка в трее, но за ней были замечены проблемы на Win8.1 и Win10. Лучше взять доработанный пример из справки от Loopback, у меня времени не хватило, чтобы вставить его в модуль.
Функция следит за удаленными и добавленными файлами и создает лог во временном каталоге. Также в %TEMP% создаются еще два файла, в которых хранится предыдущий снимок и журнал операций. Последний открывается в кнопке-меню по коду 81001. Чтобы украсить меню значками, используются em_ команды:
Код: Выделить всё
[em_dir_monitor_new]
button=%COMMANDER_PATH%\Ini\NewsBar\notify-yes.ico
[em_dir_monitor_old]
button=%COMMANDER_PATH%\Ini\NewsBar\notify-no.ico
[em_dir_monitor_log]
button=%COMMANDER_PATH%\Utilites\AkelPad\AkelPad.exe
cmd=%COMMANDER_PATH%\Utilites\AkelPad\AkelPad.exe
param=tc_dir_monitor.log
path=%TEMP%
[em_dir_monitor_ops]
button=%COMMANDER_PATH%\Utilites\AkelPad\AkelPad.exe
cmd=%COMMANDER_PATH%\Utilites\AkelPad\AkelPad.exe
param=tc_dir_changes.log
path=%TEMP%
[em_dir_monitor_2log]
button=%COMMANDER_EXE%,0
cmd=CD %TEMP%\tc_dir_monitor.log
[em_dir_monitor_2ops]
button=%COMMANDER_EXE%,0
cmd=CD %TEMP%\tc_dir_changes.logПростой способ запустить монитор в отдельном потоке:
Код: Выделить всё
RunThread ThreadDirMonitor
Func ThreadDirMonitor()
While 1
Sleep(180*60*1000)
DirMonitor(DIR_MONITOR1, 0)
Wend
EndFuncУ меня не было времени посмотреть, и сейчас тоже не могу, так как много разных дел появилось, но еще вернусь к этому позже.AkulaBig писал(а):Я выше написал. Там некоторые поля неправильно выводятся.
Обнаружил первый небольшой косячок, забыл добавить FileAppend(sLogFile, sLog) перед Return:
Код: Выделить всё
# каталог не доступен
If Not FileExist(sDir) Then
sLog &= LogFormat(1, "Каталог не доступен.")
FileAppend(sLogFile, sLog)
Return
EndifДоработал функцию подсчёта. Теперь может обрабатывать список выделенного, и ряд других улучшений:
[cut]TOTALCMD#BAR#DATA
62013
%COMMANDER_EXE%
Подсчёт времени воспроизведения|Alt - Использовать TCMediaInfo.wdx|Ctrl - Глубина каталога 1|Shift - Вывод информации в отладчик|CapsLock - Отключить фильтр расширений
-1
[/cut]
[cut][/cut]
Сделал заодно нечто подобное для торрент-файлов, но каталоги в глубину не обрабатываются, работает только с выделенными объектами на панели:
[cut]TOTALCMD#BAR#DATA
62014
%COMMANDER_EXE%
Подсчёт размера .torrent файлов
-1
[/cut]
[cut][/cut]
[cut]TOTALCMD#BAR#DATA
62013
%COMMANDER_EXE%
Подсчёт времени воспроизведения|Alt - Использовать TCMediaInfo.wdx|Ctrl - Глубина каталога 1|Shift - Вывод информации в отладчик|CapsLock - Отключить фильтр расширений
-1
[/cut]
[cut]
Код: Выделить всё
RegisterCommand 62013 "Duration"
Global MI_DURATION = 0, MI_BREAK = false
Func Duration(lParam)
If MI_DURATION > 0 Then
MI_BREAK = true
Sleep(250)
Return
EndIf
RunThread DurationInfo
EndFunc
Func DurationInfo()
Local T1 = GetUptime(), T2 = 0
Local b_Ctrl = IsPressed(0x11), b_Shift = IsPressed(0x10), b_Alt = IsPressed(0x12)
Local b_Caps = BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1)
Local hMI = 0
Static sLib = "MediaInfo" & (auX64 ? "" : "_i386") & ".dll", _
hLib = DllCall("LoadLibrary", "wstr", COMMANDER_PATH & "\Ini\Tools\Libs\" & sLib, "ptr")
Static sExt = ".aac .ac3 .aif .aiff .aifc .afc .ape .au .snd .cda .dsf .dts .dtswav .dtshd .dtsma .eac3 _
.flac .fla .m1a .m2a .mka .mpa .mp1 .mp2 .mp3 .mp4 .m4a .m4b .m4r .mod .mpc .mp+ .mpp _
.oga .ogx .ogg .ra .spx .opus .qoa .svx .8svx .tak .tta .wav .wave .w64 .bwf .rf64 .wma .wv _
.avi .wmv .wmp .wm .asf .mpg .mpeg .mpe .m1v .m2v .mpv2 .mp2v .ts .tp .tpr .trp .vob .ifo _
.ogm .ogv .mp4 .m4v .m4p .m4b .3gp .3gpp .3g2 .3gp2 .mkv .rm .ram .rmvb .rpm .flv .swf .mov _
.qt .amr .nsv .dpg .m2ts .m2t .mts .dvr-ms .k3g .skm .evo .nsr .amv .divx .webm .wtv .f4v .mxf"
If Not b_Alt Then
If hLib = 0 Then
ShowHint("Error LoadLibrary " & sLib)
Return
EndIf
hMI = DllCall(sLib & '\MediaInfo_New', "Ptr")
If hMI = 0 Then
ShowHint("MediaInfo.dll failed to create new object")
Return
Endif
Else
Local obj = Plugin("TCMediaInfo")
If ERROR <> 0 Then
ShowHint("TCMediaInfo.wdx plugin error " & ERROR)
Return
Endif
EndIf
Local s = 0
Local aSel = List()
aSel.Text = GetSelectedItems(3, 0)
Local sPath = RequestCopyDataInfo("SP")
Local sName = RequestCopyDataInfo("SN")
Local sFile = sPath & sName
If aSel.Count = 0 Then
If Not FileExist(sFile) Then
ShowHint("Файл не существует " & sFile)
Free(aSel)
Return
Endif
EndIf
If aSel.Count = 0 And Not StrPos(FileGetAttr(sFile), "D") Then
Free(aSel)
If b_Alt Then
obj.FileName = sFile
s = obj.GetValue(0) # duration
Free(obj)
Else
If DllCall(sLib & '\MediaInfo_Open', 'ptr', hMI, "wstr", sFile, "uint") <> 1 Then
Return ShowHint("MediaInfo.dll failed to open file " & sFile)
EndIf
s = DllCall(sLib & '\MediaInfo_Get', _
'ptr', hMI, "int", 0, "int", 0, "wstr", "Duration/String3", "int", 1, "int", 0, "wstr")
EndIf
Return ShowHint("Файл: " & sName & auCRLF & "Длительность: " & s)
Endif
ShowHint("Загрузка")
MI_BREAK = false
MI_DURATION = 1
Local i, j, k, dirs = 0, files = 0, errs = 0, item = 0, aFiles = List(), seconds = 0, b_Hint = 0
Local depth = (b_Ctrl ? 1 : 0)
b_Win = false
# загрузка файлов в массив
If aSel.Count > 0 Then
For j = 0 To aSel.Count - 1
sFile = sPath & aSel[j]
If FileExist(sFile) Then
k += 1
aFiles.Add(sFile)
If StrPos(FileGetAttr(sFile), "D") Then ListDirectory(sFile, aFiles, depth)
EndIf
Next
sName = "S/A: " & aSel.Count & "/" & k # Selected / Available
Else
aFiles.Add(sFile)
ListDirectory(sFile, aFiles, depth)
EndIf
Free(aSel)
If aFiles.Count > 1 Then
ShowHint("Depth: " & depth & auCRLF & _
"CapsLock: " & (b_Caps ? "Yes" : "No") & auCRLF & _
(b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"Элементов: " & aFiles.Count & auCRLF & _
"Подсчёт времени...")
EndIf
For i = 0 To aFiles.Count - 1
If b_Win Then OutputDebugString("Duration.File:" & aFiles[i])
If StrPos(FileGetAttr(aFiles[i]), "D") Then
dirs += 1
If b_Shift Then OutputDebugString("Duration.Directory:" & aFiles[i])
Continue
EndIf
item += 1
If b_Alt Then
obj.FileName = aFiles[i]
s = obj.GetValue(0,3) # duration -> milliseconds
Else
ext = FileGetExt(aFiles[i])
If Not b_Caps Then
If Not StrPos(sExt, '.' & ext) Then
If b_Shift Then OutputDebugString("Duration.Filter:" & aFiles[i])
Continue
EndIf
EndIf
If DllCall(sLib & '\MediaInfo_Open', 'ptr', hMI, "wstr", aFiles[i], "uint") <> 1 Then
errs += 1
If b_Shift Then OutputDebugString("Duration.Error:" & aFiles[i])
Continue
EndIf
s = DllCall(sLib & '\MediaInfo_Get', _
'ptr', hMI, "int", 0, "int", 0, "wstr", "Duration", "int", 1, "int", 0, "wstr")
EndIf
If s > 0 Then
seconds += s
files += 1
Else
If b_Shift Then OutputDebugString("Duration.Empty:" & aFiles[i])
EndIf
If MI_BREAK = true Or (IsPressed (0x11) And IsPressed (0x1B)) Then
ShowHint("Операция прервана")
Sleep(700)
Break
EndIf
If IsPressed(0x11) And IsPressed(0x12) Then
b_Hint += 1
If Round(GetUptime() - T2, 0) > 500 Then
ShowHint( _
(b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"CapsLock: " & (b_Caps ? "Yes" : "No") & auCRLF & _
"Depth: " & depth & auCRLF & _
"File: " & i & " of " & aFiles.Count _
)
T2 = GetUptime()
EndIf
Else
If b_Hint > 0 Then
b_Hint = 0
ShowHint("Depth: " & depth & auCRLF & _
"CapsLock: " & (b_Caps ? "Yes" : "No") & auCRLF & _
(b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"Элементов: " & aFiles.Count & auCRLF & _
"Подсчёт времени...")
EndIf
EndIf
Next
If b_Alt Then Free(obj)
If hMI <> 0 Then DllCall(sLib & '\MediaInfo_Delete', "Ptr", hMI)
MI_BREAK = false
MI_DURATION = 0
seconds = Floor(seconds / 1000)
Local day = Floor(seconds / 86400)
Local hour = Floor((seconds - (day * 86400)) / 3600)
Local min = Floor(((seconds - (day * 86400)) - (hour * 3600)) / 60)
Local sec = seconds - (day * 86400 + hour * 3600 + min * 60)
Local total = StrFormat("%02d:%02d:%02d:%02d",day,hour,min,sec)
Local tl = Round(GetUptime() - T1, 0) / 1000
ShowHint("Имя: " & sName & auCRLF & _
"Каталогов: " & dirs & auCRLF & _
"Элементов: " & aFiles.Count & auCRLF & _
"Обработано: " & files & " из " & item & auCRLF & _
"Ошибки DLL: " & errs & auCRLF & _
"Секунды: " & seconds & auCRLF & _
"Минуты: " & Round(seconds / 60, 2) & auCRLF & _
"Часы: " & Round(seconds / 3600, 2) & auCRLF & _
"Сутки: " & Round(seconds / 86400, 2) & auCRLF & _
"Время: " & Chr(0x2211) & " "& total & auCRLF & _
"Powered by " & (b_Alt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"Время операции: " & StrFormat("%.3f", tl) & " sec")
Free(aFiles)
EndFunc
Сделал заодно нечто подобное для торрент-файлов, но каталоги в глубину не обрабатываются, работает только с выделенными объектами на панели:
[cut]TOTALCMD#BAR#DATA
62014
%COMMANDER_EXE%
Подсчёт размера .torrent файлов
-1
[/cut]
[cut]
Код: Выделить всё
RegisterCommand 62014 "TorrentSize"
Func TorrentSize(lParam)
Local T1 = GetUptime()
Local obj = Plugin("TCTorrent")
If ERROR <> 0 Then
ShowHint("TCTorrent.wdx plugin error " & ERROR)
Return
Endif
Local size = 0, files = 0
Local aSel = List()
aSel.Text = GetSelectedItems(3, 0)
Local sPath = RequestCopyDataInfo("SP")
Local sName = RequestCopyDataInfo("SN")
Local sFile = sPath & sName
Local lRet = false
If aSel.Count = 0 Then
If Not FileExist(sFile) Then
ShowHint("Файл не существует " & sFile)
lRet = true
ElseIf StrPos(FileGetAttr(sFile), "D") Then
ShowHint("Каталог " & sFile)
lRet = true
Else
obj.FileName = sFile
files = obj.GetValue(1)
size = obj.GetValue(2,0) # size -> bytes
Free(obj)
Endif
EndIf
If lRet Then
Free(obj, aSel)
Return
EndIf
If aSel.Count > 10 Then
ShowHint("Выделено: " & aSel.Count & auCRLF & "Подсчёт времени...")
EndIf
Local j, k = 0, dirs = 0, torrs = 0
If aSel.Count > 0 Then
For j = 0 To aSel.Count - 1
sFile = sPath & aSel[j]
If FileExist(sFile) Then
k += 1
If Not StrPos(FileGetAttr(sFile), "D") Then
obj.FileName = sFile
s = obj.GetValue(2,0)
If s > 0 Then
size += s
files += obj.GetValue(1)
torrs += 1
Endif
Else
dirs += 1
Endif
EndIf
Next
sName = "S/A: " & aSel.Count & "/" & k # Selected / Available
Else
Return ShowHint("" & sName & auCRLF & _
"Размер: " & SizeFormat(size, 1, 'G', 2, 1) & auCRLF & _
"Файлов: " & files)
EndIf
Local tl = Round(GetUptime() - T1, 0) / 1000
ShowHint((k = aSel.Count ? "" : "Файл " & sName & auCRLF) & _
"Элементов: " & aSel.Count & auCRLF & _
"Обработано: " & torrs & auCRLF & _
"Каталогов: " & dirs & auCRLF & _
"Размер: " & SizeFormat(size, 0, 'M', 2) & auCRLF & _
"Размер: " & SizeFormat(size, 0, 'G', 2) & auCRLF & _
"Размер: " & SizeFormat(size, 0, 'T', 4) & auCRLF & _
"Файлов: " & files & auCRLF & _
"Powered by TCTorrent.wdx" & auCRLF & _
"Время операции: " & StrFormat("%.3f", tl) & " sec")
Free(obj, aSel)
EndFuncПоправка: не 16, а скорее 32. Но DllCall как всегда выручает. По мотивам статьи:ClipGet принимает максимум 16 Кб
Код: Выделить всё
Local hCB, pMem, obg, CF_UNICODETEXT = 13
If DllCall("OpenClipboard", "handle", 0) Then
hCB = DllCall("GetClipboardData", "uint", CF_UNICODETEXT, "handle")
pMem = DllCall("GlobalLock", "handle", hCB, "ptr")
obj = Buffer(1024*500, pMem)
txt = obj.GetStr()
Free(obj)
DllCall("GlobalUnlock ", "handle", hCB)
DllCall("CloseClipboard")
Else
MsgBox("Clipboard Error" )
EndIfOrion9
Проблема та же, что была в ProcessExecGetOutput. Доработаю, механизм уже есть. И надо будет проверить, в каких еще функциях может появиться текст большого размера на выходе. Навскидку это только GetWMIValue/WMIQuery.
Проблема та же, что была в ProcessExecGetOutput. Доработаю, механизм уже есть. И надо будет проверить, в каких еще функциях может появиться текст большого размера на выходе. Навскидку это только GetWMIValue/WMIQuery.
Да, она уже выделена GetClipboardData. Если вторым параметром указан адрес, то размер это просто границы диапазона. Для теста ок, но по-хорошему этот размер надо получать c помощью GlobalSize.Orion9 писал(а): что это просто "окно" для чтения, а на самом деле память не выделяется?
Вот же, а... Случайно отредактировал предыдущий пост, вместо отправки нового.
Loopback, там было про проблему с функцией ClipGet, которая режет текст из буфера. Используя DllCall удалось обойти это ограничение:
Но в приведенном коде используется другое ограничение буфера размером в 500 Кб. Правильно я понимаю, что это просто "окно" для чтения из памяти, на самом деле память в таких случаях не выделяется? А как вообще правильно сделать, ведь объем текстовых данных в буфере может быть ещё больше?
Короче, вдохновившись новым лозунгом Autorun "Пока Гислер думает, Autorun делает", соорудил небольшую функцию:
[cut]TOTALCMD#BAR#DATA
62015
%COMMANDER_EXE%
Подсчёт колонок|Ctrl - Запуск потока|Ctrl + ESC - Отмена
-1
[/cut]
[cut][/cut]
Функция еще сырая и абсолютно тестовая, но, кажется, делает то, что от неё требуется. Запуск с CTRL удобен на небольших списках, когда выделенных позиций меньше 100 или где-то около 100, тогда данные обновляются в подсказке в реальном времени. Но чем больше выделено, тем больше тормозов, поэтому на больших списках лучше пользоваться одиночным кликом, так надежнее. Но надо будет с этим что-то придумать.
Добавлено спустя 6 минут:
Ну, что-то у меня совсем не заладилось )
Кстати, были кое-какие проблемы с объектом List. Пока не инициализировал принудительно:
Были какие-то глюки и непонятные результаты.
Loopback, там было про проблему с функцией ClipGet, которая режет текст из буфера. Используя DllCall удалось обойти это ограничение:
Код: Выделить всё
Local hCB, pMem, obg, CF_UNICODETEXT = 13
If DllCall("OpenClipboard", "handle", 0) Then
hCB = DllCall("GetClipboardData", "uint", CF_UNICODETEXT, "handle")
pMem = DllCall("GlobalLock", "handle", hCB, "ptr")
obj = Buffer(1024*500, pMem)
txt = obj.GetStr()
Free(obj)
DllCall("GlobalUnlock ", "handle", hCB)
DllCall("CloseClipboard")
Else
MsgBox("Clipboard Error" )
EndIfКороче, вдохновившись новым лозунгом Autorun "Пока Гислер думает, Autorun делает", соорудил небольшую функцию:
[cut]TOTALCMD#BAR#DATA
62015
%COMMANDER_EXE%
Подсчёт колонок|Ctrl - Запуск потока|Ctrl + ESC - Отмена
-1
[/cut]
[cut]
Код: Выделить всё
RegisterCommand 62015 "Summarize"
Global SUM_THREAD = 0, SUM_MX = 0, SUM_MY = 0
Func Summarize(lParam)
If SUM_THREAD > 0 Then
SUM_THREAD = 0
Sleep(250)
Return
EndIf
If Not IsPressed(0x11) Then
MouseGetPos("SUM_MX", "SUM_MY")
SumUpColumns(1)
Return
EndIf
# CTRL запуск потока
RunThread ThreadSumCustomView
EndFunc
Func ThreadSumCustomView()
Local i
SUM_THREAD = 1
MouseGetPos("SUM_MX", "SUM_MY")
While SUM_THREAD > 0
SumUpColumns(0)
For i = 1 To 10
If SUM_THREAD = 0 Or (IsPressed (0x11) And IsPressed (0x1B)) Then
SUM_THREAD = 0
ShowHint("Операция прервана")
Break
EndIf
Sleep(50)
Next
Wend
SUM_THREAD = 0
EndFunc
Func SumUpColumns(lWait = 0)
Local txt, i, j, T1 = GetUptime()
#If GetSelectedItems(3, 0) = '' And GetCurrentItem(3, 2) = 0 Then
If GetCurrentItem(3, 2) = 0 Then
ShowHint("Index = 0", SUM_MX, SUM_MY, 1000, 1)
Sleep(500)
Return
EndIf
ShowHint("Clipboard Waiting", SUM_MX, SUM_MY, (lWait ? "" : 1000), (lWait ? "" : 1))
Local bReady = false, sMsg
Local aSel = List(), aCol = List(), aVal = List(), aRow = List()
aSel.Count = 0
aCol.Count = 0
aVal.Count = 0
aRow.Count = 0
SendCommand(2090, 0, 1) # cm_CopyHdrFileDetailsToClip
#Sleep(100)
#txt = ClipGet()
Local hCB, pMem, obg, CF_UNICODETEXT = 13
If DllCall("OpenClipboard", "handle", 0) Then
hCB = DllCall("GetClipboardData", "uint", CF_UNICODETEXT, "handle")
pMem = DllCall("GlobalLock", "handle", hCB, "ptr")
obj = Buffer(1024*500, pMem)
txt = obj.GetStr()
Free(obj)
DllCall("GlobalUnlock ", "handle", hCB)
DllCall("CloseClipboard")
Else
sMsg = "Clipboard Error"
EndIf
If StrLen(txt) > 0 Then
bReady = true
aSel.Text = txt
EndIf
If StrPos(aSel[0], auTAB) = 0 Then
bReady = false
sMsg = "Clipboard Data Incorrect"
Endif
#FileWrite(TEMP & "\temp.tmp", txt)
#MsgBox("hCB: " & hCB & auCRLF & "Len: " & StrLen(txt) & auCRLF & "txt")
#Return
If Not bReady Then
If lWait Then
ShowHint(sMsg, SUM_MX, SUM_MY)
Else
ShowHint(sMsg, SUM_MX, SUM_MY, 1000, 1)
Endif
Free(aSel, aCol, aRow, aVal)
Return
Endif
aCol.Split(aSel[0], auTAB)
aVal.Count = aCol.Count
For j = 0 To aVal.Count - 1
aVal[j] = ""
Next
txt = ""
For j = 1 To aSel.Count - 1
aRow.Split(aSel[j], auTAB)
For i = 0 To aRow.Count - 1
If StrPos(aRow[i], Chr(160)) Then
aRow[i] = StrReplace(aRow[i], Chr(160), "")
EndIf
If IsNumber(aRow[i]) Then aVal[i] += aRow[i]
Next
Next
For j = 0 To aCol.Count - 1
txt &= aCol[j] & ": " & aVal[j] & auCRLF
Next
Local TL = Round(GetUptime() - T1, 0) / 1000
txt &= "---" & auCRLF & _
"Selected: " & aSel.Count - 1 & auCRLF & _
"Powered by Autorun.wdx" & auCRLF & _
"Время операции: " & StrFormat("%.3f", TL) & " sec"
Free(aSel, aCol, aRow, aVal)
If lWait Then
ShowHint(StrTrim(txt), SUM_MX, SUM_MY)
Else
ShowHint(StrTrim(txt), SUM_MX, SUM_MY, 1000, 1)
Endif
EndFuncФункция еще сырая и абсолютно тестовая, но, кажется, делает то, что от неё требуется. Запуск с CTRL удобен на небольших списках, когда выделенных позиций меньше 100 или где-то около 100, тогда данные обновляются в подсказке в реальном времени. Но чем больше выделено, тем больше тормозов, поэтому на больших списках лучше пользоваться одиночным кликом, так надежнее. Но надо будет с этим что-то придумать.
Добавлено спустя 6 минут:
Ну, что-то у меня совсем не заладилось )
Не знаю, успею ли глянуть. А можно пример? Вопрос тот же: ак вообще правильно сделать, ведь объем текстовых данных в буфере может быть ещё больше?по-хорошему этот размер надо получать c помощью GlobalSize.
Кстати, были кое-какие проблемы с объектом List. Пока не инициализировал принудительно:
Код: Выделить всё
aSel.Count = 0
aCol.Count = 0
aVal.Count = 0
aRow.Count = 0
Я утром успел прочитать, просто не было возможности ответить. Мой ответ выше - первая часть про ClipGet, вторая про вашу функцию.Orion9 писал(а):Случайно отредактировал предыдущий пост, вместо отправки нового.
Примерно так (не тестировал):Orion9 писал(а): А как вообще правильно сделать, ведь объем текстовых данных в буфере может быть ещё больше?
Код: Выделить всё
pMem = DllCall("GlobalLock", "handle", hCB, "ptr")
size = DllCall("GlobalSize", "handle", hCB, "uint_ptr")
obj = Buffer(size, pMem)
Какие именно? Нужна все же какая-то конкретика.Orion9 писал(а):Кстати, были кое-какие проблемы с объектом List.