Страница 229 из 243

Добавлено: Ср апр 15, 2026 17:02
Orion9
ZiabrevLV
У вас все правильно, что тут добавить.

Разве что, сделать проверку существования библиотеки, если вам это интересно. Такие проверки, как правило, лишними не бывают, и код потом повторять легче.

Например

Код: Выделить всё

IniWrite /R /EV- %COMMANDER_INI% "Configuration" "IconLib" "%COMMANDER_EXE%"

Else

If Not FileExist(COMMANDER_PATH & "\Fileicons.dll") Then 
   MsgBox("Не найден Fileicons.dll")
   Return
Endif
   
iniWrite /R /EV-  %COMMANDER_INI% "Configuration" "IconLib" "%COMMANDER_PATH%\Fileicons.dll" 
AkulaBig писал(а): они не стремительно быстро работают, как плагин ExifToolWDX.
Автор плагина ExifToolWDX, по всей видимости, использует опцию -stay_open. По-крайней мере в Readme.txt об этом неявно говорится.

Код: Выделить всё

ExifTool will be remain in the memory, until TotalCMD is closed.  If TotalCMD is closed unexpected, ExifTool will be need to be ended in Task Manager.
Я, однако, не нашел этому подтверждения. Но может вам тоже стоит попробовать?
[cut]

Код: Выделить всё

Опция -stay_open в ExifTool используется для повышения производительности при обработке большого количества файлов. Она позволяет держать программу запущенной в фоновом режиме, избавляя от затрат времени на загрузку Perl-интерпретатора и библиотек для каждой отдельной команды. 
Как это работает
При использовании этого флага ExifTool переходит в режим ожидания команд из текстового файла. 

    Запуск: Вы запускаете ExifTool с флагом -stay_open True и указываете файл, из которого будут считываться аргументы (обычно через -@ ARGFILE).
    Выполнение: Программа считывает команды из файла. Как только она встречает в файле специальный маркер (по умолчанию -execute), она выполняет накопленный блок команд и возвращается в режим ожидания.
    Завершение: Чтобы закрыть программу, нужно записать в файл команд -stay_open False. 

Основные преимущества

    Скорость: Огромный выигрыш во времени, так как основная задержка ExifTool обычно связана с инициализацией процесса.
    Интеграция: Идеально подходит для GUI-оболочек или скриптов, которым нужно постоянно взаимодействовать с метаданными. 

Пример использования (концептуальный)

    Команда в терминале:
    bash

    exiftool -stay_open True -@ commands.txt

    Используйте код с осторожностью.
    Содержимое commands.txt:
    text

    -filename
    image.jpg
    -execute
    -Artist=Phil Harvey
    image.jpg
    -execute
    -stay_open
    False

    Используйте код с осторожностью.
[/cut]

Добавлено: Ср апр 15, 2026 17:24
AkulaBig
Orion9 писал(а):Но может вам тоже стоит попробовать?
Я все что можно пробовал. Эта опция для нас даже опасна. А прибавки скорости никакой нет.
Остается попробовать последний вариант. Запуск скрипта на au3 из Autorun. Вдруг WinScriptsAdv хоть чуть-чуть скорость крадет. Я здесь не хочу на эту тему писать. Но я там в скрипт au3 включил код на vbs. Освоил такую функция. Прикольненко.

Добавлено: Ср апр 15, 2026 18:14
Orion9
AkulaBig писал(а):Я все что можно пробовал.
А вот так пробовали?
[cut="au3"]

Код: Выделить всё

В AutoIt работа с -stay_open строится аналогично: мы создаем процесс один раз и общаемся с ним через текстовый файл. Для чтения данных (StdOut) в AutoIt удобнее всего использовать встроенную функцию StdoutRead, которая позволяет забирать текст прямо из памяти процесса без создания лишних временных файлов.
Вот полный пример реализации:
autoit

#include <Constants.au3>

; --- Конфигурация ---
Global $sExifPath = "exiftool.exe" ; Путь к exiftool
Global $sArgFile = @TempDir & "\exiftool_args.txt"

; 1. Подготовка файла аргументов
FileDelete($sArgFile)
FileWrite($sArgFile, "")

; 2. Запуск процесса ExifTool (один раз)
; Используем $STDIN_CHILD + $STDOUT_CHILD для взаимодействия
Global $iPID = Run($sExifPath & ' -stay_open True -@ "' & $sArgFile & '"', "", @SW_HIDE, $STDIN_CHILD + $STDOUT_CHILD)

; --- Примеры использования ---

; Читаем модель камеры
$sModel = _ExifTool_GetTag("photo.jpg", "Model")
MsgBox(64, "Результат", "Модель камеры: " & $sModel)

; Читаем дату создания
$sDate = _ExifTool_GetTag("photo.jpg", "CreateDate")
MsgBox(64, "Результат", "Дата создания: " & $sDate)

; Закрываем ExifTool
_ExifTool_Quit()


; --- Функция получения данных ---
Func _ExifTool_GetTag($sFile, $sTag)
    ; Очищаем буфер перед командой (на всякий случай)
    StdoutRead($iPID)

    ; Формируем команду
    ; -s3: только значение, -S: краткий формат, -echo4: выводит маркер в StdOut после завершения
    Local $sCmd = "-s3" & @LF & "-" & $sTag & @LF & $sFile & @LF & "-echo4" & @LF & "{ready}" & @LF & "-execute" & @LF
    
    ; Записываем команду в файл аргументов
    Local $hFile = FileOpen($sArgFile, 1) ; 1 = Write mode (append)
    FileWrite($hFile, $sCmd)
    FileClose($hFile)

    ; Ждем ответа в StdOut
    Local $sOut = ""
    Local $iTimer = TimerInit()
    
    While 1
        $sOut &= StdoutRead($iPID)
        If StringInStr($sOut, "{ready}") Then ExitLoop ; Ищем наш маркер завершения
        If TimerDiff($iTimer) > 2000 Then Return "Error: Timeout" ; Таймаут 2 сек
        Sleep(10)
    WEnd

    ; Очищаем результат от маркера и лишних пробелов
    $sOut = StringReplace($sOut, "{ready}", "")
    Return StringStripWS($sOut, 3)
EndFunc

; --- Функция закрытия ---
Func _ExifTool_Quit()
    Local $hFile = FileOpen($sArgFile, 1)
    FileWrite($hFile, "-stay_open" & @LF & "False" & @LF)
    FileClose($hFile)
    ProcessWaitClose($iPID, 2)
    FileDelete($sArgFile)
EndFunc

Используйте код с осторожностью.
Ключевые моменты этого примера:

    -echo4 {ready}: ExifTool выводит этот текст в поток Standard Output сразу после того, как команда выполнена. Это позволяет AutoIt понять, что данные получены полностью и можно двигаться дальше.
    StdoutRead: Данные попадают из консоли ExifTool прямо в переменную $sOut.
    @LF: ExifTool в файле аргументов требует, чтобы каждый параметр был на новой строке.
    Производительность: Поскольку процесс не перезапускается, чтение каждого последующего тега происходит почти мгновенно (миллисекунды).

Хотите ли вы дополнить скрипт функцией записи метаданных (например, массовой простановки копирайта)?
ИИ может ошибаться. Советуем проверять его ответы.
[/cut]
[cut="vbs"]

Код: Выделить всё

В VBScript работа с -stay_open является наиболее сложной, так как этот язык не имеет встроенных средств для прямой работы со стандартными потоками (StdIn/StdOut) уже запущенного процесса так же гибко, как AutoIt или AHK.
Наиболее надежный способ для VBScript — общение через два файла: один для команд (argfile), второй для вывода (output).
Полный пример (VBScript)
vbscript

Option Explicit

Dim fso, shell, argFile, outFile, exifPath
Set fso = CreateObject("Scripting.FileSystemObject")
Set shell = CreateObject("WScript.Shell")

' --- Конфигурация ---
exifPath = "exiftool.exe" ' Путь к exiftool
argFile  = fso.GetSpecialFolder(2) & "\exiftool_args.txt" ' Временная папка
outFile  = fso.GetSpecialFolder(2) & "\exiftool_out.txt"

' 1. Подготовка файлов
If fso.FileExists(argFile) Then fso.DeleteFile(argFile)
If fso.FileExists(outFile) Then fso.DeleteFile(outFile)
fso.CreateTextFile(argFile).Close

' 2. Запуск процесса ExifTool (один раз)
' Процесс будет ждать появления команд в argFile
shell.Run Chr(34) & exifPath & Chr(34) & " -stay_open True -@ " & Chr(34) & argFile & Chr(34), 0, False

' --- Примеры использования ---

MsgBox "Модель камеры: " & GetExifTag("photo.jpg", "Model")
MsgBox "Дата съемки: " & GetExifTag("photo.jpg", "CreateDate")

' Завершение работы
QuitExifTool

' --- Функции ---

Function GetExifTag(fileName, tagName)
    Dim stream, result
    
    ' Если файл вывода существует, удаляем его перед новой командой
    If fso.FileExists(outFile) Then fso.DeleteFile(outFile)
    
    ' Формируем блок команд
    ' -s3 (только значение), -w! (записать вывод в файл и перезаписать его)
    Set stream = fso.OpenTextFile(argFile, 8) ' 8 = Append
    stream.WriteLine "-s3"
    stream.WriteLine "-" & tagName
    stream.WriteLine fileName
    stream.WriteLine "-w!"
    stream.WriteLine outFile
    stream.WriteLine "-execute"
    stream.Close
    
    ' Ожидаем появления файла с результатом (цикл ожидания)
    Dim timeout
    timeout = 0
    Do While Not fso.FileExists(outFile) And timeout < 200 ' 2 секунды таймаут
        WScript.Sleep 10
        timeout = timeout + 1
    Loop
    
    If fso.FileExists(outFile) Then
        Set stream = fso.OpenTextFile(outFile, 1)
        If Not stream.AtEndOfStream Then
            result = Trim(stream.ReadAll)
        Else
            result = "Empty"
        End If
        stream.Close
        GetExifTag = result
    Else
        GetExifTag = "Error: Timeout"
    End If
End Function

Sub QuitExifTool()
    Dim stream
    Set stream = fso.OpenTextFile(argFile, 8)
    stream.WriteLine "-stay_open"
    stream.WriteLine "False"
    stream.Close
    WScript.Sleep 500 ' Даем время на закрытие
    If fso.FileExists(argFile) Then fso.DeleteFile(argFile)
    If fso.FileExists(outFile) Then fso.DeleteFile(outFile)
End Sub

Используйте код с осторожностью.
Разбор особенностей для VBScript:

    Chr(34): Используется для вставки кавычек в строку пути, чтобы скрипт не "ломался" на пробелах в путях к файлам.
    shell.Run ..., 0, False: Запускает ExifTool скрыто (0) и не ждет его завершения (False), так как процесс должен работать параллельно со скриптом.
    fso.OpenTextFile(argFile, 8): Режим 8 (Append) критически важен. Мы постоянно дописываем новые инструкции в конец файла, а ExifTool считывает их по мере поступления после маркера -execute.
    Синхронизация через файл: Поскольку VBScript не умеет эффективно слушать поток StdOut в реальном времени без блокировки, мы заставляем ExifTool записывать результат в outFile с помощью ключа -w!. Как только файл появился на диске — данные готовы.

Нужно ли добавить в пример обработку сразу нескольких файлов (массовое чтение) для еще большей скорости?
[/cut]
[cut="aucfg"]Сейчас с болваном можно что угодно пробовать, разве что с Autorun он не умеет работать. Ну ничего... Loopback вернется — научит :)[/cut]

Добавлено: Ср апр 15, 2026 19:10
AkulaBig
Orion9 писал(а):А вот так пробовали?
Не, так не пробовал. Оказывается еще файл надо создавать. Я просто включал эту опцию. Видимо из-за этого глюки были. Может быть будет время, попробую. Сейчас-бы понять почему один и тот-же код работает по разному. А потом уж в дебри лезть.

Добавлено: Ср апр 15, 2026 22:19
AkulaBig
Orion9
Закончил тестирование с запуском скрипта через Ауторан. Не учел, что ShellExec работает везде одинаково. То-есть результат можно получить только через буфер обмена и только через задержку. Остается только -stay_open потестить

Добавлено: Ср апр 15, 2026 23:17
Orion9
Похоже, недооценил я болвана. Оказывается, он уже умеет работать с Autorun, хотя с большими ограничениями. Но все-равно прикольно.

[cut="Autorun"]

Код: Выделить всё

В контексте Total Commander под «Autorun» чаще всего подразумевается плагин Autorun. Он использует собственный скриптовый язык для автоматизации действий при запуске и работе TC.
Ниже приведен полный пример конфига Autorun.cfg, который запускает ExifTool в режиме -stay_open при старте Total Commander и корректно закрывает его при выходе.
Полный пример Autorun.cfg
Этот файл должен находиться в папке с плагином (обычно %COMMANDER_PATH%\Plugins\wlx\Autorun\).
autoscale

; =========================================================
; Автозапуск ExifTool в режиме -stay_open для Total Commander
; =========================================================

; 1. Определяем пути (используем внутренние переменные TC)
Set EXIFTOOL_PATH %COMMANDER_PATH%\Utils\ExifTool\exiftool.exe
Set ARG_FILE %COMMANDER_PATH%\Utils\ExifTool\exiftool_args.txt

; 2. Очищаем файл аргументов при старте, если он остался
ShellExec /SW_HIDE /WAIT %COMSPEC% "/c break > ""%ARG_FILE%"""

; 3. Запускаем ExifTool в фоновом режиме
; Он будет висеть в памяти и ждать команд из ARG_FILE
ShellExec /SW_HIDE "%EXIFTOOL_PATH%" "-stay_open True -@ ""%ARG_FILE%"""

; 4. (Опционально) Добавляем команду в пользовательское меню TC через скрипт
; Здесь можно прописать дополнительные действия, например, переменные окружения

; 5. Регистрация события на ВЫХОД из Total Commander
; Чтобы не оставлять "зомби-процесс" в памяти
Pragma Events ExitingTC

Func ExitingTC
    ; Записываем команду закрытия в файл аргументов
    ; В Autorun.cfg запись в файл удобнее делать через cmd
    ShellExec /SW_HIDE %COMSPEC% "/c echo -stay_open > ""%ARG_FILE%"" && echo False >> ""%ARG_FILE%"""
EndFunc

Используйте код с осторожностью.
Как это работает:

    Set: Создает внутренние переменные для удобства. %COMMANDER_PATH% — это корень вашего Total Commander.
    ShellExec /SW_HIDE: Запускает процесс абсолютно скрыто, чтобы консольное окно не мелькало перед глазами.
    %COMSPEC% /c break > ...: Это системная команда для создания пустого файла или его очистки.
    Pragma Events ExitingTC: Ключевая фишка плагина Autorun. Она заставляет плагин выполнить функцию ExitingTC ровно в тот момент, когда вы нажимаете "крестик" в Total Commander.
    Завершение: Мы отправляем -stay_open False в файл, и ExifTool сам корректно завершает свою работу.

Как использовать этот процесс из кнопок TC?
Теперь, когда процесс уже запущен плагином, вы можете создать кнопку на панели TC для мгновенного выполнения действий:

    Команда: cmd.exe
    Параметры: /c echo -Artist="MyName" >> "%%COMMANDER_PATH%%\Utils\ExifTool\exiftool_args.txt" && echo %N >> "%%COMMANDER_PATH%%\Utils\ExifTool\exiftool_args.txt" && echo -execute >> "%%COMMANDER_PATH%%\Utils\ExifTool\exiftool_args.txt"
    Иконка: exiftool.exe

Нужно ли пояснить, как настроить автоматическую передачу списка всех выделенных файлов в этот запущенный процесс?

Чтобы эффективно передать список всех выделенных файлов из Total Commander в уже запущенный через Autorun процесс ExifTool, лучше всего использовать промежуточный скрипт (VBScript или Batch), так как сама кнопка TC не умеет циклом записывать строки в файл.
Самый быстрый и надежный способ — создать Batch-файл, который переформатирует список файлов %L (временный файл со списком выделенного) в формат, понятный ExifTool.
1. Создаем управляющий Batch-скрипт (et_send.bat)
Сохраните этот код в файл, например, в папку с ExifTool:
batch

@echo off
set "ARG_FILE=%COMMANDER_PATH%\Utils\ExifTool\exiftool_args.txt"

:: Проверяем, переданы ли параметры
if "%~1"=="" exit

:: Записываем параметры команды (например, -Artist="Name")
:: Мы будем передавать их как первый аргумент скрипта
echo %~2 >> "%ARG_FILE%"

:: Читаем файл списка %L, который передает Total Commander
:: И записываем каждый путь в arg-файл для ExifTool
for /f "usebackq delims=" %%a in ("%~1") do (
    echo %%a >> "%ARG_FILE%"
)

:: Отправляем команду на выполнение
echo -execute >> "%ARG_FILE%"

Используйте код с осторожностью.
2. Настраиваем кнопку в Total Commander
Создайте новую кнопку на панели инструментов:

    Команда: путь\к\вашему\et_send.bat
    Параметры: %L "-Artist=My Property"
        %L — это критический параметр TC, он создаст временный файл со списком всех выделенных файлов и передаст путь к этому списку в скрипт.
        "-Artist=My Property" — это сама команда для ExifTool (можно менять на любые другие теги).
    Иконка: exiftool.exe
    Запуск в свернутом виде: Поставьте галочку (чтобы не мелькало окно консоли).

Как это работает в связке:

    Autorun запустил «вечный» процесс ExifTool при старте TC.
    Вы выделяете 100 фотографий и нажимаете кнопку.
    Скрипт et_send.bat мгновенно берет список этих 100 файлов и дописывает их в exiftool_args.txt.
    В конце дописывается -execute.
    ExifTool (который уже в памяти) видит обновление файла, мгновенно обрабатывает все 100 файлов и снова переходит в режим ожидания.

Почему это лучше обычных кнопок?
Если запускать ExifTool обычным способом на 100 файлов через %L, TC создаст 100 процессов или один тяжелый процесс с огромной командной строкой. Метод -stay_open через Autorun делает это в 10-50 раз быстрее, так как программа не тратит время на запуск.
[/cut]
[cut="ProcessExecGetOutput"]

Код: Выделить всё

В плагине Autorun для Total Commander функция ProcessExecGetOutput является частью дополнительного расширения Process (входящего в состав пакета системных функций плагина). Она позволяет запустить внешнюю программу и сразу перехватить её консольный вывод в переменную скрипта.
Однако важно помнить: при использовании -stay_open процесс ExifTool не завершается, поэтому ProcessExecGetOutput будет «висеть» в ожидании, пока вы не закроете ExifTool.
1. Как использовать ProcessExecGetOutput (Разовый запуск)
Если вам нужно просто получить данные один раз (без фонового режима), используйте такой синтаксис:
autoscale

; Загружаем библиотеку для работы с процессами (обязательно!)
LoadLibrary Plugins\Process.dll

; Выполняем команду и записываем результат в переменную ModelName
; Параметр -s3 в ExifTool выводит только «чистое» значение тега
Set ModelName ProcessExecGetOutput("%COMMANDER_PATH%\Utils\ExifTool\exiftool.exe", "-s3 -Model ""photo.jpg""")

; Выводим результат пользователю
MsgBox "Модель камеры: %ModelName%"

Используйте код с осторожностью.
2. Особенности для фонового режима (-stay_open)
Как упоминалось ранее, ProcessExecGetOutput не подходит для чтения данных из уже запущенного фонового процесса. Для этого в Autorun используется связка с временным файлом.
Полная схема «Запрос — Чтение» в Autorun.cfg:
autoscale

LoadLibrary Plugins\Process.dll

; --- Настройка путей ---
Set ET_EXE "%COMMANDER_PATH%\Utils\ExifTool\exiftool.exe"
Set ET_ARGS "%COMMANDER_PATH%\Utils\ExifTool\args.txt"
Set ET_OUT "%COMMANDER_PATH%\Utils\ExifTool\out.txt"

; --- Функция получения тега из фонового процесса ---
Func GetTag(FilePath, Tag)
    ; 1. Удаляем старый файл вывода
    ShellExec /SW_HIDE /WAIT %COMSPEC% "/c if exist ""%ET_OUT%"" del ""%ET_OUT%"""
    
    ; 2. Записываем команды в arg-файл (ExifTool запишет результат в ET_OUT)
    ShellExec /SW_HIDE %COMSPEC% "/c echo -s3 >> ""%ET_ARGS%"" && echo -%Tag% >> ""%ET_ARGS%"" && echo %FilePath% >> ""%ET_ARGS%"" && echo -w! >> ""%ET_ARGS%"" && echo %ET_OUT% >> ""%ET_ARGS%"" && echo -execute >> ""%ET_ARGS%"""
    
    ; 3. Ждем, пока ExifTool создаст файл (цикл ожидания)
    Set WaitCount 0
    While not FileExist("%ET_OUT%")
        Sleep 50
        Set WaitCount %WaitCount% + 1
        if %WaitCount% > 20 then Break ; Таймаут 1 сек
    Wend
    
    ; 4. Читаем результат в переменную
    Set TagValue ReadFile("%ET_OUT%")
    Return %TagValue%
EndFunc

; --- Пример вызова ---
Set MyResult GetTag("C:\Images\test.jpg", "Artist")
MsgBox "Автор: %MyResult%"

Используйте код с осторожностью.
Важные команды плагина Process:

    ProcessExist(name): Проверяет, запущен ли процесс (вернет 1 или 0). Полезно проверять перед отправкой команд.
    ProcessTerminate(name): Принудительно завершает процесс по имени.
    ProcessCount(name): Считает количество запущенных копий программы.
[/cut]
Ограничения. Видно, что код ИИ использует старую версию плагина, в которой командная запись была главной и чаще всего единственно возможной. Похоже, источником информации для ИИ является форум Гислера и те небольшие данные о работе плагина, которые он берет только оттуда. Этот форум он не анализирует, а жаль. Современный Autorun далеко уже ушел.

AkulaBig, а вы упорно хотите добить ExifTool :) Думаю, автору плагина результаты ваших тестов будут, как минимум, интересны.

Добавлено спустя 10 минут:

P.s.
Болван писал(а):Pragma Events ExitingTC: Ключевая фишка плагина Autorun. Она заставляет плагин выполнить функцию ExitingTC ровно в тот момент, когда вы нажимаете "крестик" в Total Commander.
Закат под стол

Добавлено: Чт апр 16, 2026 04:53
AkulaBig
Orion9 писал(а):а вы упорно хотите добить ExifTool
Ну свойства документов у меня уже начисто сделаны. То-есть независимо от того, смогу увеличить скорость обработки или нет, exiftool будет использоваться. Потом для изображений без него не обойтись и т.д. То-есть у ExifTool есть поля, которые другие плагины не показывают. Например, для документов я заменил 4 плагина на ExifTool. С учетом, что ExifTool обновляется, а плагины не обновляются, выбор очевиден.

Добавлено: Чт апр 16, 2026 16:13
AkulaBig
Orion9
Начал внимательно изучать код с -stay_open. Сразу стало понятно, что варианты на au3, vbs отпадают. Для пользовательских колонок функции ExifTool_Quit() просто не может быть.
Сейчас попытаюсь реализовать вариант для Ауторан. Хотя есть большие сомнения, что это можно использовать из-за того, что ExifTool запускается со стартом ТС. Но хочу увидеть скорость работы этого варианта.

Добавлено: Чт апр 16, 2026 21:21
AkulaBig
Orion9
Код из ProcessExecGetOutput нормально запустить не смог. Но судя по тому, что смог запустить, стандартное поведение Ауторан. Сначала висит некоторое время, потом выводит данные.

Добавлено: Чт апр 16, 2026 23:33
Orion9
AkulaBig писал(а):Хотя есть большие сомнения, что это можно использовать из-за того, что ExifTool запускается со стартом ТС.
Хорошая новость в том, что не надо потом думать, как закрыть процесс при завершении работы ТС. Ключ /TT сам это делает.

Для запуска должен быть, конечно, триггер, запускать ExifTool со стартом ТС не годится. Вам придется придумать такой триггер.

Мне было проще, поскольку я взял за пример свою подсказку ExifTool. Поля подсказки активируются по Alt+F12, соответственно, это и служит триггером. Следующая смена полей (подсказки) позволяеет выгрузить ExifTool по PID, который уже известен.

[cut]

Код: Выделить всё

Global gExifPID = 0, gExifStay = 1, gExifOut = TEMP & "\exiftool_out.txt", gExifArgs = TEMP & "\exiftool_args.txt"

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)
    If c = 1 Then
       If gExifStay Then
          FileWrite(gExifArgs, "", "UTF-8 NOBOM")       
          ShellExec /TT /SW_HIDE %gMediaExifX32% "-stay_open True -@ ""%gExifArgs%""" 
          gExifPID = ProcessGetId("exiftool.exe") 
          If gExifPID = 0 Then MsgBox("Процесс ExifTool не запущен")
       EndIf          
    Else
       If gExifPID > 0 Then ProcessTerminate("~/TT",gExifPID)
    EndIf   
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 /C:65001 gHintPipe %gMediaExifX32% ' -G -S -lang ru "%FileName%"'      
       gHintPipe = GetExifInfo(FileName)
    Endif     
    Return StrPart(gHintPipe, auLF, FieldIndex)
EndFunc

Func GetExifInfo(FileName)
    Static a = List(), u = List()
    Local ansi, utf8, wrong = Chr(0xFFFD)
    If Not gExifStay Then
       ProcessExecGetOutput ansi %gMediaExifX32% ' -charset filename=utf8 -G -S -lang ru "%FileName%"'
    Else   
       If FileExist(gExifOut) Then
          ShellExec /SW_HIDE %COMSPEC% '/c del /f /q "%gExifOut%"'
       EndIf
       Local sArgs = "-W+!" & auCRLF & gExifOut & auCRLF & FileName & auCRLF & "-execute" & auCRLF
       Local obj = BinaryFile(gExifArgs, "a")    
       obj.WriteStr(sArgs, "", "UTF-8")
       Free(obj)
       ansi = "<time-out>"
       For i = 1 To 50
           If FileExist(gExifOut) Then
              ansi = FileRead(gExifOut)
              ShellExec /SW_HIDE %COMSPEC% '/c del /f /q "%gExifOut%"'
              Break
           EndIf
           Sleep(20)   # time-out
       Next
    EndIf   
    Local nSize = StrLen(ansi)
    Local buf = Buffer(nSize)
    buf.Zero()
    buf.SetStr(ansi, 0, nSize, "ANSI")
    utf8 = buf.GetStr(0, nSize, "CP:65001")    
    Free(buf)
    a.Count = 0    
    u.Count = 0     
    a.Text = ansi   
    u.Text = utf8
    For i = 0 to u.Count - 1
       If StrPos(u[i], wrong) Then u[i] = a[i]
    Next
    Return u.text    
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
[/cut]

Код из модуля MediaInfo.aucfg, это самая его концовка. Можно подключить к модулю из сборки и проверить его работу. Но можно, конечно, не подключать, а просто посмотреть алгоритм и реализацию.

Скорость, конечно, взлетела. Не обманул болван :) Я проверял на 10 полях из 60 возможных (те самые C1-C60), работает очень быстро.

Сейчас нет возможности расписать все в деталях, но может быть вам это и не нужно. Оставлю только поля для колонок, чтобы вручную их не делать самостоятельно

Код: Выделить всё

Widths32=80,30,30,30,30,30,30,30,30,30,30,30,30
Headers32=C1\nC2\nC3\nC4\nC5\nC6\nC7\nC8\nC9\nC10\nC11
Contents32=[=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]
Options32=-1|0|96

Добавлено: Пт апр 17, 2026 06:42
AkulaBig
Orion9 писал(а):Для запуска должен быть, конечно, триггер, запускать ExifTool со стартом ТС не годится.
Но для тестирования-то нормальное решение. Которое ничего не дало. Вся проблема в том, что любой вариант использования Ауторан работает одинаково. Очень долгая пауза, во время которой ТС висит. Потом выдача данных. При этом передвижение по панелям ТС практически неваозможно.
Позже запишу гифку, чтобы понятнее было.

Добавлено: Пт апр 17, 2026 11:25
AkulaBig
Orion9
Вот я натестировал сегодня. Дело в том, что некоторые документы очень тяжелые. Видимо из-за количества метаданных. К ним относятся некоторые djvu, pdf. И оказалось, что при полноценном тестировании на всех своих тестовых файлах плагин ExifToolWDX также, как и Ауторан, сдох. Также сначала ничего не происходит, потом появляется инфа. Правда в отлиичии от Ауторан он не вешает ТС. А мое решение работает быстрей всего.
Вот что значит неправильное тестирование.
DocsExifToolWDX:
Изображение
Autorun работает практически также. Не стал подключать для тестирования. У меня там и код непричесанный. Только одно поле обработано. И с крякозябрами не все решено.
А вот WinScriptsAdv:
Изображение
Просто летает. Наверное есть смысл и со -stay_open этот вариант прогнать. Вдруг еще побыстрей будет. Триггер конечно навряд ли можно придумать для такого. Ладно это будет следующий этап, если окажется, что смысл есть.

Добавлено: Пт апр 17, 2026 11:50
Orion9
Позже запишу гифку, чтобы понятнее было
Вызывать exiftool.exe для каждого файла - медленно, это понятно. По этой причине вы и хотели ускориться. Опция -stay_open позволяет это сделать, т.к. процесс ExifTool запускается только один раз, а дальнейшее общение с ним происходит через файл параметров, который указывается в опции -@. Как только новые параметры появляются в этом файле с маркером -execute, ExifTool их выполняет. Результат передается либо в stdout, либо во внешний файл. Поскольку ProcessExecGetOutput в Autorun ждет завершения процесса, прежде чем предать полученные данные назад в плагин (о чем, кстати, неплохо написал ИИ), придется использовать только второй вариант с созданием временного файла.

Фрагмент из модуля может показаться большим, но нужного кода там мало, буквально 20 строк.

Запуск ExifTool и создание файла параметров во временном каталоге

Код: Выделить всё

If gExifStay Then
   FileWrite(gExifArgs, "", "UTF-8 NOBOM")       
   ShellExec /TT /SW_HIDE %gMediaExifX32% "-stay_open True -@ ""%gExifArgs%""" 
   gExifPID = ProcessGetId("exiftool.exe") 
   If gExifPID = 0 Then MsgBox("Процесс ExifTool не запущен")
EndIf
Основное тело. Временный файл (для вывода ExifTool) удаляется. Файл параметров заполняется с маркером -execute. Далее код ожидает появление нового временного файла с выводом ExifTool, и как только он появляется, данные с него считываются и, собственно, дальше передаются для обработки и вывода подсказки. Здесь я добавил параметры "-g1" и "-lang ru", чтобы вывод был такой же, как в wlx плагине от Progman13.

Код: Выделить всё

If FileExist(gExifOut) Then
   ShellExec /SW_HIDE %COMSPEC% '/c del /f /q "%gExifOut%"'
EndIf
#Local sArgs = "-W+!" & auCRLF & gExifOut & auCRLF & FileName & auCRLF & "-execute" & auCRLF
Local sArgs = "-g1"   & auCRLF & _
              "-lang" & auCRLF & _
              "ru"    & auCRLF & _                     
              "-W+!"  & auCRLF & gExifOut & auCRLF & FileName & auCRLF & "-execute" & auCRLF       
Local obj = BinaryFile(gExifArgs, "a")    
obj.WriteStr(sArgs, "", "UTF-8")
Free(obj)
ansi = "<time-out>"
For i = 1 To 50
    If FileExist(gExifOut) Then
       ansi = FileRead(gExifOut)
       ShellExec /SW_HIDE %COMSPEC% '/c del /f /q "%gExifOut%"'
       Break
    EndIf
    Sleep(20)   # time-out
Next
EndIf   
Скорость - космос. Пока не знаю, ближний это космос или дальний, но то, что космос, однозначно :)

Добавлено: Ср апр 29, 2026 16:57
FallenAngel
Помогите с кнопочкой. Переключает (и тут же применяет):
icon size: 16x16 <>24x24
на панели size 25 <> 32
на панели small icons 16 <> 24

Т.е. нажал - переключились три параметра, нажал еще раз - вернулось как было.

Изображение

Добавлено: Ср апр 29, 2026 18:49
Orion9
FallenAngel писал(а):Т.е. нажал - переключились три параметра, нажал еще раз - вернулось как было.
К сожалению, это не так просто сделать, как может показаться. Все эти параметры привязаны к разрешению и DPI — потребуются сложные алгоритмы для чтения и записи ключей в файл конфигурации. Вряд ли оно того стоит.

[cut="Iconsize32"][%Screen_Resolution%]
Iconsize32=16

Wincmd.ini Version: 3.00

Определяет размер значков (в пикселях) для файловых панелей, а также для выпадающего списка в цепочках навигации и для списка в диалоге "Соединение с FTP-сервером".

По умолчанию: 16 (в списке на странице настроек "Значки" отображается как 16x16).

ПРИМЕЧАНИЯ:

Изменение этого ключа приводит к автоматической коррекции высоты строк в соответствующем списке. Опция остаётся доступной, даже если значки в файловых панелях отключены (Showicons=0), в этом случае она просто определяет высоту строк в файловом списке. Аналогичным образом ключ влияет на высоту строк в не содержащем значки окне "Дерево каталогов" (ALT+F10).

Минимальный размер места, отведённого для значков в файловых панелях, может зависеть от дополнительных отступов, задаваемых ключами MinLineHeight и MinIconWidth.

В режиме эскизов для тех файлов, у которых вместо эскизов отображаются значки, их размер регулируется отдельным ключом ThumbIconSize.

В 16-битных версиях TC (по 6.58 включительно) использовался аналогичный по назначению ключ Iconsize, где размер значка указывался в пунктах (в оригинальной английской справке он упоминается и сейчас, но не включён в русскую справку и в базу данных Configuration Editor по причине полной бесполезности в любых 32- и 64-битных версиях TC).

Для работы на нескольких мониторах с различным масштабированием дополнительно используются ключи вида Iconsize32_<DPI> (см. описание Iconsize32_96) и Iconsize32_dpi.

Пояснения по именам секций, зависящих от экранного разрешения, см. в описании ключа ExtraDriveWidth ("Интерфейс программы" — "Основное окно" — "Стиль отображения").

Значение ключа можно изменить на странице настроек "Значки", выбрав в выпадающем списке один из стандартных вариантов (16x16, 24x24, 32x32, 48x48 или 64x64). Другие размеры можно ввести вручную, хотя это и не рекомендуется (с произвольным масштабированием значков возможны проблемы). Достаточно указать в поле "Размер значка" одно число, сохранённое значение отображается в виде NxN, но в выпадающий список не добавляется.
[%Screen_Resolution%]
Iconsize32_96=16

Wincmd.ini Version: 9.21

Дополняет ключ Iconsize32, определяя размер значков (в пикселях) для файловых панелей, а также для выпадающего списка в цепочках навигации и для списка в диалоге "Соединение с FTP-сервером" при работе на нескольких мониторах с разным масштабированием (DPI).

По умолчанию: 16 (в списке на странице настроек "Значки" отображается как 16x16).

ПРИМЕЧАНИЯ:

Этот ключ дополняет работу основного ключа Iconsize32 (см. его описание), когда операционная система при работе с несколькими мониторами позволяет указывать для них разное значение DPI (эта возможность впервые заявлена в Windows 8.1, а должным образом начала работать в Windows 10).

Размер значков, изменённый на первичном мониторе, записывается как значение основного ключа Iconsize32 в секцию, соответствующую текущему разрешению экрана. Если же вывести окно TC на второй экран с другим значением DPI и изменить там размер значков через диалог настроек, то в секции с разрешением для первичного монитора будет автоматически создан также ключ вида Iconsize32_<DPI>, содержащий в имени значение DPI (число точек на дюйм) для вторичного монитора. Это позволит затем при переключении между мониторами автоматически выбирать размер значка, сопоставленный данному значению DPI.

Ключи вида Iconsize32_<DPI> с указанием DPI в именах имеют приоритет перед ключом Iconsize32_dpi с указанием DPI в значении.

Используемое в файле данных Configuration Editor имя Iconsize32_96 является демонстрационным. Если это необходимо, можно добавить один или несколько аналогичных ключей (например, Iconsize32_120), открыв этот файл данных, например, в Блокноте и приведя имя и описание нового ключа в соответствие с системным значением DPI для вторичного монитора. Вы также можете вызвать в Configuration Editor встроенную функцию добавления ключа комбинацией SHIFT+F4 или через меню ("Правка" —> "Файл данных" —> "Добавить ключ"). Однако предпочтительнее изменять размер значков через основной диалог настроек TC.

Пояснения по именам секций, зависящих от экранного разрешения, см. в описании ключа ExtraDriveWidth ("Интерфейс программы" — "Основное окно" — "Стиль отображения").

Значение ключа можно изменять на странице настроек "Значки", но опосредованно, через изменение других настроек (см. выше).
[%Screen_Resolution%]
Iconsize32_dpi=96

Wincmd.ini Version: 10.50

Сохраняет значение экранного масштабирования (DPI, в точках на дюйм), установленное при последнем сохранении значения ключа Iconsize32 для данного экранного разрешения.

По умолчанию значение не указано (условно 96).

ПРИМЕЧАНИЯ:

Ключ используется для динамического масштабирования значков при переключении между двумя экранами с различным DPI (подробности см. в описании ключа Iconsize32_96). Он создаётся и изменяется автоматически, вмешательства пользователя его работа обычно не требует. Ключи с явным указанием DPI в именах имеют приоритет перед Iconsize32_dpi, который важен только в случае их отсутствия.

Пояснения по именам секций, зависящих от экранного разрешения, см. в описании ключа ExtraDriveWidth ("Интерфейс программы" — "Основное окно" — "Стиль отображения").

Значение ключа можно изменять на странице настроек "Значки", но опосредованно, через изменение других настроек (см. выше).[/cut]
[cut="Buttonheight"][Buttonbar]
Buttonheight=29

Wincmd.ini Version: 1.30

Определяет размер кнопок в главной панели инструментов (в пикселях), влияющий также на высоту строк панели.

При правке значения вручную надо указывать его на 5 пикселей больше того, которое отображается в окне настройки Total Commander!

По умолчанию используется значение 29, что соответствует размеру 24 в окне настройки.

ПРИМЕЧАНИЯ:

При использовании ключа SmallIcons со значением 1 размер значков на кнопках главной панели инструментов будет практически равен размеру самих кнопок, в противном случае (при SmallIcons=0, как по умолчанию) размер значков на этих кнопках определяется ключом SmallIconSize.

Оверлейные значки в правом нижнем углу некоторых кнопок (со стрелкой вниз — для открытия связанной панели в виде выпадающего меню, с вертикальными полосками — при приостановке синхронной навигации) отрисовываются увеличенными для кнопок с отображаемым в диалоге настройки размером 25 и более, а начиная с размера кнопок 40 увеличиваются дополнительно.

ВНИМАНИЕ! Эта и последующие диалоговые опции — общие для главной панели инструментов и всех её дочерних панелей. Содержимое конкретных панелей описывается специальным набором ключей в соответствующих BAR-файлах. Вертикальная панель инструментов, расположенная между файловыми панелями, настраивается одноимёнными ключами, содержащимися в секции [ButtonbarVertical].

Значение ключа можно изменить в диалоге "Настройка панели инструментов" для главной панели.
[Buttonbar]
Buttonheight96=29

Wincmd.ini Version: 9.20

Определяет, как и Buttonheight, размер кнопок в главной панели инструментов (и, соответственно, высоту её строк), но предназначен для экрана с указанным в имени ключа DPI (в данном случае — 96 точек на дюйм).

При правке значения вручную надо указывать его на 5 пикселей больше того, которое отображается в окне настройки Total Commander!

По умолчанию используется значение 29, что соответствует размеру 24 в окне настройки.

ПРИМЕЧАНИЯ:

Ключ введён для улучшения работы с панелью инструментов на нескольких мониторах с различным масштабированием. Например, при текущем системном значении DPI 96 любое первичное изменение настроек главной панели сохраняет пару ключей Buttonheight и Buttonheight96 с одинаковыми значениями. Кроме того, сохраняются ключи SmallIconSize и SmallIconSize96, а также ключ DefaultDpi=96, фиксирующий текущее значение DPI. При переключении на монитор с другим DPI прежние размеры в INI-файле не перезаписываются, но в диалоге отображаются уже в автоматически преобразованном виде. Если затем изменить в диалоге значения Buttonheight и/или SmallIconSize, с этими значениями будут автоматически созданы новые дополнительные ключи. Например, при DPI 120 появятся ключи Buttonheight120, SmallIconSize120, ключ DefaultDpi примет значение 120, а ключи Buttonheight96 и SmallIconSize96 останутся неизменными.

При изменении системного DPI автоматически создаются также по мере необходимости файлы с кэшем значков, дополняющие такие файлы, как default.br2. Соответствующее значение DPI завершает их расширения вместо цифры 2: например, default.br96, default.br120 и т.д.

Используемое в файле данных Configuration Editor имя Buttonheight96 является демонстрационным. Для системных значений DPI, отличных от 96, можно добавить один или несколько аналогичных ключей (например, Buttonheight120), открыв этот файл данных, например, в Блокноте и приведя имя и описание нового ключа в соответствие с системным значением DPI. Вы также можете вызвать в Configuration Editor встроенную функцию добавления ключа комбинацией SHIFT+F4 или через меню ("Правка" —> "Файл данных" —> "Добавить ключ"). Однако предпочтительнее изменять размер кнопок/значков через диалог "Настройка панели инструментов" в TC.

Значение ключа можно изменить в диалоге "Настройка панели инструментов" для главной панели, но опосредованно, через изменение других настроек (см. выше).[/cut]
[cut="SmallIconSize"][Buttonbar]
SmallIconSize=16

Wincmd.ini Version: 7.00

Определяет размер значков в главной панели инструментов (в пикселях) для случая, когда он не совпадает с размером кнопок (SmallIcons=1).

По умолчанию: 16.

ПРИМЕЧАНИЕ: По умолчанию значение ключа используется и для значков дочерней панели в виде выпадающего меню (см. ключ PopupIconSize). Размер "маленького" значка может на величину до 5 пикселей превышать размер кнопки, указанный в диалоге настройки (поскольку эта цифра прибавляются при записи ключа Buttonheight к его значению).

Значение ключа можно изменить в диалоге "Настройка панели инструментов" для главной панели, однако оно сохраняется только при SmallIcons=1.
[Buttonbar]
SmallIconSize96=16

Wincmd.ini Version: 9.20

Определяет, как и SmallIconSize, размер значков в главной панели инструментов для случая, когда он не совпадает с размером кнопок (SmallIcons=1), но предназначен для экрана с указанным в имени ключа DPI (в данном случае — 96 точек на дюйм).

По умолчанию: 16.

ПРИМЕЧАНИЯ:

Ключ введён для улучшения работы с панелью инструментов на нескольких мониторах с различным масштабированием. Основные принципы зависимости этих опций от текущего значения DPI изложены в описании ключа Buttonheight96.

По умолчанию значение ключа используется и для значков дочерней панели в виде выпадающего меню (см. ключ PopupIconSize). Размер "маленького" значка может на величину до 5 пикселей превышать размер кнопки, указанный в диалоге настройки (поскольку эта цифра прибавляются при записи ключа Buttonheight к его значению).

Значение ключа можно изменить в диалоге "Настройка панели инструментов" для главной панели, но опосредованно, через изменение других настроек (см. описание Buttonheight96).
[Buttonbar]
DefaultDpi=96

Wincmd.ini Version: 9.20

Определяет системное значение DPI, учитываемое в настройках кнопок главной панели инструментов при сохранении значений Buttonheight и SmallIconSize для текущего экрана. Используется для масштабирования значков.

По умолчанию: условно 96 (для DPI 96).

ПРИМЕЧАНИЕ: Ключ введён для улучшения работы с панелью инструментов на нескольких мониторах с различным масштабированием. Основные принципы зависимости этих опций от текущего значения DPI изложены в описании ключа Buttonheight96.

Значение ключа непосредственно в диалоговом режиме не изменяется, но устанавливается и корректируется автоматически при сохранении упомянутых выше опций.[/cut]

FallenAngel
На случай, если Loopback не вернется... Спросил я тут у интеллехта, как повесить хук, и он сразу дал рабочее решение.

[cut="ahk"]

Код: Выделить всё

#Requires AutoHotkey v2.0
Persistent ; Скрипт должен продолжать работу для получения сообщений

; Константы WinAPI
WH_MOUSE_LL := 14
WM_LBUTTONDOWN := 0x0201
HC_ACTION := 0

; 1. Создаем Callback. "Fast" рекомендуется для хуков ввода.
mouseCallback := CallbackCreate(LowLevelMouseProc, "Fast", 3)

; 2. Устанавливаем хук
hHook := DllCall("SetWindowsHookEx", "Int", WH_MOUSE_LL, "Ptr", mouseCallback, "Ptr", DllCall("GetModuleHandle", "Ptr", 0, "Ptr"), "UInt", 0, "Ptr")

if !hHook {
    MsgBox "Не удалось установить хук!"
    ExitApp
}

; Удаляем хук при закрытии скрипта
OnExit((*) => DllCall("UnhookWindowsHookEx", "Ptr", hHook))

; --- Сама функция перехвата ---
LowLevelMouseProc(nCode, wParam, lParam) 
{
    if nCode = HC_ACTION {
        ; Пример: ловим нажатие левой кнопки мыши
        if wParam = WM_LBUTTONDOWN {
            ; Извлекаем координаты из структуры MSLLHOOKSTRUCT
            x := NumGet(lParam, 0, "Int")
            y := NumGet(lParam, 4, "Int")
                        
            ToolTip "Нажата левая кнопка в: " x ", " y
            SetTimer () => ToolTip(), -1000 ; Скрыть через 1 сек
            
            ; return 1 ; Раскомментируйте, чтобы заблокировать клик для системы
        }
    }
    result := DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "Ptr", wParam, "Ptr", lParam, "Ptr")
    ; Передаем управление следующему хуку в цепочке
    return result
}
[/cut]
[cut="ahk"]

Код: Выделить всё

#Requires AutoHotkey v2.0
Persistent ; Скрипт должен продолжать работу для получения сообщений

; Константы WinAPI
WH_MOUSE_LL := 14
WM_LBUTTONDOWN := 0x0201
HC_ACTION := 0

; 1. Создаем Callback. "Fast" рекомендуется для хуков ввода.
mouseCallback := CallbackCreate(LowLevelMouseProc, "Fast", 3)

; 2. Устанавливаем хук
hHook := DllCall("SetWindowsHookEx", "Int", WH_MOUSE_LL, "Ptr", mouseCallback, "Ptr", DllCall("GetModuleHandle", "Ptr", 0, "Ptr"), "UInt", 0, "Ptr")

if !hHook {
    MsgBox "Не удалось установить хук!"
    ExitApp
}

; Удаляем хук при закрытии скрипта
OnExit((*) => DllCall("UnhookWindowsHookEx", "Ptr", hHook))

; --- Сама функция перехвата ---
LowLevelMouseProc(nCode, wParam, lParam) 
{
    if nCode = HC_ACTION {
        ; Пример: ловим нажатие левой кнопки мыши
        if wParam = WM_LBUTTONDOWN 
        {
            if !GetKeyState("Shift", "P")
               return  DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "Ptr", wParam, "Ptr", lParam, "Ptr")
               
            ; Извлекаем координаты из структуры MSLLHOOKSTRUCT
            x := NumGet(lParam, 0, "Int")
            y := NumGet(lParam, 4, "Int")
            
            hWnd := DllCall("WindowFromPoint", "Int64", NumGet(lParam, 0, "Int64"), "Ptr")
            if (hWnd) {
                rootHWnd := DllCall("GetAncestor", "Ptr", hWnd, "UInt", 2)
                
                classBuffer := Buffer(512)
                DllCall("GetClassName", "Ptr", rootHWnd, "Ptr", classBuffer, "Int", 256)
                
                hitTest := DllCall("SendMessage", "Ptr", rootHWnd, "UInt", 0x84, "Ptr", 0, "Ptr", (y << 16) | (x & 0xFFFF))
                isTitleBar := (hitTest == 2) ; HTCAPTION
        
                ;MsgBox "Класс: " . StrGet(classBuffer) . "`nЗаголовок: " . (isTitleBar ? "Да" : "Нет")
                ToolTip "Класс: " . StrGet(classBuffer) . "`nЗаголовок: " . (isTitleBar ? "Да" : "Нет")
                SetTimer () => ToolTip(), -2000 ; Скрыть через 1 сек                
            }
            ;ToolTip "Нажата левая кнопка в: " x ", " y
            ;SetTimer () => ToolTip(), -1000 ; Скрыть через 1 сек
            
            ; return 1 ; Раскомментируйте, чтобы заблокировать клик для системы
        }
    }
    result := DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "Ptr", wParam, "Ptr", lParam, "Ptr")
    ; Передаем управление следующему хуку в цепочке
    return result
}
[/cut]
Перевод на Autorun не занял много времени. Пришлось правда добавить обработчик очереди сообщений вместо

Код: Выделить всё

hHook = DllCall("SetWindowsHookEx", _
                "Int", WH_MOUSE_LL, _
                "Ptr", MyMouse.Ptr, "Ptr", DllCall("GetModuleHandleW", "Ptr", 0, "Ptr"), "UInt", 0, "Ptr")

Ну и вместо

Код: Выделить всё

# Извлечение координат из структуры MSLLHOOKSTRUCT
#x = NumGet(lParam, 0, "Int")
#y = NumGet(lParam, 4, "Int")
Я просто использовал MouseGetPos("x","y")

[cut="aucfg"]

Код: Выделить всё

Pragma IncludeOnce

Global WH_MOUSE_LL = 14, HC_ACTION = 0

Global MyMouse = Callback("LowLevelMouseProc", "int;wparam;lparam")

#hHook = DllCall("SetWindowsHookEx", _
#                "Int", WH_MOUSE_LL, _
#                "Ptr", MyMouse.Ptr, "Ptr", DllCall("GetModuleHandleW", "Ptr", 0, "Ptr"), "UInt", 0, "Ptr")

RunThread("MouseHook")

Func MouseHook()    
    Local hHook
    hHook = DllCall("SetWindowsHookEx", _
                    "Int", WH_MOUSE_LL, _
                    "Ptr", MyMouse.Ptr, "Ptr", 0, "UInt", 0, "Ptr")
    Local buf = Buffer(auX64 ? 56 : 28)
    While 1      
       DllCall("GetMessage", "ptr", buf.ptr, "hwnd", -1, "uint", 0, "uint", 0) 
       DllCall("TranslateMessage", "ptr", buf.ptr)
       DllCall("DispatchMessage", "ptr", buf.ptr)
    Wend              
EndFunc

Func LowLevelMouseProc(nCode, wParam, lParam)
    # WM_LBUTTONDOWN
    If (nCode = HC_ACTION) And (wParam = 0x0201) Then
       If IsPressed(0x10) Then    
       
          # Извлечение координат из структуры MSLLHOOKSTRUCT
          #x = NumGet(lParam, 0, "Int")
          #y = NumGet(lParam, 4, "Int")
          
          MouseGetPos("x","y")
          
          # Дескриптор окна под курсором
          Local hWnd = DllCall("WindowFromPoint", "Int64", MakeInt(x, y, 2), "Ptr")
          If hWnd Then
              rootHWnd = DllCall("GetAncestor", "Ptr", hWnd, "UInt", 2)
              
              classBuffer = Buffer(512)
              DllCall("GetClassName", "Ptr", rootHWnd, "Ptr", classBuffer.Ptr, "Int", 256)
              
              hitTest = DllCall("SendMessage", "Ptr", rootHWnd, "UInt", 0x84, "Ptr", 0, "Ptr", MakeInt(x, y, 0))
              isTitleBar = (hitTest = 2)  # HTCAPTION
              If isTitleBar And classBuffer.GetStr() = "TLister" Then AlignListerWindow()
              #MsgBox("Класс: " & classBuffer.GetStr() & auCRLF & "Заголовок: " & (isTitleBar ? "Да" : "Нет"))
          EndIf          
          # Return 1  # Заблокировать клик для системы
        EndIf
    EndIf
    # Передача управления следующему хуку в цепочке
    Return DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "wParam", lParam, "Ptr", lParam, "Ptr")
EndFunc
[/cut]
В код добавлена проверка класса TLister: если под курсором находится заголовок листера, будет вызвана AlignListerWindow, подгоняющая его размеры под окно тотала.

Вроде бы все работает, но ИИ советует использовать другой метод через функцию RegisterRawInputDevices

Код: Выделить всё

Если вы используете Raw Input (как мы обсуждали ранее) — вам вообще не нужны эти хуки, так как Raw Input еще более безопасен и не тормозит систему.
Там более сложный код получается, завтра скину.