Orion9

|
Posted: Fri May 16, 2025 00:32 Post subject: |
|
|
AkulaBig wrote: | Собственно ведь поля тэгов для всех этих расширений одинаковы |
MediaInfo.dll больше, чем просто тэги. Гораздо важнее техническая информация, которую дает эта библиотека. И если задача просто вывести некоторые поля из MediaInfo.dll, то, думаю, TCMediaInfo.wdx вполне для этого достаточно. А то, что там используется свой язык, так это только гибкости добавляет, на мой взгляд.
Все, готов монитор. Очень простенький, конечно, но зато рабочий.
Отдельный модуль:
 Monitor.aucfg Code: | 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 |
Дополнительные функции:
 ListDirectory Code: | 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 |
 NotifyInfoMessage Code: | # иконки окна уведомлений
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_ команды:
Code: | [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 |
Простой способ запустить монитор в отдельном потоке:
Code: | RunThread ThreadDirMonitor
Func ThreadDirMonitor()
While 1
Sleep(180*60*1000)
DirMonitor(DIR_MONITOR1, 0)
Wend
EndFunc |
Раз в полчаса каталог DIR_MONITOR1 будет проверяться и изменения будут логироваться в файлы, сообщения об изменениях будут отображаться в системных уведомлениях. |
|