| View previous topic :: View next topic |
| Author |
Message |
Orion9

Joined: 01 Jan 2024 Posts: 1241
|
(Separately) Posted: Tue Sep 01, 2026 23:27 Post subject: |
|
|
| AkulaBig wrote: | | Исключительно по Авторан. |
Я бы рад, но ситуация сейчас напряжная. Сам не ожидал, что так получится, но ничего не подклаешь, приходится теперь мириться.
А что там в двух словах? |
|
| Back to top |
|
 |
AkulaBig
Joined: 03 Dec 2008 Posts: 587
|
(Separately) Posted: Wed Sep 02, 2026 11:03 Post subject: |
|
|
Orion9
Понятно. Будем ждать, когда ваша ситуация успокоится.
Я изучил ваш код и сделал функцию чтения данных из ExifTool через Вин АПИ. Мы-же обсуждали, что ShellExec и т.д. в ТС64 неправильно работают. И оказалось, что вызов через DllCall работает также, то есть не функции вывода виноваты. При этом с MediaInfo, где мы используем dll, все норм.
Хотел обсудить с вами эту тему.
И еще одну, но там надо все-же практическое решение. Так что не буду озвучивать. |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1241
|
(Separately) Posted: Thu Sep 03, 2026 23:46 Post subject: |
|
|
| AkulaBig wrote: | | Мы-же обсуждали, что ShellExec и т.д. |
Я уже ничего не помню. Но вообще-то тот код делал ИИ, а я всего лишь перевел его в Autorun.
| AkulaBig wrote: | | Хотел обсудить с вами эту тему. |
А с ИИ пробовали? От него будет больше пользы, чем от меня  |
|
| Back to top |
|
 |
AkulaBig
Joined: 03 Dec 2008 Posts: 587
|
(Separately) Posted: Fri Sep 04, 2026 05:28 Post subject: |
|
|
| Orion9 wrote: | | А с ИИ пробовали? От него будет больше пользы, чем от меня |
У меня, как у вас не получается. Кто вам такие портянки ответов выдает, не знаю. Мне Алиса краткие ответы дает и все.
Хочется понять, почему с MediaInfo DllCall работает нормально, а с ExifTool - нет. Понятно, что одна длл, а вторая экзе. Но неужели нельзя как-то решить этот вопрос без сансея?
Есть еще более локальный вопрос. Сделал через ET и всплывающие подсказки к файлам по типу MI. И вот тут скорость работы ET очень заметна. При передвижении мыши функция не успевает отработать и вешает ТС. Вот мне думка в голову пришла. В своих плагинах я делаю защиту от быстрого нажатия клавиш стрелок. А для подсказок над файлами можно как-то проверить, что функция выполнена до конца? Может ProcessWait в этом поможет? Или какой-нить код написать? |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1241
|
(Separately) Posted: Sat Sep 05, 2026 00:13 Post subject: |
|
|
| AkulaBig wrote: | | У меня, как у вас не получается. |
Если у вас не работает режим ИИ в google.com, значит его блокирует провайдер или какие-то другие проблемы. Попробуйте для начала сменить адреса DNS-серверов на эти. Лучше используйте DoH в браузере или в системе (Windows 11 это позволяет сделать). Это проксируемый DNS от Comss.ru, который позволяет обойти геоблок многих сервисов, включая ИИ:
 Hidden text Доступ к ИИ-сервисам и обновлениям Windows
Comss.one DNS также предоставляет доступ к популярным сайтам и сервисам. В частности, вы можете пользоваться ИИ-сервисами (ChatGPT и Sora, Microsoft Copilot, GitHub Copilot, xAI Grok, Google Gemini и Claude AI), или устанавливать обновления антивирусов, инсайдерские сборки и обновления Windows, а также играть в Brawl Stars и сетевые режимы Doom Eternal в России.
Или используйте другие методы обхода блокировки.
| AkulaBig wrote: | | Но неужели нельзя как-то решить этот вопрос без сансея? |
На сенсея расчитывать не стоит. Я же говорю, его Хлебникова забрала прямо в упаковке, и выбраться оттуда - ой как сложно (знающие люди говорят).
Юзайте ИИ, сейчас без этого никуда. Но если заниматься этим профессионально, нужно что-то помощнее, чем Google ИИ.
| AkulaBig wrote: | | При передвижении мыши функция не успевает отработать и вешает ТС. |
Да, все эти фризы - очень слабое место ТС, особенно при работе с сетью, (раздражает жестко), но Гислер вряд ли это исправит, если только не подключит к работе ИИ.
| AkulaBig wrote: | | А для подсказок над файлами можно как-то проверить, что функция выполнена до конца? |
Если в подсказке свои поля, то, наверное, можно, если самостоятельно следить за координатами мыши и сразу выходить из функции. Но на другие плагины повлиять никак не получится , если только нет какой-то тонкой настройки в самом ТС. |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1241
|
(Separately) Posted: Sun Sep 06, 2026 14:06 Post subject: |
|
|
AkulaBig
Ну что, заработал у вас болван?
Я у него спросил, кстати:
 Hidden text Total Commander неи меет встроенной глобальной настройки, которая позволяла бы изолировать плагины и запускать их вне главного процесса приложения.Поскольку официальный SDK Total Commander компилирует плагины как стандартные динамические библиотеки Windows (файлы .wlx, .wfx, .wdx, .wcx — это просто переименованные .dll), они загружаются напрямую в адресное пространство памяти totalcmd.exe. Критическая ошибка (краш) внутри криво написанного плагина неизбежно приведет к падению главной оконной процедуры самого Total Commander.
Тем не менее, в зависимости от вашей цели (предотвратить зависания, избежать падений или использовать несовместимые плагины), существуют следующие варианты обхода и архитектурные решения
Реализация прокси-заглушки (Out-of-Process Proxy/Wrapper)
Если вы сами разрабатываете плагин и хотите гарантировать, что он никогда не обрушит главный поток хост-приложения, вам необходимо спроектировать его по клиент-серверной архитектуре:DLL-заглушка (In-Process): Вы пишете сам плагин .wlx/.wfx как легковесную DLL-«заглушку». Единственная задача этой DLL — общаться с отдельным процессом через механизмы межпроцессного взаимодействия (IPC).Воркер (Out-of-Process): Вы создаете отдельный исполняемый файл .exe, который и выполняет всю тяжелую работу.
Взаимодействие: Когда Total Commander вызывает функцию в вашей DLL-заглушке, эта DLL запускает ваш .exe (или связывается с уже запущенным экземпляром) через разделяемую память (Shared Memory), именованные каналы (Named Pipes) или сообщения WM_COPYDATA. Если .exe упадет, ваша DLL-заглушка сможет изящно перехватить эту ошибку и вернуть в Total Commander уведомление о сбое вместо того, чтобы обрушить всю программу.
Если создавать отдельный поток (thread) внутри той же DLL, это не защитит Total Commander от падения. В архитектуре Windows все потоки одного процесса делят между собой общее адресное пространство памяти. Если в коде плагина (даже в отдельном потоке) произойдет критическая ошибка вроде Access Violation (Segmentation Fault) или утечка памяти, операционная система завершит работу всего процесса totalcmd.exe целиком.
Именно поэтому для полной изоляции и стабильности необходимо использовать исключительно отдельный процесс (.exe).
Почему поток не спасет от падения, но полезен для отзывчивостиЧтобы четко понимать разницу в подходах, их можно разделить на две категории:
- Отдельный поток (Thread) — спасает только от "зависания" интерфейса
Если плагин делает долгий запрос к сети или обрабатывает гигантский файл, выполнение этого кода в отдельном потоке внутри DLL сохранит интерфейс Total Commander отзывчивым (главное окно не будет писать "Не отвечает"). Но если этот поток упадет — упадет и весь Total Commander.
- Отдельный процесс (.exe) — спасает от "смерти" приложения
Поскольку операционная система полностью изолирует память процессов друг от друга, краш, деление на ноль или зависание в вашем .exe никак не повлияет на totalcmd.exe. Процесс плагина просто завершится, а DLL-заглушка (Stub) получит уведомление о разрыве соединения и сможет корректно вывести пользователю сообщение: "Произошла ошибка при загрузке плагина".
Если вы пишете плагин (например, Lister .wlx), архитектура взаимодействия должна выглядеть следующим образом:
1. Инициализация: Total Commander вызывает функцию плагина (например, ListLoad).
2. Запуск воркера: Внутри этой функции DLL-заглушка вызывает Windows API функцию CreateProcess, запуская ваш скрытый worker.exe.
3. Передача данных: DLL передает в .exe параметры (путь к файлу, дескриптор окна hWnd для отрисовки) через один из механизмов IPC (Inter-Process Communication). Для плагинов просмотра чаще всего используют:
* WM_COPYDATA — самый простой способ передать кусок памяти или строку между окнами разных процессов.
* Named Pipes (Именованные каналы) — отлично подходит для постоянного стриминга данных.
* Shared Memory (Разделяемая память / File Mapping) — идеальный вариант, если нужно передавать большие объемы данных (например, текстуры или тяжелые документы) без накладных расходов на копирование.
4. Отрисовка (для Lister): Чтобы worker.exe мог рисовать прямо внутри панели Total Commander, DLL-заглушка должна передать ему hWnd родительского окна, которое ей выдал Total Commander. Затем .exe привязывает свое окно к родительскому с помощью функции SetParent(child_hwnd, parent_hwnd).
Вы планируете реализовать такую схему самостоятельно? Напишите, какой именно тип плагина (Lister, Content, Packer) вы разрабатываете и на каком языке программирования (C++, Delphi, C#) — я могу набросать базовый шаблон кода для DLL-заглушки и IPC-взаимодействия.
Решение с потоками рабочее. Например, была функция, которая выводит сведения о кодировке в кастомное поле
| Code: | Func EncDetect(FileName, FieldIndex, UnitIndex)
Local pipe
Static exe_tool = COMMANDER_PATH & "\Ini\Tools\uchardet.exe"
ProcessExecGetOutput pipe %exe_tool% '"%FileName%"'
Return pipe
EndFunc |
Если файл с текстом большой (>1 Гб), то это заметно вешает ТС при отображении подсказки. Но если переделать в поток, то фризов нет - интерфейс продолжает быть полностью доступным для работы
| Code: | Func EncDetect(FileName, FieldIndex, UnitIndex)
Global gEncDetect = 1, gEncPipe
RunThread("ThreadEncDetect", FileName, FieldIndex, UnitIndex)
While gEncDetect
Sleep(50)
Wend
Return gEncPipe
EndFunc
Func ThreadEncDetect(FileName, FieldIndex, UnitIndex)
Static exe_tool = COMMANDER_PATH & "\Ini\Tools\uchardet.exe"
ProcessExecGetOutput gEncPipe %exe_tool% '"%FileName%"'
gEncDetect = 0
EndFunc |
Это очень грубый пример, но сама идея рабочая.
Что касается других плагинов.
Да, может быть такая строчка в подсказке
| Code: | 21exts=>Текстовые файлы
21fields=Тип: [=encinfo.Type]\nКодировка: [=encinfo.Encoding]\nКодировка: [=autorun.Encoding] |
Т.е. помимо кода Авторан, выводятся данные из других плагинов (в данном случае EncInfo). Их тоже можно завернуть в Авторан при помощи объекта Plugin.
Можно сделать более продвинутый код, чтобы подсказка не отображалась (возвращала "") при смене позиции или по таймауту, но даже так уже гораздо лучше, чем наблюдать эти чудовищные фризы. Вообще удивляет, что маестро тратит время на всякую ерунду типа встроенного 7z, и ничего не делает для более комфортного существования в самом ТС. |
|
| Back to top |
|
 |
AkulaBig
Joined: 03 Dec 2008 Posts: 587
|
(Separately) Posted: Mon Sep 07, 2026 06:48 Post subject: |
|
|
| Orion9 wrote: | Ну что, заработал у вас болван?
|
Он работает, но не как у вас.
Вот я переделал из вашего кода для тестирования всех вариантов обработки ExifTool, вариант с CallDll:
 Hidden text
| Code: |
Static hChildStdInWr = 0
Static hChildStdOutRd = 0
Static hChildStdInRd = 0
Static hChildStdOutWr = 0
Static hProcess = 0
Static hThread = 0
Func ET(FileName, FieldIndex, UnitIndex)
# Расположение файла Autorun.ini
# Location of Autorun.ini file
Local ini_TypeHints = COMMANDER_PATH & "\Ini\Autorun.ini"
# Читаем номер вида
# Reading type number
Local TypeHintsNum = IniRead(ini_TypeHints, "TypeHints", "TypeNum", 0)
# 0 - стандартный вид подсказки над файлами
# 1 - расширенный вид подсказки над файлами
If TypeHintsNum = 0 Then Return
If StrPos(FileGetAttr(FileName), "D") Then Return
Local sFile = "", j, files = 0, str
Local sPath = RequestCopyDataInfo("SP")
Local sName = RequestCopyDataInfo("SN")
Static aSel = List()
aSel.Count = 0
aSel.Text = GetSelectedItems(3, 0)
If aSel.Count = 0 Then aSel.Add(sName)
# Настройка атрибутов безопасности для наследования дескрипторов
Local Sec = Buffer(auX64 ? 24 : 12)
Sec.Zero()
Sec.SetNum(0, "UInt", Sec.size) # nLength
If auX64 Then
Sec.SetNum(8, "Ptr", 0) # lpSecurityDescriptor
Sec.SetNum(16, "Int", 1) # bInheritHandle
Else
Sec.SetNum(4, "Ptr", 0)
Sec.SetNum(8, "Int", 1)
EndIf
# Создаем Pipe для STDIN (Запись из Autorun -> Чтение в ExifTool)
If Not DllCall("CreatePipe", "Ptr*", @hChildStdInRd, "Ptr*", @hChildStdInWr, "Ptr", Sec.Ptr, "UInt", 0) Then
MsgBox("Error CreatePipe STDIN")
Return 0
EndIf
# Создаем Pipe для STDOUT (Запись из ExifTool -> Чтение в Autorun)
if Not DllCall("CreatePipe", "Ptr*", @hChildStdOutRd, "Ptr*", @hChildStdOutWr, "Ptr", Sec.Ptr, "UInt", 0) Then
DllCall("CloseHandle", "Ptr", hChildStdInRd)
DllCall("CloseHandle", "Ptr", hChildStdInWr)
MsgBox("Error CreatePipe")
Return 0
EndIf
# Запрещаем наследование нашей (записывающей/читающей) стороны каналов
DllCall("SetHandleInformation", "Ptr", hChildStdInWr, "UInt", 1, "UInt", 0)
DllCall("SetHandleInformation", "Ptr", hChildStdOutRd, "UInt", 1, "UInt", 0)
# Настройка STARTUPINFO
Local SI = Buffer(auPtrSize = 8 ? 104 : 68)
SI.Zero()
SI.SetNum(0, "UInt", SI.Size)
SI.SetNum(auX64 ? 60 : 44, "UInt", 0x00000101) # STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW
SI.SetNum(auX64 ? 64 : 48, "UShort", 0) # SW_HIDE (скрывает окно консоли)
SI.SetNum(SI.Size - 3 * auPtrSize, "Ptr", hChildStdInRd)
SI.SetNum(SI.Size - 2 * auPtrSize, "Ptr", hChildStdOutWr)
SI.SetNum(SI.Size - auPtrSize, "Ptr", hChildStdOutWr) # Дублируем stdout в stderr
# Настройка PROCESS_INFORMATION
PI = Buffer(auPtrSize = 8 ? 24 : 16)
PI.Zero()
# Командная строка запуска
Local cmdLine = '"' & util_ET & '" -stay_open True -@ -'
# Флаг CREATE_NO_WINDOW (0x08000000) полностью блокирует создание консольного окна
If Not DllCall("CreateProcessW", "Ptr", 0, "WStr", cmdLine, _
"Ptr", 0, "Ptr", 0, "Int", 1, "UInt", 0x08000000, _
"Ptr", 0, "Ptr", 0, "Ptr", SI.Ptr, "Ptr", PI.Ptr) Then
# Закрываем все открытые дескрипторы при ошибке
DllCall("CloseHandle", "Ptr", hChildStdInRd)
DllCall("CloseHandle", "Ptr", hChildStdInWr)
DllCall("CloseHandle", "Ptr", hChildStdOutRd)
DllCall("CloseHandle", "Ptr", hChildStdOutWr)
MsgBox("Error CreateProcess")
Return 0
EndIf
# Сохраняем нужные дескрипторы
hProcess = PI.GetNum(0, "Ptr")
hThread = PI.GetNum(auPtrSize, "Ptr")
# Закрываем дескрипторы, которые больше не нужны родительскому процессу
DllCall("CloseHandle", "Ptr", hChildStdInRd)
DllCall("CloseHandle", "Ptr", hChildStdOutWr)
WriteLine("-lang")
WriteLine("ru")
WriteLine("-m")
WriteLine("-q")
WriteLine("-q")
WriteLine(FileName)
WriteLine("-echo3")
WriteLine("{ready}")
WriteLine("-execute")
#MsgBox(hProcess & " " & hChildStdInWr & " " & hChildStdOutRd & " " & hChildStdInRd & " " & hChildStdOutWr )
Local output = "", chunk = ""
# Буфер для побайтового/посимвольного чтения из пайпа
Static readBuf = Buffer(1024*2)
readBuf.Zero()
While 1
Local bytesRead = 0
If Not DllCall("ReadFile", _
"Ptr", hChildStdOutRd, _
"Ptr", readBuf.Ptr, "UInt", readBuf.Size, "UInt*", @bytesRead, "Ptr", 0) Then
Break
EndIf
If bytesRead <= 0 Then Break
chunk = readBuf.GetStr(0, bytesRead, "ANSI")
output &= chunk
If StrPos(chunk, "{ready}") Then
Break
EndIf
Wend
# Очищаем результат от маркеров
output = StrReplace(output, "{ready}", "")
If hChildStdInWr Then
WriteLine("-stay_open")
WriteLine("False")
DllCall("CloseHandle", "Ptr", hChildStdInWr)
hChildStdInWr = 0
EndIf
If hChildStdOutRd Then
DllCall("CloseHandle", "Ptr", hChildStdOutRd)
hChildStdOutRd = 0
EndIf
if hProcess Then
DllCall("CloseHandle", "Ptr", hProcess)
hProcess = 0
EndIf
If hThread Then
DllCall("CloseHandle", "Ptr", hThread)
hThread = 0
EndIf
Return TrimSpaces(StrPart(output, auLF, FieldIndex))
EndFunc
Func WriteLine(text)
rawString = text & auCRLF
# ExifTool ожидает UTF-8 или системную кодировку (зависит от настроек, UTF-8 наиболее универсален)
bufLen = StrLen(rawString) * 2
buf = Buffer(bufLen)
buf.Zero()
bufWr = buf.SetStr(rawString, 0, bufLen, "ANSI")
# Запись через WinAPI WriteFile
Local bytesWritten = 0
DllCall("WriteFile", "Ptr", hChildStdInWr, "Ptr", buf.ptr, "UInt", bufWr, "UInt*", @bytesWritten, "Ptr", 0)
Free(buf)
EndFunc
Func TrimSpaces(String)
Local a, b
If Not StrPos(String, ":") Then Return String
a = StrPart(String, ": ", 1)
b = StrPart(String, ": ", 2)
Return StrTrim(FixCPET(a)) & ": " & StrTrim(FixCPET(b))
EndFunc
Func FixCPET(String)
Static a = List(), u = List()
Local ansi = String, utf8, wrong = Chr(0xFFFD)
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
|
Ни одного использования ShellExec и т.д. MediaInfo с таким алгоритмом работает прекрасно. А ExifTool под ТС32 работает правильно, а под ТС64 сначала обрабатывает все файлы, а потом выводит данные. Что создает огромную задержку. Может у вас есть идеи, как исправить это поведение? Ну и еще как-бы сделать, чтобы отслеживалось полное выполнение скрипта? |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1241
|
(Separately) Posted: Mon Sep 07, 2026 10:57 Post subject: |
|
|
| AkulaBig wrote: | | Он работает, но не как у вас. |
А как он у вас работает, не понимаю.
| AkulaBig wrote: | | а под ТС64 сначала обрабатывает все файлы, а потом выводит данные. Что создает огромную задержку. |
А, теперь понял о чем речь (сорри, я реально не понял этого из первого сообщения).
Ну, ИИ здесь не поможет. Это давняя проблема о которой я писал Loopback, но он либо не заметил, либо не придал значения, а оно вон во что вылилось.
Т.ч. вы правы: без сенсея тут никак. Проблема лежит в самой реализации Pragma AutorunPluginFields, и только он знает ее корни. |
|
| 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
|