| View previous topic :: View next topic |
| Author |
Message |
FallenAngel
Joined: 30 Dec 2025 Posts: 25
|
(Separately) Posted: Fri Feb 06, 2026 13:12 Post subject: |
|
|
Orion9
TCFS2, точно, спасибо.
Про CompareTool расскажу что хочу. Решение пока не могу придумать. Идея, условно:
if exist WinMergeU.exe then (выполняем как обычно CompareTool=WinMergeU.exe) else (предлагаем скачать перекинув на условный BAT-ник). |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1024
|
(Separately) Posted: Fri Feb 06, 2026 19:13 Post subject: |
|
|
FallenAngel
А что тут думать? Нужно брать и делать, как вы написали )
Сначала считать ключ CompareTool и проверить путь в его значении: если путь существует, то выполнить cm_CompareFilesByContent, если не существует, то вывести MsgBox с вопросом, нужно ли скачивать WinMerge.
Опционально можно добавить возможность сравнения внутренним инструментом, если пользователь откажется от скачивания.
Небольшой пример:
| Code: | RegisterCommand 60050 "CompareTwoFiles"
Func CompareTwoFiles()
Local sTool
# чтение ключа
sTool = IniRead("~/R", COMMANDER_INI, "Configuration", "CompareTool", 0)
# раскрытие переменных окружения в значении ключа, если они есть
sTool = Set(sTool)
# проверка существования файла
If FileExist(sTool) Then
# файл существует
# послать команду сравнения и выйти
SendCommand(2022) # cm_CompareFilesByContent
Return
EndIf
# файл не существует
MsgBox("Инструмент сравнения не найден " & sTool & auCRLF & auCRLF & _
"Загрузить из Интернета?", "Autorun", 3+0+48)
# кнопка "Да" не была нажата, выйти из скрипта
If EXTENDED <> 6 Then Return
# запуск батника для загрузки
ShellExec(COMMANDER_PATH & "\Scripts\WinMergedownload.bat")
EndFunc |
Как у вас со скриптингом, можете дальше развить этот пример, а то я через неделю только освобожусь.
Кстати, вместо батника можно использовать функцию WinInetDownloadFile для загрузки файла прямо из Autorun
| Code: | Local url = "https://downloads.sourceforge.net/winmerge/winmerge-2.16.54-x64-exe.zip"
WinInetDownloadFile(url, TEMP & "\winmerge.zip") |
WinMerge загрузится во временный каталог в архиве winmerge.zip. Останется распаковать этот архив в нужное место и сообщить пользователю об окончании операции. |
|
| Back to top |
|
 |
FallenAngel
Joined: 30 Dec 2025 Posts: 25
|
(Separately) Posted: Sun Feb 08, 2026 11:03 Post subject: |
|
|
Orion9
Спасибо, работает отлично. Единственное, т.к. сейчас Нет и Отмена делают одно и тоже, то лучше чтобы Нет открывал внутренний инструмент.
| Orion9 wrote: |
Как у вас со скриптингом |
На bat\ps1 я неплохо пишу. Это не проблема.
| Orion9 wrote: |
Что касается Листера, если задача стоит добиться, чтобы его окно при открытии имело тот же размер и положение |
Может тогда лучше упростить? Просто повесить хоткей: нажал - и листер стал размером с окно ТС.
| Quote: | | Добавил переменную gTitleRound для указания количества знаков после точки у сетевого трафика. |
Может тогда и InfoHeader.aucfg обновите с учетом этой новинки? |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1024
|
(Separately) Posted: Sun Feb 08, 2026 14:09 Post subject: |
|
|
FallenAngel
Если у вас со скриптами PowerShell получается работать, то уверен, что и с Autorun получится. Вопрос времени.
Чтобы добавить действие на кнопку "Нет", нужно обработать код с номером 7 в макросе EXTENDED. Из справки Autorun на функцию MsgBox:
| Code: | После закрытия диалога сообщения функция присвоит макросу EXTENDED числовой код, идентифицирующий нажатую кнопку:
1 «OK»
2 «Отмена»
3 «Прервать»
4 «Повтор»
5 «Пропустить»
6 «Да»
7 «Нет»
10 «Повторить»
11 «Продолжить»
Возможные сценарии при нажатии клавиши ESC:
Если есть кнопка «Отмена», функция присвоит 2 макросу EXTENDED.
Если нет кнопок «Отмена» и «OK», никакого эффекта не будет.
Если нет кнопки «Отмена», но есть «OK», функция присвоит 1 макросу EXTENDED.
Функция не всегда работает на 64-битной версии Total Commander. |
Т.е. нужно добавить:
| Code: | # кнопка "Нет"
If EXTENDED = 7 Then SendCommand(2040) #cm_IntCompareFilesByContent
# кнопка "Да" не была нажата, выйти из скрипта
If EXTENDED <> 6 Then Return |
Кстати, для этой задачи хорошо может подойти MsgBoxLinks, вместо стандартного MsgBox. Но там код чуть сложнее, пока не могу его написать и протестировать. Позднее попробую.
| Quote: | | Может тогда лучше упростить? Просто повесить хоткей: нажал - и листер стал размером с окно ТС. |
Можно так сделать. Нужно зарегистрировать отдельный код на функцию SyncListerPosition и создать для него em_команду или сразу повесить функцию на хоткей.
| Code: | RegisterCommand 60051 "SyncListerPosition"
# Alt + "["
SetHotkeyAction /K:A /V:219 SyncListerPosition
Func SyncListerPosition()
Static c = 0
If IniRead("~/R", COMMANDER_INI, "Lister", "Maximized", 0) = 0 Then
WinGetPos("x", "y", "w", "h")
IniWrite("~/R", COMMANDER_INI, "Lister", "x", x)
IniWrite("~/R", COMMANDER_INI, "Lister", "y", y)
IniWrite("~/R", COMMANDER_INI, "Lister", "dx", w)
IniWrite("~/R", COMMANDER_INI, "Lister", "dy", h)
c += 4
#ShowHint("Запись ключей: " & c, SYSINFO_DESKTOPWIDTH/2-50, SYSINFO_DESKTOPHEIGHT/2, 1000, 1)
EndIf
EndFunc
|
Посмотрите в справочнике SetHotkeyAction.
| Quote: | | Может тогда и InfoHeader.aucfg обновите с учетом этой новинки? |
Так он уже обновлен в последней версии на предыдущей странице, пропустили?  |
|
| Back to top |
|
 |
FallenAngel
Joined: 30 Dec 2025 Posts: 25
|
(Separately) Posted: Sun Feb 08, 2026 20:32 Post subject: |
|
|
Наверное, нужно обнулять, т.к. сейчас КАЖДЫЙ раз +4
| Orion9 wrote: | Так он уже обновлен в последней версии на предыдущей странице, пропустили?  |
Там он вместе с погодой (ну или я не туда смотрю). Речь про оригинал по моей ссылке в 68 строк. |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1024
|
(Separately) Posted: Mon Feb 09, 2026 00:33 Post subject: |
|
|
FallenAngel
c += 4 не обнуляется, потому что цель была увидеть общее количество записей в ини-файл. Подключите последний модуль, захватите окно за заголовок и поводите им по экрану — количество записей быстро перевалит за сотни. Я боялся, что будет еще больше. Хотя в принципе все это не страшно.
| Quote: | | Там он вместе с погодой (ну или я не туда смотрю). |
Так вы и хотели вроде с погодой, даже ссылку давали на github Но если хотите совсем уж легковесный заголовок, то переменную для окруления десятичных можно и не вводить. Сразу лучше в строку вывода внести изменения:
| Code: | gInfoHeader = gTitle & ' ' & Date("d MMMM, ddd") & '. CPU: ' & StrFormat("%02d", GetCPUUsage()) & '% RAM: ' & GetMemStats() & '% NET: ↓ ' & Round(nRecvSpeed / 1000, 2) & ' ↑ ' & Round(nSendSpeed / 1000, 2) & ' mb/s' |
Т.е. вместо 1 теперь 2. Так реально лучше смотрится, на мой взгляд. |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1024
|
(Separately) Posted: Mon Feb 09, 2026 12:17 Post subject: |
|
|
FallenAngel
Вчера спешил, не подумал, что окно листера надо искать. Должно быть примерно так:
| Code: | SetHotkeyAction /K:C /H:0 /DM /S "AlignListerWindow"
Func AlignListerWindow()
If IniRead("~/R", COMMANDER_INI, "Lister", "Maximized", 0) = 0 Then
WinGetPos("x", "y", "w", "h")
IniWrite("~/R", COMMANDER_INI, "Lister", "x", x)
IniWrite("~/R", COMMANDER_INI, "Lister", "y", y)
IniWrite("~/R", COMMANDER_INI, "Lister", "dx", w)
IniWrite("~/R", COMMANDER_INI, "Lister", "dy", h)
Local hWnd = WinFind(0, "TLister")
If hWnd = 0 Then Return ShowHint("Окно листера не найдено")
WinSetPos(x, y, w, h, "", hWnd)
EndIf
EndFunc |
CTRL+0 подстраивает окно листера под позицию окна тотала при условии, что окно листера не развернуто во весь экран. Так вы хотели? |
|
| Back to top |
|
 |
FallenAngel
Joined: 30 Dec 2025 Posts: 25
|
(Separately) Posted: Mon Feb 09, 2026 12:31 Post subject: |
|
|
| Orion9 wrote: |
Т.е. вместо 1 теперь 2. Так реально лучше смотрится, на мой взгляд. |
Хм... не уверен что лучше. Нужно подумать. Но вот навеяло другую идея походу: почему "в спокойствии" у нас "0" ? По идеи должно быть "0.0".
| Orion9 wrote: |
If hWnd = 0 Then Return ShowHint("Окно листера не найдено")
|
Это строка тут лишняя, ИМХО.
Да, круто что окно Листера теперь сразу подстраивается, единственное, теряет фокус (возможно, нужно просто передать его обратно). |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1024
|
(Separately) Posted: Mon Feb 09, 2026 13:27 Post subject: |
|
|
FallenAngel
Нужно просто отформатировать строку через StrFormat. Т.е. вместо:
| Code: | Round(nRecvSpeed / 1000, 2) & ' ↑ ' & Round(nSendSpeed / 1000, 2) & ' mb/s' |
Должно быть:
| Code: | StrFormat("%02.2f", Round(nRecvSpeed / 1000, 2)) & ' ↑ ' & StrFormat("%02.2f", Round(nSendSpeed / 1000, 2)) & ' mb/s' |
Может вам так больше понравится.
| Quote: | | Это строка тут лишняя, ИМХО. |
Ну если лишняя, можно убрать )
А что на счет фокуса? У меня он не теряется. Но если у вас теряется, можно принудительно его вернуть через WinSetState:
| Code: | WinSetPos(x, y, w, h, "", hWnd)
WinSetState(23, hWnd) |
А вот и линксы, как обещал:
 Hidden text | Code: | RegisterCommand 60043 "CompareTwoFiles"
RegisterCommand 60044 "CompareTwoFilesDialog"
Func CompareTwoFiles()
Local sTool, nDialogMode = 1
# чтение ключа
sTool = IniRead("~/R", COMMANDER_INI, "Configuration", "CompareTool", "")
# раскрытие переменных окружения
sTool = Set(sTool)
# проверка существования файла
If FileExist(sTool) Then
# файл существует
# послать команду сравнения и выйти
SendCommand(2022) # cm_CompareFilesByContent
Return
EndIf
If nDialogMode = 1 Then Return CompareTwoFilesDialog(sTool)
# файл не существует
MsgBox("Инструмент сравнения не найден " & sTool & auCRLF & auCRLF & _
"Загрузить из Интернета?", "Autorun", 3+0+48)
# нажата кнопка "Нет"
If EXTENDED = 7 Then SendCommand(2040) # cm_IntCompareFilesByContent
# не нажата кнопка "Да", выйти из скрипта
If EXTENDED <> 6 Then Return
# запуск батника для загрузки
ShellExec(COMMANDER_PATH & "\Scripts\WinMergeDownload.bat")
EndFunc
Func CompareTwoFilesDialog(FilePath)
Local lst = List()
lst.Add("Сравнить внутренним" & auLF & "Будет использован внутренний инструмент сравнения Total Commander")
lst.Add("Загрузить из интернета" & auLF & "https://winmerge.org/downloads/?lang=ru")
Local nRet = MsgBoxLinks(1, "Инструмент сравнения не найден", FilePath, lst)
Free(lst)
If nRet = 2 Then Return
If nRet = 1001 Then
SendCommand(2040) # cm_IntCompareFilesByContent
Else
ShellExec(COMMANDER_PATH & "\Scripts\WinMergeDownload.bat")
EndIf
EndFunc
#{
Icon:
1 - Warning
2 - Error
3 - Information
4 - Shield
ByRef: List() of 1-3 elements
Returns: 1001-1003, 2 for cancel
#}
Func MsgBoxLinks(Icon, Header, Message, ByRef Links)
If Abs(Icon) > 4 Then Icon = 2
Icon = 65536 - Icon
If Links.Count = 0 Then Return MsgBox("Links not specified")
Local Res, Ret
Local buf = Buffer(auX64 ? 160 : 96), _
ttl = Buffer(16), _
hdr = Buffer(StrLen(Header)*2+2), _
msg = Buffer(StrLen(Message)*2+2), _
lnk = Buffer(auX64 ? 48 : 24)
ttl.SetStr("Autorun" & Chr(0))
hdr.SetStr(Header & Chr(0))
msg.SetStr(Message & Chr(0))
Local b1 = Buffer(512), b2 = Buffer(512), b3 = Buffer(512)
b1.Zero()
b2.Zero()
b3.Zero()
b1.SetStr(Links[0] & Chr(0))
If Links.Count > 1 Then b2.SetStr(Links[1] & Chr(0))
If Links.Count > 2 Then b3.SetStr(Links[2] & Chr(0))
lnk.Zero()
lnk.SetNum(0, "int", 1001, _
"ptr", b1.ptr, _
"int", 1002, _
"ptr", b2.ptr, _
"int", 1003, _
"ptr", b3.ptr)
buf.Zero()
buf.SetNum(0, "uint", buf.size, _
"hwnd", AUTORUN_TCHANDLE, _
"handle", 0, _
"dword", 0x0019, _
"dword", 0x0008, _
"ptr", ttl.ptr, _
"ptr", Icon, _
"ptr", hdr.ptr, _
"ptr", msg.ptr, _
"uint", Links.Count, _
"ptr", lnk.ptr)
Res = DllCall("TaskDialogIndirect", _
"ptr", buf.ptr, _
"int*", @Ret, _
"int*", 0, _
"bool*", 0, "hresult")
Free(buf, ttl, hdr, msg, lnk, b1, b2, b3)
Return Ret
EndFunc |
Ну не персик ли?
 PS Если персик не нужен, можно изменить nDialogMode = 1 на любое значение |
|
| Back to top |
|
 |
FallenAngel
Joined: 30 Dec 2025 Posts: 25
|
(Separately) Posted: Mon Feb 09, 2026 15:18 Post subject: |
|
|
| Orion9 wrote: |
Может вам так больше понравится. |
Пока так тестирую:
| Code: | StrFormat("%02.1f", Round(nRecvSpeed / 1000, 1)) & ' ↑ ' & StrFormat("%02.1f", Round(nSendSpeed / 1000, 1)) & ' mb/s' |
| Code: | WinSetState(23, hWnd) |
Да, так все ОК. |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1024
|
(Separately) Posted: Tue Feb 10, 2026 13:54 Post subject: |
|
|
Прошелся тут по последним страницам. Удивительно, ссылки на 11,000 сохранилась, а ссылка на 13К не доступна. Непорядок творится в королевстве. Перезаливка.
https://www.upload.ee/files/19062762/TC.11.56.7z.html
 Warning Сайт находится в 16-20 Кб блоке. С территории России без средств обхода скачать архив не получится. Адрес площадки пока не меняю, вдруг блокировку еще снимут.
Обновил модуль Icons.aucfg.
 Hidden text | Code: | Pragma IncludeOnce
# 64000-65000
Global TrayShow = 0, TrayLog = List()
Global Tray1001 = 0, Tray1002 = 0, Tray1003 = 0, Tray1010 = 0
Global gNotifyIcon = COMMANDER_EXE
#Global gNotifyIcon = COMMANDER_PATH & "\Ini\Newsbar\notify-yes.ico"
# регистрация уникальных кодов
Global Code1003 = DllCall("RegisterWindowMessageW", "wstr", "TrayNotify1003", "uint")
Global Code1010 = DllCall("RegisterWindowMessageW", "wstr", "TrayNotify1010", "uint")
# коды кнопок
RegisterCommand 64000 "ToggleTrayIcon"
RegisterCommand 64001 "ChangeTrayIcon"
RegisterCommand 64002 "NotifyInfo"
RegisterCommand 64003 "RotateIcon"
# функции обратного вызова
SetMessageAction /P 99999 "AutorunTrayAction"
SetMessageAction /P %"Code1003" "MinTrayAction"
SetMessageAction /P %"Code1010" "TrayNotifyInfo"
# сворачивание в трей
ControlSetMouseAction /K:C /L /H:8 0 "MinimizeToTray"
# иконки окна уведомлений
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
# системные сообщения
Const WM_MOUSEMOVE = 0x0200, _
WM_LBUTTONDOWN = 0x0201, _
WM_LBUTTONUP = 0x0202, _
WM_LBUTTONDBLCLK = 0x0203, _
WM_RBUTTONDOWN = 0x0204, _
WM_RBUTTONUP = 0x0205, _
WM_RBUTTONDBLCLK = 0x0206, _
WM_MBUTTONDOWN = 0x0207, _
WM_MBUTTONUP = 0x0208, _
WM_MBUTTONDBLCLK = 0x0209
# старт
TrayIcon()
# главная иконка
Func TrayIcon()
Local ico, idx = 0
# чтение конфигурации
IniRead TrayShow %AUTORUN_INI% "TrayIcon" "Show" 1
If Not TrayShow Then
Return
EndIf
IniRead ico %AUTORUN_INI% "TrayIcon" "Icon"
IniRead idx %AUTORUN_INI% "TrayIcon" "Index" 0
# раскрытие переменной окружения
ico = Set(ico)
# откат к умолчаниям
If ico = "" Or Not FileExist(ico) Then
idx = 0
ico = COMMANDER_EXE
EndIf
Local sHint = "Autorun " & FileGetVersion(AUTORUN_PATH & "\Autorun.wdx", "FileVersion")
If auX64 Then sHint &= " x64"
# дескриптор иконки
Local hIco = DllCall("shell32\ExtractIconW", _
"ptr", AUTORUN_TCHANDLE, _
"wstr", ico, "uint", idx, "ptr")
# установка в трей с идентификатором 1001
If NotifyIcon("add", 1001, 99999, hIco, sHint) Then Tray1001 = 1
If hIco > 0 Then DllCall("DestroyIcon", "ptr", hIco)
EndFunc
# главная иконка Autorun
# функция обратного вызова
Func AutorunTrayAction(hWnd, uMsg, wParam, lParam)
Local bCtrl = IsPressed(0x11)
Switch lParam
# движение над иконкой
Case WM_MOUSEMOVE
If LAST_HINT_WINDOW = 0 Then
If bCtrl Then ShowHint(GetState("threads"), "", "", 2000, 1)
EndIf
# левый клик
Case WM_LBUTTONDOWN
If bCtrl Then
ClipPut(GetState("threads"))
ShowHint(GetState("threads"))
#ShowDarkHint(GetState("threads"))
Return
EndIf
AutorunMenu(0)
# правый клик
Case WM_RBUTTONDOWN
If bCtrl Then
ShowDarkHint(GetState("libs"))
Else
ShowSetEnviroments()
EndIf
# клик по сообщению
Case NIN_BALLOONUSERCLICK
MsgBox("Baloon click")
#WinSetState(23)
# клик "закрыть сообщение"
Case NIN_BALLOONTIMEOUT
MsgBox("Time-out")
EndSwitch
EndFunc
# иконка уведомлений
Func TrayNotifyInfo(hWnd, uMsg, wParam, lParam)
Switch lParam
Case WM_LBUTTONDOWN
ShowPopupMenu /D /F "TrayNotifyInfoMenu"
Case WM_RBUTTONDOWN
#NotifyIcon("delete", 1010)
Case NIN_BALLOONUSERCLICK
Case NIN_BALLOONTIMEOUT
EndSwitch
EndFunc
# меню уведомлений
Func TrayNotifyInfoMenu()
Local txt, nIco, sIco, sTime, sInfo, sType, sFunc, i = 0, j = 0
For i = TrayLog.Count - 1 To 0 Step -1
nIco = -1
sIco = "-1"
sTime = StrPart(TrayLog[i], Chr(0), 1)
sInfo = StrPart(TrayLog[i], Chr(0), 2)
sType = StrPart(TrayLog[i], Chr(0), 4)
If BitAND(sType, 3) = 1 Then
nIco = 76
ElseIf BitAND(sType, 3) = 2 Then
nIco = 79
ElseIf BitAND(sType, 3) = 3 Then
nIco = 93
EndIf
If nIco <> -1 Then sIco = "imageres.dll," & nIco
sFunc = "TrayNotifyItem " & i & " " & nIco
txt &= 'MENUITEM "' & sTime & " " & sInfo & '", em_aucmd ' & sIco & " " & sFunc & auCRLF
j += 1
If j = 30 Then Break
Next
If TrayLog.Count = 0 Then txt &= 'MENUITEM "<Пусто>", em_aucmd' & auCRLF
txt &= 'MENUITEM SEPARATOR' & auCRLF
txt &= 'MENUITEM "Копировать", em_aucmd -1 TrayNotifyCopy' & auCRLF
txt &= 'MENUITEM "Скрыть иконку", em_aucmd -1 NotifyIcon "delete" 1010' & auCRLF
Return txt
EndFunc
Func TrayNotifyItem(nItem, nIco)
Local nFlag
Local sInfo = StrPart(TrayLog[nItem], Chr(0), 2)
Local sText = StrPart(TrayLog[nItem], Chr(0), 3)
Switch nIco
Case 76
nFlag = 64
Case 79
nFlag = 48
Case 93
nFlag = 16
Else
nFlag = ''
EndSwitch
MsgBox(sText, sInfo, nFlag)
EndFunc
Func TrayNotifyCopy()
Local txt = TrayLog.Text
txt = StrReplace(txt, Chr(0), ";")
ClipPut(txt)
ShowTransHint("Скопировано в буфер")
EndFunc
# переключение иконки
Func ToggleTrayIcon(lParam)
If Tray1001 > 0 Then
IniWrite %AUTORUN_INI% "TrayIcon" "Show" 0
If NotifyIcon("delete", 1001) Then Tray1001 = 0
Else
IniWrite %AUTORUN_INI% "TrayIcon" "Show" 1
TrayIcon()
EndIf
If Tray1001 > 0 Then
ShowTransHint("Иконка включена")
Else
ShowTransHint("Иконка отключена")
EndIf
EndFunc
# иконка свернутого окна
Func MinTrayAction(hWnd, uMsg, wParam, lParam)
If lParam = WM_LBUTTONDOWN Then
If NotifyIcon("delete", 1003) Then Tray1003 = 0
WinSetState(5)
WinSetState(23)
ElseIf lParam = WM_RBUTTONDOWN Then
EndIf
EndFunc
# сворачивание
Func MinimizeToTray()
Local sHint = "Click to restore Total Commander"
Local hIcon = SendMessage(AUTORUN_TCHANDLE, 0x7f, 2, 0)
If hIcon = 0 Then
MsgBox("Не удалось получить дескриптор иконки", "Autorun", 48)
Return
EndIf
If NotifyIcon("add", 1003, Code1003, hIcon, sHint) Then Tray1003 = 1
WinSetState(0)
EndFunc
# тестовая функция
Func ChangeTrayIcon(lParam)
Static sDLL = GetKnownFolderPath("System") & "\shell32.dll", i = 10
If Tray1001 = 0 Then
ShowHint("Иконка отключена")
Return
EndIf
i += 1
Local hIco
hIco = DllCall("shell32\ExtractIconW", _
"ptr", AUTORUN_TCHANDLE, _
"wstr", sDLL, "uint", i, "ptr")
If IsPressed(0x11) Then
If NotifyIcon("add", 1002, 99999, hIco, "Autorun #2", "Second icon added", "Autorun", NIIF_INFO) Then
Tray1002 = 1
EndIf
Else
If IsPressed(0x12) Then hIco = 0
NotifyIcon("set", 1001, 99999, hIco, "", "Icon changed to shell32.dll, " & i, "", NIIF_WARNING)
Sleep(2000)
NotifyIcon("set", 1001,, hIco,, "Icon changed to shell32.dll, " & i,, NIIF_ERROR)
EndIf
If hIco > 0 Then DllCall("DestroyIcon", "ptr", hIco, "bool")
EndFunc
# тест уведомлений
Func NotifyInfo(lParam)
Local bCtrl = IsPressed(0x11)
Static i = 0
i += 1
If i > 3 Then i = 1
If bCtrl Then i = 1
If i = 1 Then
NotifyInfoMessage("Test message", "Test 1", NIIF_INFO)
If Not bCtrl Then Return
Sleep(2000)
EndIf
If bCtrl Or i = 2 Then
txt = "Pragma Include %COMMANDER_PATH%\Ini\Scripts\Test.aucfg"
NotifyInfoMessage(txt, "Test 2", NIIF_WARNING + NIIF_NOSOUND)
If Not bCtrl Then Return
Sleep(2000)
EndIf
If bCtrl Or i = 3 Then
txt = "Test message line 1" & auCRLF & "Test message line 2"
NotifyInfoMessage(txt, "Test 3", NIIF_ERROR)
EndIf
EndFunc
# проверка существования иконки
# функция имеет проблемы на Win10
Func IsIconOnTray(uId)
Local rc = Buffer(16) # RECT
rc.Zero()
Local id = Buffer(auX64 ? 40 : 28)
id.Zero()
If auX64 Then
id.SetNum(0, "dword", id.size)
id.SetNum(8, "hwnd", AUTORUN_TCHANDLE)
id.SetNum(16, "uint", uId)
Else
id.SetNum(0, "dword", id.size, _
"hwnd", AUTORUN_TCHANDLE, _
"uint", uId)
EndIf
Local hr = DllCall("Shell32.dll\Shell_NotifyIconGetRect", "ptr", id.ptr, "ptr", rc.ptr)
Free(id, rc)
Return hr = 0 ? true : false
EndFunc
#{
Вызов системных уведомлений:
InfoText - текст уведомления (255 символов)
InfoTitle - текст заголовка уведомления (63 символов)
InfoType - флаги NIIF_* меняющие вид и поведение окна уведомлений
Функция использует идентификатор "1010"
#}
Func NotifyInfoMessage(InfoText, InfoTitle = "Autorun", InfoType = 0)
Local Offset = auX64 ? 40 : 24, sIcon
Static buf = Buffer(auPtrSize = 4 ? 956 : 976)
Static nFlags = BitOR(NIF_MESSAGE, NIF_ICON, NIF_INFO, NIF_TIP)
If FileExist(gNotifyIcon) Then
sIcon = gNotifyIcon
Else
sIcon = COMMANDER_EXE
EndIf
Static hIco = DllCall("shell32\ExtractIconW", _
"ptr", AUTORUN_TCHANDLE, _
"wstr", sIcon, "uint", 0, "ptr")
NotifyIcon("delete", 1010)
buf.Zero()
If auX64 Then
buf.SetNum(0, "dword", buf.size)
buf.SetNum(8, "hwnd", AUTORUN_TCHANDLE)
buf.SetNum(16, "uint", 1010, _
"uint", nFlags, _
"uint", Code1010)
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", nFlags, _
"uint", Code1010, _
"ptr", hIco)
buf.SetNum(280, "dword", 1, _
"dword", 1)
EndIf
buf.SetStr("Notify Messages" & Chr(0), Offset)
buf.SetStr(StrLeft(InfoText, 255) & Chr(0), Offset + 264) # 256 + 4 + 4
Offset += 264
If InfoTitle <> "" Then
buf.SetStr(StrLeft(InfoTitle, 63) & Chr(0), Offset + 516) # 512 + 4
EndIf
Offset += 516
If InfoType > 0 Then
buf.SetNum(Offset + 128, "dword", InfoType) # 128
EndIf
TrayLog.Add(Time() & Chr(0) & InfoTitle & Chr(0) & InfoText & Chr(0) & InfoType)
Tray1010 = 1
Return DllCall("Shell32.dll\Shell_NotifyIconW", "uint", 0, "ptr", buf.ptr)
EndFunc
#{
Добавление иконки в трей:
sAction - тип действия ("add", "set", "delete")
uID - внутренний уникальный идентификатор иконки
nCallback - код зарегистрированного сообщения для функции обратного вызова
hIcon - дескриптор иконки (только для "add")
sTip - текст подсказки в трее
sText - текст уведомления (только для "add" и "set")
sTitle - текст заголовка уведомления
nType - флаги NIIF_* (изменение вида и поведения окна уведомлений)
https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataw
#}
Func NotifyIcon(sAction, uID, nCallback = 0, hIcon = 0, sTip = "", sText = "", sTitle = "", nType = 0)
Local nAction, nFlags
Static TIP_MAXCHAR = 127, INFO_MAXCHAR = 255, TITLE_MAXCHAR = 63
Static buf = Buffer(auPtrSize = 4 ? 956 : 976)
buf.Zero()
nFlags = BitOR( hIcon = 0 ? 0 : NIF_ICON, _
nCallback = 0 ? 0 : NIF_MESSAGE, _
StrLen(sTip) = 0 ? 0 : NIF_TIP, _
StrLen(sText) = 0 ? 0 : NIF_INFO )
Switch sAction
Case "add"
nAction = 0
Case "set"
nAction = 1
Case "delete"
nAction = 2
Else
Return
EndSwitch
If auX64 Then
buf.SetNum(0, "dword", buf.size)
buf.SetNum(8, "hwnd", AUTORUN_TCHANDLE)
buf.SetNum(16, "uint", uID, _
"uint", nFlags, _
"uint", nCallback)
buf.SetNum(32, "ptr", hIcon)
Else
buf.SetNum(0, "dword", buf.size, _
"hwnd", AUTORUN_TCHANDLE, _
"uint", uID, _
"uint", nFlags, _
"uint", nCallback, _
"ptr", hIcon)
EndIf
Local nOffset = auX64 ? 40 : 24 # PtrSize*2 + 4*4 + padding for X64
If sTip <> 0 Then
buf.SetStr(StrLeft(sTip, TIP_MAXCHAR) & Chr(0), nOffset)
EndIf
If sText <> 0 Then
nOffset += 264
buf.SetStr(StrLeft(sText, INFO_MAXCHAR) & Chr(0), nOffset) # 256 + 4 + 4
If sTitle <> 0 Then
buf.SetStr(StrLeft(sTitle, TITLE_MAXCHAR) & Chr(0), nOffset + 516) # 512 + 4
EndIf
If nType > 0 Then
buf.SetNum(nOffset + 644, "dword", nType) # 128
EndIf
EndIf
Return DllCall("Shell32.dll\Shell_NotifyIconW", "uint", nAction, "ptr", buf.ptr, "bool")
EndFunc
Global ROTATE_THREAD = 0
Func RotateIcon()
If ROTATE_THREAD > 0 Then
ROTATE_THREAD = 0
Return
EndIf
RunThread("ThreadRotateIcon", IsPressed(0x11))
EndFunc
Func ThreadRotateIcon(FileIcons)
ROTATE_THREAD = 1
Local hIcon = SendMessage(AUTORUN_TCHANDLE, 0x7f, 2, 0)
While ROTATE_THREAD > 0
Sleep(150)
If FileIcons Then
IconRotateDraw()
Else
RotateDeviceContext()
EndIf
Wend
SendMessage(AUTORUN_TCHANDLE, 0x80, 0, hIcon)
WinRedraw(2)
EndFunc
Func IconRotateDraw()
Static nIco = 0
nIco += 1
If nIco > 4 Then nIco = 1
Local sFile = COMMANDER_PATH & "\Icons\TC\" & nIco & ".ico"
Local hIco = DllCall("shell32\ExtractIconW", _
"ptr", AUTORUN_TCHANDLE, _
"wstr", sFile, _
"uint", 0, _
"ptr")
Local hWnd = WinFind(AUTORUN_TCHANDLE, _
(AUTORUN_TCARCH = 32 ? "TMyPanel" : "Window"), _
(AUTORUN_TCARCH = 32 ? 6 : 10))
# Local hWnd = RequestInfo(15)
# hDC = DllCall("GetDC", "ptr", hWnd, "ptr")
Local hDC = DllCall("GetWindowDC", "ptr", hWnd, "ptr")
Local x, y, w, h
WinGetPos("x", "y", "w", "h", hWnd)
DllCall("DrawIconEx", _
"ptr", hDC, _
"int", w - 20, _
"int", 1, _
"ptr", hIco, _
"int", 16, _
"int", 16, _
"uint", 0, _
"ptr", 0, _
"uint", 0x0003)
SendMessage(AUTORUN_TCHANDLE, 0x80, 0, hIco)
SendMessage(AUTORUN_TCHANDLE, 0x80, 1, hIco)
DllCall("ReleaseDC", "ptr", AUTORUN_TCHANDLE, "ptr", hDC)
DllCall("DestroyIcon", "ptr", hIco)
EndFunc
Func RotateDeviceContext()
Static c = 0
c += 1
If c > 4 Then c = 1
Local x, y, w, h
Local hIco = SendMessage(AUTORUN_TCHANDLE, 0x7f, 2, 0)
Local hWnd = WinFind(AUTORUN_TCHANDLE, _
(AUTORUN_TCARCH = 32 ? "TMyPanel" : "Window"), _
(AUTORUN_TCARCH = 32 ? 6 : 10))
Local DC = DllCall("GetDC", "int", 0)
Local nDPI = DllCall("GetDeviceCaps", "handle", DC, "int", 88)
Local nScale = DllCall("MulDiv", "int", 100, "int", nDPI, "int", 96)
Local nSize = Round(16*nScale/100,0)
# Local hWnd = RequestInfo(15)
Local hdcWndDC = DllCall("GetWindowDC", "ptr", hWnd, "ptr")
Local hdcMemDC = DllCall("CreateCompatibleDC", "ptr", hdcWndDC, "ptr")
Local hdcBltDC = DllCall("CreateCompatibleDC", "ptr", hdcWndDC, "ptr")
Local hbmDB1 = DllCall("CreateCompatibleBitmap", "ptr", hdcWndDC, "int", nSize, "int", nSize,"ptr")
Local hbmDB2 = DllCall("CreateCompatibleBitmap", "ptr", hdcWndDC, "int", nSize, "int", nSize,"ptr")
DllCall("SelectObject", "ptr", hdcMemDC, "ptr", hbmDB1, "ptr")
DllCall("SelectObject", "ptr", hdcBltDC, "ptr", hbmDB2, "ptr")
DllCall("DrawIconEx", _
"ptr", hdcMemDC, _
"int", 1, _
"int", 1, _
"ptr", hIco, _
"int", nSize, _
"int", nSize, _
"uint", 0, _
"ptr", 0, _
"uint", 0x0003)
Local pt = Buffer(24)
pt.Zero()
If c = 1 Then
pt.SetNum(0, "int", nSize, "int", 0, _
"int", 0, "int", 0, _
"int", nSize, "int", nSize)
ElseIf c = 2 Then
pt.SetNum(0, "int", nSize, "int", nSize, _
"int", nSize, "int", 0, _
"int", 0, "int", nSize)
ElseIf c = 3 Then
pt.SetNum(0, "int", 0, "int", nSize, _
"int", nSize, "int", nSize, _
"int", 0, "int", 0)
ElseIf c = 4 Then
pt.SetNum(0, "int", 0, "int", 0, _
"int", 0, "int", nSize, _
"int", nSize, "int", 0)
EndIf
DllCall("PlgBlt", _
"ptr", hdcBltDC, _
"ptr", pt.Ptr, _
"ptr", hdcMemDC, _
"int", 0, _
"int", 0, _
"int", nSize, _
"int", nSize, _
"ptr", 0, _
"int", 0, "int", 0)
WinGetPos("x", "y", "w", "h", hWnd)
DllCall("BitBlt", _
"ptr", hdcWndDC, _
"int", w - 20, _
"int", 2, _
"int", nSize, _
"int", nSize, _
"ptr", hdcBltDC, _
"int", 1, _
"int", 1, _
"dword", 13369376)
DllCall("DeleteObject", "ptr", hbmDB1)
DllCall("DeleteObject", "ptr", hbmDB2)
DllCall("DeleteObject", "ptr", hdcMemDC)
DllCall("DeleteObject", "ptr", hdcBltDC)
DllCall("ReleaseDC", "ptr", AUTORUN_TCHANDLE, "ptr", hdcWndDC)
EndFunc |
В модуле есть две универсальные функции для показа системных уведомлений и создания иконок в трее: NotifyInfoMessage и NotifyIcon. Коды кнопок 64000-64002 тестирую функционал. Созданные идентификаторы иконок нужно добавить в секцию финализации, чтобы при выхода из ТС они не оставались висеть в трее.
 Pragma AutorunFinalizeSection | Code: | # удаление иконок
If Tray1001 > 0 Then NotifyIcon("delete", 1001)
If Tray1002 > 0 Then NotifyIcon("delete", 1002)
If Tray1003 > 0 Then NotifyIcon("delete", 1003)
If Tray1010 > 0 Then NotifyIcon("delete", 1010) |
Модуль можно накатить на тот, что в сборке, для удобного и быстрого теста. |
|
| Back to top |
|
 |
FallenAngel
Joined: 30 Dec 2025 Posts: 25
|
(Separately) Posted: Tue Feb 10, 2026 15:44 Post subject: |
|
|
| Orion9 wrote: | | Перезаливка. |
Почему просто не использовать приличный хостинг? terabox.com, mega.nz или pixeldrain.com ?
| Orion9 wrote: | | Обновил модуль Icons.aucfg. |
Добавляйте небольшое описание в самом начале файла, модуль возможно и интересный, но не ясно что он делает (как и остальные 13к строк).
Повторюсь, намного полезнее (понятнее, удобнее, логичнее, ...) было бы выкладывать просто модулями. Возможно и найдется самурай, который скачает сборку и осилит часть написанного... но это 1-2 юзера (с огромным запасом свободного времени) и не более. |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1024
|
(Separately) Posted: Tue Feb 10, 2026 19:01 Post subject: |
|
|
| FallenAngel wrote: | | Возможно и найдется самурай, который скачает сборку и осилит часть написанного |
Cамурай звучит громо, скорее фрик, как я )
А я ведь предупреждал Loopback, что у нас с Autorun всё всьерёз и надолго, а он мне не верил ) Могу только повторить свой пледж и коммитмент:
 Hidden text Till death us do part, Auto 
| FallenAngel wrote: | | terabox.com, mega.nz или pixeldrain.com |
Первый всё в том же 16 Кб блоке, остальные, судя по всему, в белых списках, но требуют регистрацию, а оно мне вроде как не надо.
Сделать перманентную ссылку на том же гугл диске (или любом другом диске) не проблема. Но не раньше, чем Loopback сделает перманентную ссылку на финальную версию Autorun
А пока все это для тестов и эксперементов. Если кто-то может извлечь из этого пользу — без проблем. Буду только рад, что помимо меня кому-то ещё пригодилось.
| FallenAngel wrote: | | Добавляйте небольшое описание в самом начале файла, модуль возможно и интересный, но не ясно что он делает (как и остальные 13к строк). |
Ранний функционал довольно хорошо документирован, просто на последние модули я не нашел возможности сделать описание. Думал, сейчас у меня будет большое окно и смогу наверстать упущенное, но нет, судя по всему, опять не получится.
Но не все так плохо. В этом топике осталось практически всё, правда мотать придется чуть дальше.
Конкретно по этому модулю. Имхо, он неплохо документирован самими комментариями. Да, возможно, сейчас вам так не кажется, но со временем все прояснится, если вы не бросите заниматься Autorun.
Когда-то, глянув на этот модуль, я подумал, надо быть реально повернутым, чтобы полностью в нем разобраться. Однако сейчас я на него смотрю и он мне кажется довольно простым и понятным. Одна мальнькая ремарка: с тех пор прошло два года
Так что верно говорят, что путь осилит идущий, а нет кто с него сходит или топчется на месте)
P.s. Ссылка на модуль за CloudFlare, т.ч. приложу его сюда.
 Hidden text | Code: | ;https://www.autohotkey.com/boards/viewtopic.php?t=113308
;======================================================================================================================
; ToolTipOptions - additional options for ToolTips
;
; Tooltip control -> https://learn.microsoft.com/en-us/windows/win32/controls/tooltip-control-reference
; TTM_SETMARGIN = 1050
; TTM_SETTIPBKCOLOR = 1043
; TTM_SETTIPTEXTCOLOR = 1044
; TTM_SETTITLEW = 1057
; WM_SETFONT = 0x30
; SetClassLong() -> https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setclasslongw
; ======================================================================================================================
Class ToolTipOptions {
; -------------------------------------------------------------------------------------------------------------------
Static HTT := DllCall("User32.dll\CreateWindowEx", "UInt", 8, "Str", "tooltips_class32", "Ptr", 0, "UInt", 3
, "Int", 0, "Int", 0, "Int", 0, "Int", 0, "Ptr", A_ScriptHwnd, "Ptr", 0, "Ptr", 0, "Ptr", 0)
Static SWP := CallbackCreate(ObjBindMethod(ToolTipOptions, "_WNDPROC_"), , 4) ; subclass window proc
Static OWP := 0 ; original window proc
Static ToolTips := Map()
; -------------------------------------------------------------------------------------------------------------------
Static BkgColor := ""
Static TktColor := ""
Static Icon := ""
Static Title := ""
Static HFONT := 0
Static Margins := ""
; -------------------------------------------------------------------------------------------------------------------
Static Call(*) => False ; do not create instances
; -------------------------------------------------------------------------------------------------------------------
; Init() - Initialize some class variables and subclass the tooltip control.
; -------------------------------------------------------------------------------------------------------------------
Static Init() {
If (This.OWP = 0) {
This.BkgColor := ""
This.TktColor := ""
This.Icon := ""
This.Title := ""
This.Margins := ""
If (A_PtrSize = 8)
This.OWP := DllCall("User32.dll\SetClassLongPtr", "Ptr", This.HTT, "Int", -24, "Ptr", This.SWP, "UPtr")
Else
This.OWP := DllCall("User32.dll\SetClassLongW", "Ptr", This.HTT, "Int", -24, "Int", This.SWP, "UInt")
OnExit(ToolTipOptions._EXIT_, -1)
Return This.OWP
}
Else
Return False
}
; -------------------------------------------------------------------------------------------------------------------
; Reset() - Close all existing tooltips, delete the font object, and remove the tooltip's subclass.
; -------------------------------------------------------------------------------------------------------------------
Static Reset() {
If (This.OWP != 0) {
For HWND In This.ToolTips.Clone()
DllCall("DestroyWindow", "Ptr", HWND)
This.ToolTips.Clear()
If This.HFONT
DllCall("DeleteObject", "Ptr", This.HFONT)
This.HFONT := 0
If (A_PtrSize = 8)
DllCall("User32.dll\SetClassLongPtrW", "Ptr", This.HTT, "Int", -24, "Ptr", This.OWP, "UPtr")
Else
DllCall("User32.dll\SetClassLongW", "Ptr", This.HTT, "Int", -24, "Int", This.OWP, "UInt")
This.OWP := 0
Return True
}
Else
Return False
}
; -------------------------------------------------------------------------------------------------------------------
; SetColors() - Set or remove the text and/or the background color for the tooltip.
; Parameters:
; BkgColor - color value like used in Gui.BackColor(...)
; TxtColor - see above.
; -------------------------------------------------------------------------------------------------------------------
Static SetColors(BkgColor := "", TxtColor := "") {
This.BkgColor := BkgColor = "" ? "" : BGR(BkgColor)
This.TxtColor := TxtColor = "" ? "" : BGR(TxtColor)
BGR(Color, Default := "") { ; converts colors to BGR
; HTML Colors (BGR)
Static HTML := {AQUA: 0xFFFF00, BLACK: 0x000000, BLUE: 0xFF0000, FUCHSIA: 0xFF00FF, GRAY: 0x808080,
GREEN: 0x008000, LIME: 0x00FF00, MAROON: 0x000080, NAVY: 0x800000, OLIVE: 0x008080,
PURPLE: 0x800080, RED: 0x0000FF, SILVER: 0xC0C0C0, TEAL: 0x808000, WHITE: 0xFFFFFF,
YELLOW: 0x00FFFF}
If HTML.HasProp(Color)
Return HTML.%Color%
If (Color Is String) && IsXDigit(Color) && (StrLen(Color) = 6)
Color := Integer("0x" . Color)
If IsInteger(Color)
Return ((Color >> 16) & 0xFF) | (Color & 0x00FF00) | ((Color & 0xFF) << 16)
Return Default
}
}
; -------------------------------------------------------------------------------------------------------------------
; SetFont() - Set or remove the font used by the tooltip.
; Parameters:
; FntOpts - font options like Gui.SetFont(Options, ...)
; FntName - font name like Gui.SetFont(..., Name)
; -------------------------------------------------------------------------------------------------------------------
Static SetFont(FntOpts := "", FntName := "") {
Static HDEF := DllCall("GetStockObject", "Int", 17, "UPtr") ; DEFAULT_GUI_FONT
Static LOGFONTW := 0
If (FntOpts = "") && (FntName = "") {
If This.HFONT
DllCall("DeleteObject", "Ptr", This.HFONT)
This.HFONT := 0
LOGFONTW := 0
}
Else {
If (LOGFONTW = 0) {
LOGFONTW := Buffer(92, 0)
DllCall("GetObject", "Ptr", HDEF, "Int", 92, "Ptr", LOGFONTW)
}
HDC := DllCall("GetDC", "Ptr", 0, "UPtr")
LOGPIXELSY := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 90, "Int")
DllCall("ReleaseDC", "Ptr", HDC, "Ptr", 0)
If (FntOpts != "") {
For Opt In StrSplit(RegExReplace(Trim(FntOpts), "\s+", " "), " ") {
Switch StrUpper(Opt) {
Case "BOLD": NumPut("Int", 700, LOGFONTW, 16)
Case "ITALIC": NumPut("Char", 1, LOGFONTW, 20)
Case "UNDERLINE": NumPut("Char", 1, LOGFONTW, 21)
Case "STRIKE": NumPut("Char", 1, LOGFONTW, 22)
Case "NORM": NumPut("Int", 400, "Char", 0, "Char", 0, "Char", 0, LOGFONTW, 16)
Default:
O := StrUpper(SubStr(Opt, 1, 1))
V := SubStr(Opt, 2)
Switch O {
Case "C":
Continue ; ignore the color option
Case "Q":
If !IsInteger(V) || (Integer(V) < 0) || (Integer(V) > 5)
Throw ValueError("Option Q must be an integer between 0 and 5!", -1, V)
NumPut("Char", Integer(V), LOGFONTW, 26)
Case "S":
If !IsNumber(V) || (Number(V) < 1) || (Integer(V) > 255)
Throw ValueError("Option S must be a number between 1 and 255!", -1, V)
NumPut("Int", -Round(Integer(V + 0.5) * LOGPIXELSY / 72), LOGFONTW)
Case "W":
If !IsInteger(V) || (Integer(V) < 1) || (Integer(V) > 1000)
Throw ValueError("Option W must be an integer between 1 and 1000!", -1, V)
NumPut("Int", Integer(V), LOGFONTW, 16)
Default:
Throw ValueError("Invalid font option!", -1, Opt)
}
}
}
}
NumPut("Char", 1, "Char", 4, "Char", 0, LOGFONTW, 23) ; DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS
NumPut("Char", 0, LOGFONTW, 27) ; FF_DONTCARE
If (FntName != "")
StrPut(FntName, LOGFONTW.Ptr + 28, 32)
If !(HFONT := DllCall("CreateFontIndirectW", "Ptr", LOGFONTW, "UPtr"))
Throw OSError()
If This.HFONT
DllCall("DeleteObject", "Ptr", This.HFONT)
This.HFONT := HFONT
}
}
; -------------------------------------------------------------------------------------------------------------------
; SetMargins() - Set or remove the margins used by the tooltip
; Parameters:
; L, T, R, B - left, top, right, and bottom margin in pixels.
; -------------------------------------------------------------------------------------------------------------------
Static SetMargins(L := 0, T := 0, R := 0, B := 0) {
If ((L + T + R + B) = 0)
This.Margins := 0
Else {
This.Margins := Buffer(16, 0)
NumPut("Int", L, "Int", T, "Int", R, "Int", B, This.Margins)
}
}
; -------------------------------------------------------------------------------------------------------------------
; SetTitle() - Set or remove the title and/or the icon displayed on the tooltip.
; Parameters:
; Title - string to be used as title.
; Icon - icon to be shown in the ToolTip.
; This can be the number of a predefined icon (1 = info, 2 = warning, 3 = error
; (add 3 to display large icons on Vista+) or a HICON handle.
; -------------------------------------------------------------------------------------------------------------------
Static SetTitle(Title := "", Icon := "") {
Switch {
Case (Title = "") && (Icon != ""):
This.Icon := Icon
This.Title := " "
Case (Title != "") && (Icon = ""):
This.Icon := 0
This.Title := Title
Default:
This.Icon := Icon
This.Title := Title
}
}
; -------------------------------------------------------------------------------------------------------------------
; For internal use only!
; -------------------------------------------------------------------------------------------------------------------
Static _WNDPROC_(hWnd, uMsg, wParam, lParam) {
; WNDPROC -> https://learn.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-wndproc
Switch uMsg {
Case 0x0411: ; TTM_TRACKACTIVATE - just handle the first message after the control has been created
If This.ToolTips.Has(hWnd) && (This.ToolTips[hWnd] = 0) {
If (This.BkgColor != "")
SendMessage(1043, This.BkgColor, 0, hWnd) ; TTM_SETTIPBKCOLOR
If (This.TxtColor != "")
SendMessage(1044, This.TxtColor, 0, hWnd) ; TTM_SETTIPTEXTCOLOR
If This.HFONT
SendMessage(0x30, This.HFONT, 0, hWnd) ; WM_SETFONT
If (Type(This.Margins) = "Buffer")
SendMessage(1050, 0, This.Margins.Ptr, hWnd) ; TTM_SETMARGIN
If (This.Icon != "") || (This.Title != "")
SendMessage(1057, This.Icon, StrPtr(This.Title), hWnd) ; TTM_SETTITLE
This.ToolTips[hWnd] := 1
}
Case 0x0001: ; WM_CREATE
DllCall("UxTheme.dll\SetWindowTheme", "Ptr", hWnd, "Ptr", 0, "Ptr", StrPtr(""))
This.ToolTips[hWnd] := 0
Case 0x0002: ; WM_DESTROY
This.ToolTips.Delete(hWnd)
}
Return DllCall(This.OWP, "Ptr", hWnd, "UInt", uMsg, "Ptr", wParam, "Ptr", lParam, "UInt")
}
; -------------------------------------------------------------------------------------------------------------------
Static _EXIT_(*) {
If (ToolTipOptions.OWP != 0)
ToolTipOptions.Reset()
}
} |
|
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1024
|
(Separately) Posted: Wed Feb 11, 2026 20:35 Post subject: |
|
|
FallenAngel
Если вкратце.
Функция NotifyIcon принимает следующие параметры:
| Code: | sAction - тип действия ("add", "set", "delete")
uID - внутренний уникальный идентификатор иконки
nCallback - код зарегистрированного сообщения для функции обратного вызова
hIcon - дескриптор иконки (только для "add")
sTip - текст подсказки в трее
sText - текст уведомления (только для "add" и "set")
sTitle - текст заголовка уведомления
nType - флаги NIIF_* (изменение вида и поведения окна уведомлений)
Func NotifyIcon(sAction, uID, nCallback = 0, hIcon = 0, sTip = "", sText = "", sTitle = "", nType = 0) |
Чтобы добавить иконку в трей, нужен режим "add" и еще 3 параметра. Четвертый параметр sTip тоже желателен, т.к. он отвечает за текст подсказки в трее, но его в принципе можно не указывать.
Все сводится к одному вызову, например:
| Code: | NotifyIcon("add", 1005, gCode, hIco, "Иконка Autorun") |
Первый и последний параметры нам уже понятны. Осталось разобраться за что именно отвечают uID = 1005, nCallback = gCode, hIcon = hIco.
uID - это просто внутренний код иконки, взятый буквально от балды. Приложение может держать в трее несколько иконок, оболочке Windows и нам самим нужно как-то их отличать. Код может быть любым числом. Здесь он 1005.
nCallback - это код, который использует оболочка, когда она посылает сообщения о событиях в трее назад приложению. И снова этот код мы должны сами придумать, но только в определенном диапазоне. Чтобы не забивать этим голову, мы просим систему выделить нам уникальный незанятый код. Каким именно будет этот код, нам не важно, мы просто запоминаем его в переменной gCode:
| Code: | Global gCode = DllCall("RegisterWindowMessageW", "wstr", "TrayNotify1005", "uint") |
Теперь получив нужный код, мы должны внутри приложения привязать его к реальной функции, которая будет запускаться каждый раз, когда оболочка шлет нам сообщения с этим кодом.
| Code: | SetMessageAction /P %"gCode" "TestrayAction" |
Внутри функции мы должны обрабатывать те сообщения, события которых нам интересны. Это прежде всего события левого и правого клика, но можно обрабатывать и другие события.
| Code: | Func TestrayAction(hWnd, uMsg, wParam, lParam)
If lParam = WM_LBUTTONDOWN Then
MsgBox("Клик по иконке")
ElseIf lParam = WM_RBUTTONDOWN Then
ShowPopupMenu("~/D", COMMANDER_PATH & "\Bars\Vertical.bar")
EndIf
EndFunc |
Левый клик по иконке выводит MsgBox, правый отображает меню из Vertical.bar. Можно использать и другие команды, em_команды, mnu и bar файлы — здесь есть, где фантазии развернуться.
Остается только иконка. Дескриптор иконки hIcon можно получать по-разному. Самый простой способ — послать сообщение окну ТС с кодом 0x7f, тогда тотал вернет дескриптор своей иконки:
| Code: | hIcon = SendMessage(AUTORUN_TCHANDLE, 0x7f, 2, 0) |
Можно также получить дескриптор функцией ExtractIcon, вызывать которую нужно через DllCall
| Code: | sIco = GetKnownFolderPath("System") & "\shell32.dll"
hIco = DllCall("shell32\ExtractIconW", _
"ptr", AUTORUN_TCHANDLE, _
"wstr", sIco, "uint", 15, "ptr")
|
В вызовах DllCall нет ничего страшного. По сути, это просто запрос к Windows, чтобы она выполнила за нас определенные действия. В данном случае таким действием является извлечение иконки с индексом 15 из shell32.dll и передача нам дескриптора.
Нам, в свою очередь, остается передать этот дескриптор функции NotifyIcon вместе с другими параметрами. Итого, полученный код будет выглядеть так:
| Code: | # регистрация кода для функции обратного вызова
Global gCode = DllCall("RegisterWindowMessageW", "wstr", "TrayNotify1005", "uint")
# привязка функции обратного вызова к полученному коду
SetMessageAction /P %"gCode" "TestrayAction"
# функция обратного вызова
Func TestrayAction(hWnd, uMsg, wParam, lParam)
If lParam = WM_LBUTTONDOWN Then
#MsgBox("Клик по иконке")
NotifyIcon("set", 1005, gCode, hIco, "", "Test message", "", NIIF_WARNING)
ElseIf lParam = WM_RBUTTONDOWN Then
ShowPopupMenu("~/D", COMMANDER_PATH & "\Bars\Vertical.bar")
EndIf
EndFunc
# путь к иконке
sIco = GetKnownFolderPath("System") & "\shell32.dll"
# получение дескриптора иконки с индексом 15
hIco = DllCall("shell32\ExtractIconW", _
"ptr", AUTORUN_TCHANDLE, _
"wstr", sIco, "uint", 15, "ptr")
# установка в трей с идентификатором 1005
NotifyIcon("add", 1005, gCode, hIco, "Иконка Autorun") |
Вот так. Несколько строк и дело в шляпе иконка в трее
Однако, чтобы этот фрагмент кода заработал самостоятельно, без привязки к модулю Icons.aucfg, необходимо перенести из него все константы и, собственно, саму функцию NotifyIcon:
 Hidden text | 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
# системные сообщения
Const WM_MOUSEMOVE = 0x0200, _
WM_LBUTTONDOWN = 0x0201, _
WM_LBUTTONUP = 0x0202, _
WM_LBUTTONDBLCLK = 0x0203, _
WM_RBUTTONDOWN = 0x0204, _
WM_RBUTTONUP = 0x0205, _
WM_RBUTTONDBLCLK = 0x0206, _
WM_MBUTTONDOWN = 0x0207, _
WM_MBUTTONUP = 0x0208, _
WM_MBUTTONDBLCLK = 0x0209
#{
Добавление иконки в трей:
sAction - тип действия ("add", "set", "delete")
uID - внутренний уникальный идентификатор иконки
nCallback - код зарегистрированного сообщения для функции обратного вызова
hIcon - дескриптор иконки (только для "add")
sTip - текст подсказки в трее
sText - текст уведомления (только для "add" и "set")
sTitle - текст заголовка уведомления
nType - флаги NIIF_* (изменение вида и поведения окна уведомлений)
https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataw
#}
Func NotifyIcon(sAction, uID, nCallback = 0, hIcon = 0, sTip = "", sText = "", sTitle = "", nType = 0)
Local nAction, nFlags
Static TIP_MAXCHAR = 127, INFO_MAXCHAR = 255, TITLE_MAXCHAR = 63
Static buf = Buffer(auPtrSize = 4 ? 956 : 976)
buf.Zero()
nFlags = BitOR( hIcon = 0 ? 0 : NIF_ICON, _
nCallback = 0 ? 0 : NIF_MESSAGE, _
StrLen(sTip) = 0 ? 0 : NIF_TIP, _
StrLen(sText) = 0 ? 0 : NIF_INFO )
Switch sAction
Case "add"
nAction = 0
Case "set"
nAction = 1
Case "delete"
nAction = 2
Else
Return
EndSwitch
If auX64 Then
buf.SetNum(0, "dword", buf.size)
buf.SetNum(8, "hwnd", AUTORUN_TCHANDLE)
buf.SetNum(16, "uint", uID, _
"uint", nFlags, _
"uint", nCallback)
buf.SetNum(32, "ptr", hIcon)
Else
buf.SetNum(0, "dword", buf.size, _
"hwnd", AUTORUN_TCHANDLE, _
"uint", uID, _
"uint", nFlags, _
"uint", nCallback, _
"ptr", hIcon)
EndIf
Local nOffset = auX64 ? 40 : 24 # PtrSize*2 + 4*4 + padding for X64
If sTip <> 0 Then
buf.SetStr(StrLeft(sTip, TIP_MAXCHAR) & Chr(0), nOffset)
EndIf
If sText <> 0 Then
nOffset += 264
buf.SetStr(StrLeft(sText, INFO_MAXCHAR) & Chr(0), nOffset) # 256 + 4 + 4
If sTitle <> 0 Then
buf.SetStr(StrLeft(sTitle, TITLE_MAXCHAR) & Chr(0), nOffset + 516) # 512 + 4
EndIf
If nType > 0 Then
buf.SetNum(nOffset + 644, "dword", nType) # 128
EndIf
EndIf
Return DllCall("Shell32.dll\Shell_NotifyIconW", "uint", nAction, "ptr", buf.ptr, "bool")
EndFunc
# регистрация кода для функции обратного вызова
Global gCode = DllCall("RegisterWindowMessageW", "wstr", "TrayNotify1005", "uint")
# привязка функции обратного вызова к полученному коду
SetMessageAction /P %"gCode" "TestrayAction"
# функция обратного вызова
Func TestrayAction(hWnd, uMsg, wParam, lParam)
If lParam = WM_LBUTTONDOWN Then
If IsPressed(0x11) Then
NotifyIcon("set", 1005, gCode, hIco, "", "Test message", "", NIIF_WARNING)
Return
EndIf
MsgBox("Клик по иконке")
ElseIf lParam = WM_RBUTTONDOWN Then
ShowPopupMenu("~/D", COMMANDER_PATH & "\Bars\Vertical.bar")
EndIf
EndFunc
# путь к иконке
sIco = GetKnownFolderPath("System") & "\shell32.dll"
# получение дескриптора иконки с индексом 15
hIco = DllCall("shell32\ExtractIconW", _
"ptr", AUTORUN_TCHANDLE, _
"wstr", sIco, "uint", 15, "ptr")
# установка в трей с идентификатором 1005
NotifyIcon("add", 1005, gCode, hIco, "Иконка Autorun") |
Работает у вас?
В этот код я добавил обработку CTRL:
| Code: | If IsPressed(0x11) Then
NotifyIcon("set", 1005, gCode, hIco, "", "Test message", "", NIIF_WARNING)
Return
EndIf |
Теперь клик по иконке с Ctrl отображает системное уведомление. Функция NotifyIcon может не только добавлять или менять иконку в трее, но также показывать системные уведомления. Единственное условие — иконка в трее должна существовать. Именно поэтому, чтобы была возможность вызвать системные уведомления без привязки к конкретной иконке, реализована функция NotifyInfoMessage.
| Code: | #{
Вызов системных уведомлений:
InfoText - текст уведомления (255 символов)
InfoTitle - текст заголовка уведомления (63 символов)
InfoType - флаги NIIF_* меняющие вид и поведение окна уведомлений
Функция использует идентификатор "1010"
#}
Func NotifyInfoMessage(InfoText, InfoTitle = "Autorun", InfoType = 0) |
Функция заранее резервирует идентификатор иконки и не требует указания дескриптора — дескриптор берется из файла, указанного в gNotifyIcon. Если файл не существует, будет использоваться иконка тотала. Для обратного вызова также получается код и сохраняется в переменную Code1010. Функция обратного вызова определена как TrayNotifyInfo. Данная функция обрабатывает левый клик по иконке в трее, где отображается меню лога уведомлений. Это еще одна особенность NotifyInfoMessage — она сохраняет лог уведомлений в текущей сессии. Т.о. даже если уведомление было пропущено (закрыто по таймауту) в трее можно будет увидеть его след:
 Hidden text | Code: | lobal gNotifyIcon = COMMANDER_EXE
#Global gNotifyIcon = COMMANDER_PATH & "\Ini\Newsbar\notify-yes.ico"
# регистрация уникального кода
Global Code1010 = DllCall("RegisterWindowMessageW", "wstr", "TrayNotify1010", "uint")
SetMessageAction /P %"Code1010" "TrayNotifyInfo"
# иконка уведомлений
Func TrayNotifyInfo(hWnd, uMsg, wParam, lParam)
Switch lParam
Case WM_LBUTTONDOWN
ShowPopupMenu /D /F "TrayNotifyInfoMenu"
Case WM_RBUTTONDOWN
#NotifyIcon("delete", 1010)
Case NIN_BALLOONUSERCLICK
Case NIN_BALLOONTIMEOUT
EndSwitch
EndFunc
# меню уведомлений
Func TrayNotifyInfoMenu()
Local txt, nIco, sIco, sTime, sInfo, sType, sFunc, i = 0, j = 0
For i = TrayLog.Count - 1 To 0 Step -1
nIco = -1
sIco = "-1"
sTime = StrPart(TrayLog[i], Chr(0), 1)
sInfo = StrPart(TrayLog[i], Chr(0), 2)
sType = StrPart(TrayLog[i], Chr(0), 4)
If BitAND(sType, 3) = 1 Then
nIco = 76
ElseIf BitAND(sType, 3) = 2 Then
nIco = 79
ElseIf BitAND(sType, 3) = 3 Then
nIco = 93
EndIf
If nIco <> -1 Then sIco = "imageres.dll," & nIco
sFunc = "TrayNotifyItem " & i & " " & nIco
txt &= 'MENUITEM "' & sTime & " " & sInfo & '", em_aucmd ' & sIco & " " & sFunc & auCRLF
j += 1
If j = 30 Then Break
Next
If TrayLog.Count = 0 Then txt &= 'MENUITEM "<Пусто>", em_aucmd' & auCRLF
txt &= 'MENUITEM SEPARATOR' & auCRLF
txt &= 'MENUITEM "Копировать", em_aucmd -1 TrayNotifyCopy' & auCRLF
txt &= 'MENUITEM "Скрыть иконку", em_aucmd -1 NotifyIcon "delete" 1010' & auCRLF
Return txt
EndFunc
Func TrayNotifyItem(nItem, nIco)
Local nFlag
Local sInfo = StrPart(TrayLog[nItem], Chr(0), 2)
Local sText = StrPart(TrayLog[nItem], Chr(0), 3)
Switch nIco
Case 76
nFlag = 64
Case 79
nFlag = 48
Case 93
nFlag = 16
Else
nFlag = ''
EndSwitch
MsgBox(sText, sInfo, nFlag)
EndFunc
Func TrayNotifyCopy()
Local txt = TrayLog.Text
txt = StrReplace(txt, Chr(0), ";")
ClipPut(txt)
ShowTransHint("Скопировано в буфер")
EndFunc
#{
Вызов системных уведомлений:
InfoText - текст уведомления (255 символов)
InfoTitle - текст заголовка уведомления (63 символов)
InfoType - флаги NIIF_* меняющие вид и поведение окна уведомлений
Функция использует идентификатор "1010"
#}
Func NotifyInfoMessage(InfoText, InfoTitle = "Autorun", InfoType = 0)
Local Offset = auX64 ? 40 : 24, sIcon
Static buf = Buffer(auPtrSize = 4 ? 956 : 976)
Static nFlags = BitOR(NIF_MESSAGE, NIF_ICON, NIF_INFO, NIF_TIP)
If FileExist(gNotifyIcon) Then
sIcon = gNotifyIcon
Else
sIcon = COMMANDER_EXE
EndIf
Static hIco = DllCall("shell32\ExtractIconW", _
"ptr", AUTORUN_TCHANDLE, _
"wstr", sIcon, "uint", 0, "ptr")
NotifyIcon("delete", 1010)
buf.Zero()
If auX64 Then
buf.SetNum(0, "dword", buf.size)
buf.SetNum(8, "hwnd", AUTORUN_TCHANDLE)
buf.SetNum(16, "uint", 1010, _
"uint", nFlags, _
"uint", Code1010)
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", nFlags, _
"uint", Code1010, _
"ptr", hIco)
buf.SetNum(280, "dword", 1, _
"dword", 1)
EndIf
buf.SetStr("Notify Messages" & Chr(0), Offset)
buf.SetStr(StrLeft(InfoText, 255) & Chr(0), Offset + 264) # 256 + 4 + 4
Offset += 264
If InfoTitle <> "" Then
buf.SetStr(StrLeft(InfoTitle, 63) & Chr(0), Offset + 516) # 512 + 4
EndIf
Offset += 516
If InfoType > 0 Then
buf.SetNum(Offset + 128, "dword", InfoType) # 128
EndIf
TrayLog.Add(Time() & Chr(0) & InfoTitle & Chr(0) & InfoText & Chr(0) & InfoType)
Tray1010 = 1
Return DllCall("Shell32.dll\Shell_NotifyIconW", "uint", 0, "ptr", buf.ptr)
EndFunc |
Это только сами функции и их вызов. В реальности код разрастается из-за различных условий и проверок. Например, вряд ли есть необходимость всегда держать иконку в трее, а значит надо как-то учитывать это при запуске — считывать ключ из ини-файла, смотреть его значение, загружать или не загружать иконку в зависимости от этого значения и т.д. Именно поэтому модуль получился больше, чем эти две функции, ведь это мой рабочий модуль, т.е. модуль, который я использую у себя в ТС. Кое-что там лишнее и переплетается с другими модулями, поэтому сам модуль не универсальный, универсальны только эти две функции.
Как-то так  |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1024
|
(Separately) Posted: Thu Feb 12, 2026 14:02 Post subject: |
|
|
Внес некоторые изменения в модуль MediaInfo.aucfg.
Раньше была возможность разделить панель на три области, чтобы отображать в каждой области свою подсказку. Теперь при удержании Shift в подсказке также отображаются данные из плагинов, тем самым общее количество подсказок возросло до шести!
Если добавить сюда переключение полей (функция реализована в модуле как SetHintFields, вызывается по Alt+F12), количество подсказок можно увеличивать до беспредела
Однако пока Alt+F12 ограничивается только переключением на ExifHint и JoinHint, при этом JoinHint больше не актульна, хотя может быть использована в качестве примера вывода данных в окно подсказки.
Алгоритм вывода данных из плагинов ранее был реализован в функции JoinHint. Я перенес его в модуль MediaInfo.aucfg и добавил небольшие изменения.
Как это работает. В подсказку выводятся все непустые поля из заранее указанных плагинов в файле WdxHint.cfg. Пример файла:
| Code: | File.wdx;UnicodeTest.wdx;FileX.wdx
Permissions.wdx;NTLinks.wdx;NTFSFileStreams.wdx
anytag.wdx
Script.wdx;WinScriptsAdv.wdx |
Соответственно, первая строка в файле выводит в первую область панели данные из плагинов File.wdx, UnicodeTest.wdx и FileX.wdx. Вторая строка выводит во вторую область панели, а третья в третью. Комбинация плагинов в строке может быть любой. Путь к файлу WdxHint.cfg указывается в глобальной переменной наряду с другими параметрами подсказки MediaInfo:
| Code: | Global gHintPipe = "", _
gHintClipb = true, _
gHintLines = 60, _
gHintWait = 0, _
gHintShift = "duration.txt", _
gHintCaps = true
Global gHintWdx = 0, _
gHintWdxList = List(), _
gHintWdxCfg = COMMANDER_PATH & "\Ini\WdxHint.cfg"
Global gHintLayout = List(10, 75, 15), _
gHintContent = List("size.txt", "Inform", "hint.txt"), _
gHintSleep = List(0, 0, 0) |
Переменные должны быть объявлены в модуле autorun.cfg, желательно сразу после инструкции Pragma AutorunPluginFields, чтобы избежать ошибки инициализации при запуске ТС (об этом подробнее по первой ссылке).
gHintPipe, gHintWdx и gHintWdxList используются для внутренних целей, менять их значения не нужно. Остальных переменные описавались ранее, как и примеры их использования:
 Hidden text gHintClipb - копировать в буфер всю подсказку при отображении в страничном режиме
gHintLines - число строк подсказки, больше 60 быть не может
gHintWait - задержка для всех секций перед отображением
gHintShift - шаблон для смены "на лету", только для левой секции
gHintCaps - если false, подсказка будет отображаться без CapsLock или Ctrl
gHintLayout - размер каждой секции в процентах
gHintContent - шаблон для каждой секции; если пустой "", в секцию ничего не попадает, кроме самой подсказки ТС или проводника; если "Inform" - стандартный отчет MediaInfo; если имя файла, то шаблон из файла (файлы должны находиться в каталоге MediaInfo.dll, существование файла не проверяется, в случае отсутствия сообщений об ошибке не будет, отобразится сырой результат отчета MediaInfo).
gHintSleep - задержка для каждой секции.
Пара примеров.
| Code: | gHintCaps = false
gHintLayout = List(15, 70, 15)
gHintContent = List("Inform", "", "duration.txt")
gHintSleep = List(500, 0, 0) |
Подсказка будет вызываться всегда (CapsLock отключен). Левая секция - 15%, Центр - 70%, Правая секция - 15%. В левой секции стандартный отчет MediaInfo с задержкой 500 млс, в центре ничего не выводится, в правой секции шаблон duration.txt.
| Code: | gHintCaps = true
gHintLayout = List(10, 80, 10)
gHintContent = List("size.txt", "hint.txt", "Inform")
gHintSleep = List(0, 0, 0) |
Подсказка вызывается дополнительно (CapsLock включен). Левая секция - 10%, Центр - 80%, Правая секция - 10%. В левой секции шаблон size.txt, в центре шаблон hint.txt, в правой секции стандартный отчет MediaInfo. Отдельных задержек перед вызовом нет.
Дополнительно шаблон в левой секции может меняться "на лету" с тем, что указан в gHintShift. Комбинация для смены Alt+5.
Кроме Alt+5 действуют еще 4 комбинации: Alt+1..Alt+4. Каждая из этих комбинаций выводит одну страницу последней подсказки и опционально копирует ее в буфер. Такое применение удобно на очень больших подсказках, которые обрезаются на 60-и строках, оставляя одну страницу просмотра. Нажав Alt+2 можно переместиться на вторую страницу и так далее. Всего четыре страницы.
В подсказке используются шаблоны MediaInfo: текстовые файлы с собственной разметкой и синтаксисом. Внося изменения в эти файлы, можно подстраивать под себя вывод из MediaInfo.dll. Сейчас используются три шаблона hint.txt, size.txt и duration.txt, можно создать другие или полностью передлать эти.
 hint.txt General;"Name: %FileName%.%FileExtension%\nSize: %FileSize/String4%\n[Duration: %Duration%]\n[Duration: %Duration/String1%]\n[Duration: %Duration/String5%]\n
[General: %BitRate/String%][(%BitRate_Mode%)][, %Format%]$if(%Cover%,\, Cover)$if(%IsStreamable%,\, Streamable)[, %FrameRate/String%]"\n
Video;Video #%StreamKindID%: [%Width%x%Height%][, %Format%][(%Format/Family%)][, %Language%][, %AspectRatio/String% (%AspectRatio%)][, %Resolution/String%][, %FrameRate/String%][, %BitRate/String%][(%BitRate_Mode%)]\n
Video_Begin;
Video_Middle;
Video_End;\n
Audio;Audio #%StreamKindID%: [%Channel(s)%ch][, %SamplingRate/String%][, %BitRate/String%][ (%BitRate_Mode%)][, %Format%][, %Format_Profile%][, %Language%][, %FrameRate/String%]\n
Audio_Begin;
Audio_Middle;
Audio_End;\n
Text;Text #%StreamKindID%: %Format%[, %Language/String3%][, %StreamSize/String3%][, %BitRate/String%][, %FrameRate/String%][, %SamplingRate/String%]\n
Text_End;\n
Chapters;Chapters #%StreamKindID%: %Total% chapters\n
Image;Image #%StreamKindID%: [%Width%x%Height%pix][, %Format%][, %StreamSize/String5%][, %ColorSpace% (%ChromaSubsampling%)][, %BitDepth/String%][, %ColorSpace_ICC%]\n
Menu;Menu #%StreamKindID%: [%MenuID/String%][, Format:%Format/String%][ Chapters: \[%Chapters_Pos_Begin%-%Chapters_Pos_End%\]]
 size.txt General;Name: %FileName%.%FileExtension%\r\nSize: %FileSize/String4%\r\nGeneral: [%StreamSize/String%]\r\n
Video;Video #%StreamKindID%: [%StreamSize/String%]\r\n
Audio;Audio #%StreamKindID%: %StreamSize/String%[ - %Language/String%][ | %Title%]\r\n
 duration.txt General;Name: %FileName%.%FileExtension%\r\nSize: %FileSize/String4%\r\nGeneral:\r\n [Duration: %Duration%]\r\n [Duration: %Duration/String1%]\r\n [Duration: %Duration/String5%]\r\n
Video;Video #%StreamKindID%: \r\n [Duration: %Duration%]\r\n [Duration: %Duration/String1%]\r\n [Duration: %Duration/String5%]\r\n
Audio;Audio #%StreamKindID%: \r\n [Duration: %Duration%]\r\n [Duration: %Duration/String1%]\r\n [Duration: %Duration/String5%]\r\n
Шаблоны должны находиться в каталоге библиотеки.
Также в файле autorun.cfg самой первой строкой должны быть прописаны поля подсказки в инструкции Pragma AutorunPluginFields:
| Code: | Pragma AutorunPluginFields "C1:::MediaHint" "C2:::MediaHint" "C3:::MediaHint" "C4:::MediaHint" "C5:::MediaHint" "C6:::MediaHint" "C7:::MediaHint" "C8:::MediaHint" "C9:::MediaHint" "C10:::MediaHint" "C11:::MediaHint" "C12:::MediaHint" "C13:::MediaHint" "C14:::MediaHint" "C15:::MediaHint" "C16:::MediaHint" "C17:::MediaHint" "C18:::MediaHint" "C19:::MediaHint" "C20:::MediaHint" "C21:::MediaHint" "C22:::MediaHint" "C23:::MediaHint" "C24:::MediaHint" "C25:::MediaHint" "C26:::MediaHint" "C27:::MediaHint" "C28:::MediaHint" "C29:::MediaHint" "C30:::MediaHint" "C31:::MediaHint" "C32:::MediaHint" "C33:::MediaHint" "C34:::MediaHint" "C35:::MediaHint" "C36:::MediaHint" "C37:::MediaHint" "C38:::MediaHint" "C39:::MediaHint" "C40:::MediaHint" "C41:::MediaHint" "C42:::MediaHint" "C43:::MediaHint" "C44:::MediaHint" "C45:::MediaHint" "C46:::MediaHint" "C47:::MediaHint" "C48:::MediaHint" "C49:::MediaHint" "C50:::MediaHint" "C51:::MediaHint" "C52:::MediaHint" "C53:::MediaHint" "C55:::MediaHint" "C55:::MediaHint" "C56:::MediaHint" "C57:::MediaHint" "C58:::MediaHint" "C59:::MediaHint" "C60:::MediaHint" |
Указанные 60 полей должны быть предварительно добавлены в секцию HintsCustomField основной конфигурации ТС, т.е. в секции должны быть два щаблона *.* по 30 полей каждый, которые должны ее замыкать.
Возможные сценарии.
1) Если в секции нет других расширений. Достаточно просто применить готовый вариант:
 Hidden text | Code: | [HintsCustomField]
0exts=*.*
0fields=[=autorun.C1]\n[=autorun.C2]\n[=autorun.C3]\n[=autorun.C4]\n[=autorun.C5]\n[=autorun.C6]\n[=autorun.C7]\n[=autorun.C8]\n[=autorun.C9]\n[=autorun.C10]\n[=autorun.C11]\n[=autorun.C12]\n[=autorun.C13]\n[=autorun.C14]\n[=autorun.C15]\n[=autorun.C16]\n[=autorun.C17]\n[=autorun.C18]\n[=autorun.C19]\n[=autorun.C20]\n[=autorun.C21]\n[=autorun.C22]\n[=autorun.C23]\n[=autorun.C24]\n[=autorun.C25]\n[=autorun.C26]\n[=autorun.C27]\n[=autorun.C28]\n[=autorun.C29]\n[=autorun.C30]
1exts=*.*
1fields=[=autorun.C31]\n[=autorun.C32]\n[=autorun.C33]\n[=autorun.C34]\n[=autorun.C35]\n[=autorun.C36]\n[=autorun.C37]\n[=autorun.C38]\n[=autorun.C39]\n[=autorun.C40]\n[=autorun.C41]\n[=autorun.C42]\n[=autorun.C43]\n[=autorun.C44]\n[=autorun.C45]\n[=autorun.C46]\n[=autorun.C47]\n[=autorun.C48]\n[=autorun.C49]\n[=autorun.C50]\n[=autorun.C51]\n[=autorun.C52]\n[=autorun.C53]\n[=autorun.C54]\n[=autorun.C55]\n[=autorun.C56]\n[=autorun.C57]\n[=autorun.C58]\n[=autorun.C59]\n[=autorun.C60] |
2) Если в секции есть другие шаблоны и маски. Нужно добавить по последнему номеру, например:
 Hidden text | Code: | [HintsCustomField]
0exts=>NTFS Ссылка
0fields=[=ntlinks.Obj_Type]\n[=ntlinks.Obj_RealPath.Natural]
1exts=*.apk
1fields=Название: [=apk.Application Name ru]\nВерсия: [=apk.Version] ([=apk.Version Code])\nПакет: [=apk.Package]\nAndroid: [=apk.Min SDK Name]
2exts=*.aucfg; autorun.cfg;*.ini;*.ahk; ;*.au3; *.vbs; *.bat; *.ps1
2fields=Число строк: [=linebreakinfo.CRLF Count]\nБайт прочитано: [=linebreakinfo.Bytes Read] |
Ключи в секции заканчиваются вторым номером (0ext-2ext). Новые ключи нужно добавлять с третьего:
| Code: | [HintsCustomField]
0exts=>NTFS Ссылка
0fields=[=ntlinks.Obj_Type]\n[=ntlinks.Obj_RealPath.Natural]
1exts=*.apk
1fields=Название: [=apk.Application Name ru]\nВерсия: [=apk.Version] ([=apk.Version Code])\nПакет: [=apk.Package]\nAndroid: [=apk.Min SDK Name]
2exts=*.aucfg; autorun.cfg;*.ini;*.ahk; ;*.au3; *.vbs; *.bat; *.ps1
2fields=Число строк: [=linebreakinfo.CRLF Count]\nБайт прочитано: [=linebreakinfo.Bytes Read]
3exts=*.*
3fields=[=autorun.C1]\n[=autorun.C2]\n[=autorun.C3]\n[=autorun.C4]\n[=autorun.C5]\n[=autorun.C6]\n[=autorun.C7]\n[=autorun.C8]\n[=autorun.C9]\n[=autorun.C10]\n[=autorun.C11]\n[=autorun.C12]\n[=autorun.C13]\n[=autorun.C14]\n[=autorun.C15]\n[=autorun.C16]\n[=autorun.C17]\n[=autorun.C18]\n[=autorun.C19]\n[=autorun.C20]\n[=autorun.C21]\n[=autorun.C22]\n[=autorun.C23]\n[=autorun.C24]\n[=autorun.C25]\n[=autorun.C26]\n[=autorun.C27]\n[=autorun.C28]\n[=autorun.C29]\n[=autorun.C30]
4exts=*.*
4fields=[=autorun.C31]\n[=autorun.C32]\n[=autorun.C33]\n[=autorun.C34]\n[=autorun.C35]\n[=autorun.C36]\n[=autorun.C37]\n[=autorun.C38]\n[=autorun.C39]\n[=autorun.C40]\n[=autorun.C41]\n[=autorun.C42]\n[=autorun.C43]\n[=autorun.C44]\n[=autorun.C45]\n[=autorun.C46]\n[=autorun.C47]\n[=autorun.C48]\n[=autorun.C49]\n[=autorun.C50]\n[=autorun.C51]\n[=autorun.C52]\n[=autorun.C53]\n[=autorun.C54]\n[=autorun.C55]\n[=autorun.C56]\n[=autorun.C57]\n[=autorun.C58]\n[=autorun.C59]\n[=autorun.C60] |
После добавления полей в секцию, нужно зайти в диалог Настройки -> Содержимое панелей -> Пользовательские и поставить галочку "Объединять все подсказки, подходящие по типу файлов".
Всё. Предварительная часть установки завершена. Осталось подключить модуль.
Модуль подключается стандартно, директивой Pragma Include, в основной конфигурации Autorun:
| Code: | Pragma Include %COMMANDER_PATH%\Ini\Scripts\MediaInfo.aucfg |
После перезапуска ТС альтернативная подсказка из модуля должна отображаться на панелях при наведении курсора мыши на нужный файл с удержанием CTRL или включеном CapsLock. Однако CTRL работает только в 32-битной версии ТС из-за некоторых ограничений.
Окно панели поделится на 3 части: 10% справа, 75% центр, 15% слева. В каждой области отображается своя подсказка из MediaInfo.dll. Удержание Shift переключает отображение на плагины. Поскольку Shift не работает в TCx64, как и CTRL, переключением доступно только через Win+CapsLock. Данная комбинация работает и в TCx32.
Кроме подсказки, в модуле реализована кнопка для подсчета времени воспроизведения у выделенных файлов и каталогов. Код кнопки 71000. Подробнее о функционале здесь
Сам по себе модуль автономный, если не считать манипуляций описанных выше, связанных прежде всего с установкой подсказки в качестве альтернативной. В заголовке модуля требуется только указать корректные пути к библиотеке MediaHint.dll и утилите ExiTool:
 MediaInfo.aucfg | Code: | Pragma IncludeOnce
# 71000-71099
RegisterCommand 71000 "Duration"
RegisterCommand 71010 "MediaInfoTest"
# Alt+F12
SetHotkeyAction /K:A /H:F12 SetHintFields
# Alt+1(..5)
SetHotkeyAction /K:A /H:1 /DM /S ShowPipeEx 0 1
SetHotkeyAction /K:A /H:2 /DM /S ShowPipeEx 0 2
SetHotkeyAction /K:A /H:3 /DM /S ShowPipeEx 0 3
SetHotkeyAction /K:A /H:4 /DM /S ShowPipeEx 0 4
SetHotkeyAction /K:A /H:5 /DM /S LeftsideHintType
# Win+CapsLock
SetHotkeyAction /V:20 /K:W MediaHintType
Global gMediaInfoX32 = COMMANDER_PATH & "\Ini\Tools\Libs\MediaInfo_i386.dll"
Global gMediaInfoX64 = COMMANDER_PATH & "\Ini\Tools\Libs\MediaInfo.dll"
Global gMediaExifX32 = COMMANDER_PATH & "\Plugins\wlx\ExifToolView\exiftool.exe"
Global gDurationInfo = 0, gDurationBreak = false, gDurationBaloon = 1, gDurationTXT
Global gFilterAudio = ".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"
Global gFilterVideo = ".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"
Global gBTipWndProc, gBTipWnd = Map(), gBTip = 0
Global gBText = Buffer(1024*4), gBTool = Buffer(auX64 ? 56 : 40)
Global gBTipX, gBTipY
Global gBTipWP = Callback("BTipWndProc", "hwnd;uint;wparam;lparam")
Func Duration(lParam)
If gDurationInfo > 0 Then
gDurationBreak = true
Sleep(250)
Return
EndIf
If gDurationBaloon Then
gBTip = CreateBaloonTip("MediaInfo", 1, 200)
If gBTip = 0 Then Return MsgBox("Не удалось создать окно подсказки BaloonTip")
EndIf
RunThread DurationInfo
EndFunc
Func DurationInfo()
Local T1 = GetUptime(), T2 = T1
Local bCaps = BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1)
Local bCtrl = IsPressed(0x11), bShift = IsPressed(0x10), bAlt = IsPressed(0x12)
Static sLib = auX64 ? gMediaInfoX64 : gMediaInfoX32
Static hLib = DllCall("LoadLibrary", "wstr", sLib, "ptr")
Static sExt = gFilterAudio & " " & gFilterVideo
If Not bAlt Then
If hLib = 0 Then
ShowMediaHint("Error LoadLibrary " & sLib)
Return
EndIf
Static pNew = DllCall("GetProcAddress", "Ptr", hLib, "Str", "MediaInfo_New", "Ptr")
Static pOpen = DllCall("GetProcAddress", "Ptr", hLib, "Str", "MediaInfo_Open", "Ptr")
Static pGet = DllCall("GetProcAddress", "Ptr", hLib, "Str", "MediaInfo_Get", "Ptr")
Static pDel = DllCall("GetProcAddress", "Ptr", hLib, "Str", "MediaInfo_Delete", "Ptr")
Local hMI = DllCall(pNew, "Ptr")
If hMI = 0 Then
ShowMediaHint("MediaInfo.dll couldn't create new object")
Return
Endif
Else
Local obj = Plugin("TCMediaInfo")
If ERROR <> 0 Then
ShowMediaHint("TCMediaInfo.wdx plugin error " & ERROR)
Return
Endif
EndIf
Local sDuration
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
ShowMediaHint("Файл не существует " & sFile)
Free(aSel)
If bAlt Then Free(obj)
Return
Endif
EndIf
If aSel.Count = 0 And Not StrPos(FileGetAttr(sFile), "D") Then
Free(aSel)
If bAlt Then
obj.FileName = sFile
sDuration = obj.GetValue(0) # duration
Free(obj)
Else
If DllCall(pOpen, "Ptr", hMI, "Wstr", sFile, "Uint") <> 1 Then
Return ShowMediaHint("MediaInfo.dll coudn't open file " & sFile)
EndIf
sDuration = DllCall(pGet, "Ptr", hMI, "Int", 0, "Int", 0, _
"Wstr", "Duration/String3", "Int", 1, "Int", 0, "Wstr")
EndIf
Return ShowMediaHint("Файл: " & sName & auCRLF & "Длительность: " & sDuration, 1)
Endif
gDurationInfo = 1
gDurationBreak = false
ShowMediaHint("Загрузка", 1)
Local i, j, valid = 0
Local dirs = 0, files = 0, errs = 0, item = 0, aFiles = List(), seconds = 0, b_Hint = 0
Local depth = (bCtrl ? 1 : 0), ms = 0, vc, ac
bExtLog = false
# загрузка файлов в массив
If aSel.Count > 0 Then
For j = 0 To aSel.Count - 1
sFile = sPath & aSel[j]
If FileExist(sFile) Then
valid += 1
aFiles.Add(sFile)
If StrPos(FileGetAttr(sFile), "D") Then
If ListMediaFiles(sFile, aFiles, depth) > 0 Then aFiles.Count = 0
EndIf
EndIf
Next
sName = aSel.Count & "/" & valid
Else
aFiles.Add(sFile)
ListMediaFiles(sFile, aFiles, depth)
EndIf
Free(aSel)
If aFiles.Count > 1 Then
ShowMediaHint("Depth: " & depth & auCRLF & _
"Filter: " & (Not bShift ? "Yes" : "No") & auCRLF & _
(bAlt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"Элементов: " & aFiles.Count & auCRLF & _
"Подсчёт времени...", 1)
EndIf
T2 = GetUptime()
DurationLogString("Duration.Name:" & sName)
DurationLogString("Duration.Items:" & aFiles.Count)
For i = 0 To aFiles.Count - 1
If bExtLog Then DurationLogString("Duration.File:" & aFiles[i])
If StrPos(FileGetAttr(aFiles[i]), "D") Then
dirs += 1
If bExtLog Then DurationLogString("Duration.Directory:" & aFiles[i])
Continue
EndIf
item += 1
If bAlt Then
obj.FileName = aFiles[i]
ms = obj.GetValue(0,3) # duration -> milliseconds
Else
ext = FileGetExt(aFiles[i])
If Not bShift Then
If Not StrPos(sExt, '.' & ext) Then
DurationLogString("Duration.Filter:" & aFiles[i])
Continue
EndIf
EndIf
If DllCall(pOpen, "Ptr", hMI, "Wstr", aFiles[i], "Uint") <> 1 Then
errs += 1
DurationLogString("Duration.Error:" & aFiles[i])
Continue
EndIf
ms = DllCall(pGet, "Ptr", hMI, "Int", 0, "Int", 0, _
"Wstr", "Duration", "Int", 1, "Int", 0, "Wstr")
vc = DllCall(pGet, "Ptr", hMI, "Int", 0, "Int", 0, _
"Wstr", "VideoCount", "Int", 1, "Int", 0, "Wstr")
ac = DllCall(pGet, "Ptr", hMI, "Int", 0, "Int", 0, _
"Wstr", "AudioCount", "Int", 1, "Int", 0, "Wstr")
If ms > 0 And vc = "" And ac = "" Then
DurationLogString("Duration.Warning:" & aFiles[i])
Continue
EndIf
EndIf
If ms > 0 Then
seconds += ms
files += 1
Else
DurationLogString("Duration.Empty:" & aFiles[i])
EndIf
If gDurationBreak = true Or (IsPressed (0x11) And IsPressed (0x1B)) Then
ShowMediaHint("Операция прервана", 1)
Sleep(500)
If gDurationBaloon Then
Static buf = Buffer(160)
buf.Zero()
buf.SetStr("Прервано" & Chr(0))
SendMessage(gBTip, 1057, 3, buf.ptr)
EndIf
Break
EndIf
If Round(GetUptime() - T2, 0) > 500 Then
ShowMediaHint("Depth: " & depth & auCRLF & _
"Filter: " & (Not bShift ? "Yes" : "No") & auCRLF & _
(bAlt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"Элементов: " & aFiles.Count & auCRLF & _
"Обработка: " & i & " из " & aFiles.Count, 1)
T2 = GetUptime()
EndIf
Next
If bAlt Then Free(obj)
If Not bAlt And hMI <> 0 Then DllCall(pDel, "Ptr", hMI)
gDurationInfo = 0
gDurationBreak = false
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
Local txt = "Имя: " & 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 " & (bAlt ? "TCMediaInfo.wdx" : "MediaInfo.dll") & auCRLF & _
"Время операции: " & StrFormat("%.3f", tl) & " sec"
DurationLogString(txt & auCRLF & auCRLF)
Free(aFiles)
ClipPut(txt)
ShowMediaHint(txt, 1)
EndFunc
Func ListMediaFiles(sPath, ByRef aList, nDepth = 1)
Local sFile, nAttr
Local ffd = Buffer(604), bEsc = false
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
ListMediaFiles(sPath & "\" & sFile, aList, nDepth - 1)
EndIf
EndIf
Else
aList.Add(sPath & "\" & sFile)
Endif
If DllCall("FindNextFileW", "handle", hf, "ptr", ffd.Ptr) = 0 Then Break
If IsPressed (0x1B) Then
bEsc = true
Break
EndIf
Wend
DllCall("FindClose", "handle", hf)
Endif
Free(ffd)
Return bEsc
EndFunc
Func DurationLogString(LogString)
gDurationTXT &= LogString & auCRLF
EndFunc
Func ShowMediaHint(MediaHint, Persist = false)
# удаление подсказки тотала
If gDurationBaloon And gBTip > 0 Then
Local hTip = WinFind(0, "TToolTip")
If hTip > 0 Then SendMessage(hTip, 0x0010, 0, 0)
UpdateBaloonTip(gBTip, MediaHint)
Return
EndIf
SetHintParam("ShowHint", "Font", 11, "Arial")
#SetHintParam("ShowHint", "BackColor", 0x000000)
#SetHintParam("ShowHint", "Text", 0xFFFFFF)
SetHintParam("ShowHint", "DarkBackColor", 0xFF0000)
SetHintParam("ShowHint", "DarkText", 0xFFFFFF)
If Persist Then
ShowHint(MediaHint)
Else
ShowHint(MediaHint, "", "", 3000, 1)
EndIf
Sleep(10)
SetHintParam("ShowHint", "Reload")
EndFunc
Func MediaInfoTest(lParam)
Local sFile = RequestCopyDataInfo("SP") & RequestCopyDataInfo("SN")
If Not FileExist(sFile) Then
ShowHint("Файл не существует " & sFile)
Return
Endif
If StrPos(FileGetAttr(sFile), "D") Then
ShowHint("Каталог " & sFile)
Return
Endif
Static sLib = auX64 ? gMediaInfoX64 : gMediaInfoX32
Static hLib = DllCall("LoadLibrary", "wstr", sLib, "ptr")
If hLib = 0 Then
ShowHint("Error LoadLibrary " & sLib)
Return
EndIf
Static sPath = FileGetDir(sLib)
Static sLang ="file://" & sPath & "\ru.csv"
Static pNew = DllCall("GetProcAddress", "Ptr", hLib, "Str", "MediaInfo_New", "Ptr")
Static pOpen = DllCall("GetProcAddress", "Ptr", hLib, "Str", "MediaInfo_Open", "Ptr")
Static pGet = DllCall("GetProcAddress", "Ptr", hLib, "Str", "MediaInfo_Get", "Ptr")
Static pDel = DllCall("GetProcAddress", "Ptr", hLib, "Str", "MediaInfo_Delete", "Ptr")
Static pOpt = DllCall("GetProcAddress", "Ptr", hLib, "Str", "MediaInfo_Option", "Ptr")
Static pInfo = DllCall("GetProcAddress", "Ptr", hLib, "Str", "MediaInfo_Inform", "Ptr")
Local hMI = DllCall(pNew, "Ptr")
If hMI = 0 Then
ShowHint("MediaInfo.dll couldn't create new object")
Return
Endif
If DllCall(pOpen, 'ptr', hMI, "wstr", sFile, "uint") <> 1 Then
DllCall(pDel, "Ptr", hMI)
Return ShowHint("MediaInfo.dll couldn't open file " & sFile)
EndIf
Local sMI
sMI &= "Duration: "
sMI &= DllCall(pGet, 'ptr', hMI, "int", 0, "int", 0, "wstr", "Duration", "int", 1, "int", 0, "wstr") & auCRLF
sMI &= "Video: "
sMI &= DllCall(pGet, 'ptr', hMI, "int", 0, "int", 0, "wstr", "VideoCount", "int", 1, "int", 0, "wstr") & auCRLF
sMI &= "Audio: "
sMI &= DllCall(pGet, 'ptr', hMI, "int", 0, "int", 0, "wstr", "AudioCount", "int", 1, "int", 0, "wstr") & auCRLF
sMI &= "Recorded: "
sMI &= DllCall(pGet, 'ptr', hMI, "int", 0, "int", 0, "wstr", "Recorded_Date", "int", 1, "int", 0, "wstr") & auCRLF
sMI &= "Cover: "
sMI &= DllCall(pGet, 'ptr', hMI, "int", 0, "int", 0, "wstr", "Cover", "int", 1, "int", 0, "wstr") & auCRLF
sMI &= "Cover Mime: "
sMI &= DllCall(pGet, 'ptr', hMI, "int", 0, "int", 0, "wstr", "Cover_Mime", "int", 1, "int", 0, "wstr") & auCRLF
sMI &= "Track/Position: "
sMI &= DllCall(pGet, 'ptr', hMI, "int", 0, "int", 0, "wstr", "Track/Position", "int", 1, "int", 0, "wstr")
If IsPressed(0x11) Then
sMI = ""
DllCall(pOpt, "Ptr", hMI, "Wstr", "Complete", "Wstr", "0", "Wstr")
DllCall(pOpt, 'Ptr', hMI, "Wstr", "Language", "Wstr", sLang, "Wstr")
DllCall(pOpt, "Ptr", hMI, "Wstr", "Output", "Wstr", "Inform", "Wstr")
Local lst = List()
lst.Text = DllCall(pInfo, "Ptr", hMI, "Uint", 0, "Wstr")
For line in lst
sMI &= FixSpaces(line) & auCRLF
Next
Free(lst)
EndIf
DllCall(pDel, "Ptr", hMI)
If gDurationBaloon Then
gBTip = CreateBaloonTip("MediaInfo", 1, 300)
If gBTip = 0 Then Return MsgBox("Не удалось создать окно подсказки BaloonTip")
EndIf
If StrTrim(sMI) = "" Then sMI = "нет данных"
ShowMediaHint(sMI)
EndFunc
Func CreateBaloonTip(TipTitle, TipIcon, TipWidth)
Static TTM_TRACKACTIVATE = 1041, _
TTM_TRACKPOSITION = 1042, _
TTM_SETMAXTIPWIDTH = 1048, _
TTM_SETTITLE = 1057, _
TTM_ADDTOOL = 1074
Local hTip
hTip = DllCall("CreateWindowExW", _
"dword", 8, _
"wstr", "tooltips_class32", _
"wstr", "", _
"dword", 0x00000c0, _
"int", 0, "int", 0, "int", 0, "int", 0, _
"handle", AUTORUN_TCHANDLE, _
"handle", 0, "handle", 0, "ptr", 0, "handle")
If hTip = 0 Then Return 0
MouseGetPos("gBTipX","gBTipY")
#gBTipWnd.Set(hTip, MakeInt(gBTipX, gBTipY, 2))
gBTipWndProc = DllCall("SetWindowLong" & (auX64 ? "PtrW" : "W"), _
"hwnd", hTip, "int", -4, "long_ptr", gBTipWP.Ptr, "ptr")
Local buf = Buffer(160)
buf.Zero()
buf.SetStr(TipTitle & Chr(0))
SendMessage(hTip, TTM_SETTITLE, TipIcon, buf.ptr)
gBText.Zero()
gBText.SetStr("Инициализация" & Chr(0))
gBTool.Zero() # TTTOOLINFO
If auX64 Then
gBTool.SetNum(0, "uint", gBTool.size, _
"uint", 0x00a0, _
"hwnd", AUTORUN_TCHANDLE, _
"uint_ptr", 0)
gBTool.SetNum(48, "ptr", gBText.ptr)
Else
gBTool.SetNum(0, "uint", gBTool.size, _
"uint", 0x00a0, _
"hwnd", AUTORUN_TCHANDLE, _
"uint_ptr", 0, _
"long", 0, _
"long", 0, _
"long", 0, _
"long", 0, _
"ptr", 0, _
"ptr", gBText.ptr)
EndIf
SendMessage(hTip, TTM_SETMAXTIPWIDTH, 0, TipWidth)
SendMessage(hTip, TTM_ADDTOOL, 0, gBTool.ptr)
SendMessage(hTip, TTM_TRACKACTIVATE, 1, gBTool.ptr)
SendMessage(hTip, TTM_TRACKPOSITION, 0, MakeInt(gBTipX, gBTipY, 0))
Free(buf)
Return hTip
EndFunc
Func UpdateBaloonTip(hTip, TipText)
Static TTM_UPDATETIPTEXT = 1081
gBText.Zero()
gBText.SetStr(TipText & Chr(0))
SendMessage(gBTip, TTM_UPDATETIPTEXT, 0, gBTool.ptr)
EndFunc
Func BTipWndProcTest(hWnd, uMsg, wParam, lParam)
Static IsDrag = 0, _
MK_LBUTTON = 0x0001, _
WM_MOUSEMOVE = 0x0200, _
WM_LBUTTONDOWN = 0x0201, _
WM_LBUTTONUP = 0x0202, _
TTM_TRACKPOSITION = 1042
Static tx, ty
Switch uMsg
Case WM_LBUTTONDOWN
If IsDrag = 0 Then
MouseGetPos("tx","ty")
If DllCall("DragDetect", "hwnd", hWnd, "int64", MakeInt(ty, tx, 2)) Then
IsDrag = 1
DllCall("SetCapture", "hwnd", hWnd, "hwnd")
EndIf
EndIf
Case WM_LBUTTONUP
If IsDrag = 1 Then
WinGetPos("gBTipX", "gBTipY", "", "", hWnd)
IsDrag = 0
DllCall("ReleaseCapture")
Else
DllCall("DestroyWindow", "handle", hWnd)
EndIf
Case WM_MOUSEMOVE
If IsDrag = 1 And BitAND(wParam, MK_LBUTTON) Then
MouseGetPos("x","y")
SendMessage(hWnd, TTM_TRACKPOSITION, 0, MakeInt(gBTipX+(x-tx), gBTipY+(y-ty), 0))
EndIf
EndSwitch
Return DllCall("CallWindowProcW", _
"ptr", gBTipWndProc, "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
EndFunc
Func BTipWndProc(hWnd, uMsg, wParam, lParam)
Static IsDrag = 0, _
WM_CREATE = 0x0001, _
WM_DESTROY = 0x0002, _
WM_SHOWWINDOW = 0x0018, _
MK_LBUTTON = 0x0001, _
WM_MOUSEMOVE = 0x0200, _
WM_LBUTTONDOWN = 0x0201, _
WM_LBUTTONUP = 0x0202, _
WM_RBUTTONUP = 0x0205, _
TTM_TRACKACTIVATE = 1041, _
TTM_TRACKPOSITION = 1042
Static SM_CXDRAG = 68, _
SM_CYDRAG = 69, _
DragWidth = GetSystemMetrics(SM_CXDRAG), _
DragHeight = GetSystemMetrics(SM_CYDRAG), _
StartX = 0, _
StartY = 0
Local x, y
Static tx, ty, buf = Buffer(8)
Switch uMsg
Case WM_SHOWWINDOW
If wParam = 0 Then DllCall("DestroyWindow", "handle", hWnd)
Case WM_DESTROY
If gDurationInfo Then
gDurationBreak = true
MsgBox("Операция отменена")
Return 0
EndIf
Case WM_LBUTTONDOWN
If IsDrag = 0 Then
buf.Zero()
x = BitAND(lParam, 0xFFFF)
y = BitAND(BitShift(lParam,16), 0xFFFF)
StartX = x
StartY = y
buf.SetNum(0, "int", x, "int", y)
DllCall("ClientToScreen", "hwnd", hWnd, "ptr", buf.ptr)
tx = buf.GetNum(0)
ty = buf.GetNum(4)
IsDrag = 1
DllCall("SetCapture", "hwnd", hWnd, "hwnd")
EndIf
Case WM_LBUTTONUP
If IsDrag = 1 Then
WinGetPos("gBTipX", "gBTipY", "", "", hWnd)
IsDrag = 0
DllCall("ReleaseCapture")
Else
DllCall("DestroyWindow", "handle", hWnd)
EndIf
Case WM_MOUSEMOVE
If IsDrag = 1 And BitAND(wParam, MK_LBUTTON) Then
x = BitAND(lParam, 0xFFFF)
y = BitAND(BitShift(lParam,16), 0xFFFF)
If Abs(x - startX) > DragWidth Or Abs(y - startY) > DragHeight Then
buf.Zero()
buf.SetNum(0, "int", x, "int", y)
DllCall("ClientToScreen", "hwnd", hWnd, "ptr", buf.ptr)
x = buf.GetNum(0)
y = buf.GetNum(4)
SendMessage(hWnd, TTM_TRACKPOSITION, 0, MakeInt(gBTipX+(x-tx), gBTipY+(y-ty), 0))
EndIf
EndIf
Case WM_RBUTTONUP
BTipShowMenu(hWnd)
EndSwitch
Return DllCall("CallWindowProcW", _
"ptr", gBTipWndProc, "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
EndFunc
Func BTipShowMenu(hWnd)
ShowPopupMenu /D /F /I:0 "BTipCreateMenu"
EndFunc
Func BTipCreateMenu()
Local txt
txt &= 'MENUITEM "Лог операций", em_aucmd ' & (gDurationTXT <> "" ? "" : "/D") & ' -1 DurationText' & auCRLF
Return txt
EndFunc
Func DurationText()
Local sLogFile = TEMP & "\duration.txt"
FileWrite(sLogFile, gDurationTXT)
ShellExec(sLogFile)
EndFunc
Func MediaHint(FileName, FieldIndex, UnitIndex)
If FieldIndex > gHintLines Then Return
If StrPos(FileGetAttr(FileName), "D") Then Return ""
Local bCaps = DllCall("GetKeyState", "int", 0x14, "short")
Local bCtrl = BitAND(bCaps, 1), bShift = IsPressed(0x10)
If gHintWdx Then bShift = true
If Not bCtrl then bCtrl = IsPressed (0x11)
If gHintCaps And Not bCtrl Then Return
Static sLib = auX64 ? gMediaInfoX64 : gMediaInfoX32
Static hLib = DllCall("LoadLibrary", "Wstr", sLib, "Ptr")
Static sPath = FileGetDir(sLib) & "\"
Static sLang ="file://" & sPath & "ru.csv", _
sHint ="file://" & sPath & "hint.txt", _
sSize ="file://" & sPath & "size.txt"
Static bLang = true, nWait = 0, _
pNew, pOpen, pDel, pOpt, pInfo
If hLib = 0 And FieldIndex > 1 Then Return
If FieldIndex = 1 Then
If hLib = 0 Then Return "Error LoadLibrary " & sLib
Idx = 0
pNew = DllCall("GetProcAddress", "Ptr", hLib, "Str", "MediaInfo_New", "Ptr")
pOpen = DllCall("GetProcAddress", "Ptr", hLib, "Str", "MediaInfo_Open", "Ptr")
pDel = DllCall("GetProcAddress", "Ptr", hLib, "Str", "MediaInfo_Delete", "Ptr")
pOpt = DllCall("GetProcAddress", "Ptr", hLib, "Str", "MediaInfo_Option", "Ptr")
pInfo = DllCall("GetProcAddress", "Ptr", hLib, "Str", "MediaInfo_Inform", "Ptr")
nWait = 0
bLang = true
sMode = "Inform"
If gHintWait > 0 Then Sleep(gHintWait)
Local x, y, w, nCase = 0
Local hWnd = RequestInfo(ItemAtCursor("panel"))
WinGetPos("", "", "w", "", hWnd)
If w > 0 Then
MouseGetPos("x","y")
Static buf = Buffer(8) # POINT
buf.Zero()
buf.SetNum(0, "long", x, "long", y)
DllCall("ScreenToClient", "hwnd", hWnd, "ptr", buf.ptr)
x = buf.GetNum(0)
Switch Round(x/w*100,0)
Case 0 To gHintLayout[0]-1
nCase = 0
Case gHintLayout[0] To gHintLayout[0]+gHintLayout[1]-1
nCase = 1
Case 100-gHintLayout[2] To 100
nCase = 2
EndSwitch
nWait = gHintSleep[nCase]
sMode = gHintContent[nCase]
EndIf
If bShift Then
If gHintWdxList.Count <= nCase Then
gHintPipe = "" & auCRLF & "Autorun: No data in " & gHintWdxCfg
Return
EndIf
gHintPipe = ""
Static aWdx = List()
aWdx.Count = 0
aWdx.Split(gHintWdxList[nCase], ";")
For i = 0 To aWdx.Count - 1
gHintPipe &= MediaHintWDX(aWdx[i], FileName)
Next
gHintPipe = StrTrim(gHintPipe)
If gHintPipe = "" Then
gHintPipe = "" & auCRLF & "Autorun: No data in " & gHintWdxCfg
Return
EndIf
gHintPipe = "" & auCRLF & gHintPipe
Return
EndIf
If nWait > 0 Then Sleep(nWait)
If sMode = "" Then
gHintPipe = ""
Return
ElseIf sMode <> "Inform" Then
bLang = false
sMode ="file://" & sPath & sMode
EndIf
Local hMI = DllCall(pNew, "Ptr")
If hMI = 0 Then Return "MediaInfo.dll couldn't create new object"
If DllCall(pOpen, 'Ptr', hMI, "Wstr", FileName, "Uint") <> 1 Then
DllCall(pDel, "Ptr", hMI)
Return "MediaInfo.dll couldn't open file " & FileName
EndIf
If bShift Then
DllCall(pOpt, 'Ptr', hMI, "Wstr", "Complete", "Wstr", "1", "Wstr")
Else
DllCall(pOpt, 'Ptr', hMI, "Wstr", "Complete", "Wstr", "0", "Wstr")
EndIf
DllCall(pOpt, "Ptr", hMI, "Wstr", "Output", "Wstr", sMode, "Wstr")
DllCall(pOpt, 'Ptr', hMI, "Wstr", "Language", "Wstr", (Not bLang ? "" : sLang), "Wstr")
gHintPipe = DllCall(pInfo, 'Ptr', hMI, "Uint", 0, "Wstr")
#{
If StrPos(sMode, "hint.txt") Then
gHintPipe = StrReplace(gHintPipe, "DTS HD Master Audio", "DTS-HD MA")
gHintPipe = StrReplace(gHintPipe, "Dolby Digital", "DD")
EndIf
#}
If Not bLang Then gHintPipe = StrReplace(gHintPipe, Chr(32), Chr(160))
DllCall(pOpt, 'Ptr', hMI, "Wstr", "Language", "Wstr", "", "Wstr")
DllCall(pDel, "Ptr", hMI)
Endif
If Not bLang Then Return StrPart(gHintPipe, auCRLF, FieldIndex)
Return FixSpaces(StrPart(gHintPipe, auCRLF, FieldIndex))
EndFunc
Func FixSpaces(String)
Local a, b
If Not StrPos(String, ":") Then Return String
a = StrPart(String, ":", 1)
b = StrPart(String, ":", 2) & StrPart(String, ":", 3)
Return StrTrim(a) & ": " & FixCodePage(StrTrim(b))
EndFunc
Func FixCodePage(String)
Local bUsedRepl
# iso-8859-1 = 28591
DllCall("WideCharToMultiByte", _
"uint", 28591, _
"dword", 0, _
"wstr", String, _
"int", -1, _
"ptr", 0, _
"int", 0, _
"ptr", 0, _
"bool*", @bUsedRepl)
If bUsedRepl Then Return String
Local nSize = StrLen(String)
Local buf = Buffer(nSize)
buf.Zero()
DllCall("WideCharToMultiByte", _
"uint", 28591, _
"dword", 0, _
"wstr", String, _
"int", -1, _
"ptr", buf.ptr, _
"int", nSize, _
"ptr", 0, _
"ptr", 0)
Local fixed = buf.GetStr(0, nSize, "ANSI")
Free(buf)
Return fixed
EndFunc
Func FixCodePageEx(String)
Local bUsedRepl
# iso-8859-1 = 28591
DllCall("WideCharToMultiByte", _
"uint", 28591, _
"dword", 0, _
"wstr", String, _
"int", -1, _
"ptr", 0, _
"int", 0, _
"ptr", 0, _
"bool*", @bUsedRepl)
If bUsedRepl Then Return String
Local nSize = StrLen(String)
Local buf = Buffer(nSize)
buf.Zero()
buf.SetStr(String, 0, nSize, "CP:28591")
Local fixed = buf.GetStr(0, nSize, "ANSI")
Free(buf)
Return fixed
EndFunc
Func ShowPipeEx(lParam, nPage)
Local sPipe, nLines = gHintLines
Local aPipe = List(), j, nSect = 0
Local nEnd = nPage*nLines, nStart = nEnd - nLines
If gHintClipb Then ClipPut(gHintPipe)
aPipe.Text = gHintPipe
For j = 0 To aPipe.Count - 1
If aPipe[j] = "" Then nSect += 1
If (j + 1) >= nStart And (j + 1) <= nEnd Then
sPipe &= StrLeft(FixSpaces(aPipe[j]),84) & auCRLF
EndIf
Next
Free(aPipe)
If sPipe = "" Then sPipe = "Out of range"
ShowHint(StrTrim(sPipe))
#Return -1
EndFunc
Func LeftsideHintType()
Static init = gHintContent[0]
If gHintContent[0] = init Then
gHintContent[0] = gHintShift
Else
gHintContent[0] = init
EndIf
ShowRedInfoHint("Left side is " & gHintContent[0])
EndFunc
Func SetHintFields()
Local i, sHint
Static c = 0, aHints = List("MediaHint", "ExifHint", "JoinHint")
c += 1
If c > 2 Then c = 0
sHint = aHints[c]
For i = 1 to 60
SetFieldsParam("Func", "C" & i, sHint)
Next
ShowRedInfoHint("Поля подсказки " & sHint)
EndFunc
Func ShowRedInfoHint(HintText)
SetHintParam("ShowHint", "Font", 15, "Arial")
SetHintParam("ShowHint", "BackColor", 0xFF0000)
SetHintParam("ShowHint", "Text", 0xFFFFFF)
ShowHint(HintText, 0, 0, 1000, 1)
WinAlign(LAST_HINT_WINDOW)
Sleep(100)
SetHintParam("ShowHint", "Reload")
EndFunc
Func ExifHint(FileName, FieldIndex, UnitIndex)
If FieldIndex > gHintLines Then Return
If StrPos(FileGetAttr(FileName), "D") Then Return
Local bCtrl = BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1)
If Not bCtrl then bCtrl = IsPressed (0x11)
If gHintCaps And Not bCtrl Then Return
If FieldIndex = 1 Then
ProcessExecGetOutput gHintPipe %gMediaExifX32% ' -G -S -lang ru "%FileName%"'
Endif
Return StrPart(gHintPipe, auLF, FieldIndex)
EndFunc
ReadWdxHintCfg()
Func ReadWdxHintCfg()
gHintWdxList.Count = 0
gHintWdxList.LoadFromFile(gHintWdxCfg)
EndFunc
Func MediaHintWDX(WdxName, Filename)
If Not FileExist(Filename) Then
Return auCRLF & auCRLF & "Файл не существует " & Filename
Endif
Local obj = Plugin(WdxName)
If ERROR <> 0 Then
Return auCRLF & auCRLF & "Autorun: " & WdxName & " plugin error " & ERROR
EndIf
Local i, txt, data
obj.FileName = Filename
For i = 0 To obj.FieldCount -1
data = obj.GetValue(i)
If data = "" Then Continue
txt &= obj.FieldName(i) & ": " & data & auCRLF
Next
Free(obj)
txt = StrTrim(txt)
If StrLen(txt) > 0 Then txt = auCRLF & auCRLF & txt
Return txt
EndFunc
Func MediaHintType()
# переключение переменной
gHintWdx = Not gHintWdx
ShowRedInfoHint("WdxHint.cfg " & (gHintWdx ? "включен" : "выключен"))
EndFunc |
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|