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

Joined: 01 Jan 2024 Posts: 1269
|
(Separately) Posted: Wed Sep 30, 2026 12:12 Post subject: |
|
|
| AkulaBig wrote: | | куда правильно вставить это условие, чтобы все заработало. |
Тут чекушку открывать надо, а сейчас за рулем, не могу.
Но если навскидку, то функция ET запускается 60 раз. Процесс exiftool должен запуститься один раз, и желательно за пределами этой функции. FieldIndex = 1 должен сделать запрос к запущенному процессу и ждать ответа. Остальные 59 вызовов будут просто разбирать полученный выхлоп на строки.
Это была тестовая функция для проверки скорости на группе выделенных файлов. В подсказке прирост скорости менее очевиден. Имхо, лучше оставить общение с процессом через файл, что я и сделал. И код намного проще, и скорость практически та же.
Вы можете сами протестировать и убедиться в этом. Тестовая функция с тремя режимами как раз и создавалась для этого:
Win+[ запуск exiftool для каждого файла.
Win+] держит процесс открытым и взаимодействует с ним через файл аргументов.
Win+\ взаимодействует с процессом через stdin и stdout.
Результат сохраняется во временный каталог, в файлы exif_[0,1,2]. Все три файла должны совпадать за исключением метки последнего времени доступа и маркера {ready}.
 Hidden text | Code: | SetHotkeyAction /K:W /V:219 TestExiftoolSpeed 0
SetHotkeyAction /K:W /V:221 TestExiftoolSpeed 1
SetHotkeyAction /K:W /V:220 TestExiftoolSpeed 2
Static sExif = COMMANDER_PATH & "\Plugins\wlx\ExifToolView\exiftool.exe"
Static sExifOut = TEMP & "\exiftool_out.txt", sExifArgs = TEMP & "\exiftool_args.txt"
Static hChildStdInWr = 0
Static hChildStdOutRd = 0
Static hChildStdInRd = 0
Static hChildStdOutWr = 0
Static hProcess = 0
Static hThread = 0
#TestExiftoolSpeed(3)
Func TestExiftoolSpeed(StayOpen)
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)
If StayOpen = 1 And Not ProcessExist("exiftool.exe") Then
DllCall("kernel32.dll\DeleteFileW", "Wstr", sExifOut)
DllCall("kernel32.dll\DeleteFileW", "Wstr", sExifArgs)
FileWrite(sExifArgs, "", "UTF-8 NOBOM")
ShellExec /TT /SW_HIDE %sExif% "-stay_open True -@ ""%sExifArgs%"""
ShowHint("Запуск exiftool.exe")
Sleep(1000)
Local nPID = ProcessGetId("exiftool.exe")
If nPID = 0 Then Return MsgBox("Процесс ExifTool не запущен")
EndIf
If StayOpen = 2 Then
If Not StartExifProcess() Then Return ShowHint("Операция прервана")
EndIf
If StayOpen = 3 Then
If StartExifProcess() Then
WriteLine("-G")
WriteLine("-S")
WriteLine("-lang")
WriteLine("ru")
WriteLine("d:\Temp\Images\test.jpg")
WriteLine("-execute")
#MsgBox(hProcess & " " & hChildStdInWr & " " & hChildStdOutRd & " " & hChildStdInRd & " " & hChildStdOutWr )
MsgBox(ReadResponse())
Return ExifClose()
Else
Return ShowHint("Операция прервана")
EndIf
EndIf
T1 = GetUptime()
ShowHint("Обработка выделенного Exiftool.exe")
For j = 0 To aSel.Count - 1
sFile = sPath & aSel[j]
If FileExist(sFile) And Not StrPos(FileGetAttr(sFile), "D") Then
files += 1
str &= ExiftoolInfo(sFile, StayOpen)
EndIf
Next
T2 = Round(GetUptime() - T1, 0) / 1000
ShowHint("Выбрано: " & aSel.Count & auCRLF & _
"Обработано: " & files & auCRLF & _
"-stay_open: " & (StayOpen ? "Да" : "Нет") & auCRLF & _
"stdin/stdout: " & (StayOpen = 2 ? "Да" : "Нет") & auCRLF & _
"Объем данных: " & SizeFormat(StrLen(str), 0, 'B', 2) & auCRLF & _
"Время операции: " & StrFormat("%.3f", T2) & " sec")
ClipPut(str)
FileWrite(TEMP & "\_exif_" & StayOpen, str, "UTF-8")
If StayOpen = 2 Then ExifClose()
If StayOpen = 1 Then
ProcessTerminate("exiftool.exe")
Sleep(100)
DllCall("kernel32.dll\DeleteFileW", "Wstr", sExifOut)
DllCall("kernel32.dll\DeleteFileW", "Wstr", sExifArgs)
EndIf
EndFunc
Func ExiftoolInfo(FileName, StayOpen)
If StayOpen = 2 Then
#WriteLine("-G")
#WriteLine("-S")
#WriteLine("-lang")
#WriteLine("ru")
#WriteLine(FileName)
#WriteLine("-execute")
WriteLine("-G" & auCRLF & _
"-S" & auCRLF & _
"-lang" & auCRLF & _
"ru" & auCRLF & _
Filename & auCRLF & _
"-execute" & auCRLF)
Return ReadResponse() & auCRLF
EndIf
If Not StayOpen Then
ProcessExecGetOutput /C:65001 out %sExif% '-charset filename=Russian -lang ru -G -S "%FileName%"'
Else
If FileExist(sExifOut) Then
DllCall("kernel32.dll\DeleteFileW", "Wstr", sExifOut)
EndIf
Local sArgs = "-G" & auCRLF & _
"-S" & auCRLF & _
"-lang" & auCRLF & _
"ru" & auCRLF & _
"-W+!" & auCRLF & sExifOut & auCRLF & FileName & auCRLF & "-execute" & auCRLF
Static obj = BinaryFile(sExifArgs, "a")
obj.WriteStr(sArgs, "", "UTF-8")
out = "<time-out>"
For i = 1 To 50
If FileExist(sExifOut) Then
out = FileRead(sExifOut, 0, "UTF-8")
DllCall("kernel32.dll\DeleteFileW", "Wstr", sExifOut)
Break
EndIf
Sleep(10)
Next
EndIf
Return out
EndFunc
Func StartExifProcess()
# Настройка атрибутов безопасности для наследования дескрипторов
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 = '"' & sExif & '" -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)
Return 1
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, "UTF-8")
# Запись через WinAPI WriteFile
Local bytesWritten = 0
DllCall("WriteFile", "Ptr", hChildStdInWr, "Ptr", buf.ptr, "UInt", bufWr, "UInt*", @bytesWritten, "Ptr", 0)
Free(buf)
EndFunc
Func ReadResponse()
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, "UTF-8")
output &= chunk
If StrPos(chunk, "{ready}") Then
Break
EndIf
Wend
Return StrTrim(output)
EndFunc
Func ExifClose()
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
EndFunc |
Чем больше выделено файлов, тем больше (должен быть) прирост. Это было критично только для набора колонок в режиме просмотра х64. Но опция SetFieldsParam("Delayed", 1) вроде решает эту проблему. Вы ее пробовали?
Там только два прохода почему-то. |
|
| Back to top |
|
 |
AkulaBig
Joined: 03 Dec 2008 Posts: 620
|
(Separately) Posted: Wed Sep 30, 2026 13:39 Post subject: |
|
|
| Orion9 wrote: | | Процесс exiftool должен запуститься один раз, и желательно за пределами этой функции. |
За пределами он будет запускаться при старте ТС, что не очень хорошо. Но он запускается один раз, поэтому на данном этапе место запуска не имеет значения.
| Orion9 wrote: | | В подсказке прирост скорости менее очевиден. |
Очень заметен.
| Orion9 wrote: | | лучше оставить общение с процессом через файл |
Лучше, но проблема в том, при запуске колонок они засекаться начинают и все подвисает. А так у меня и вариант с файлами есть. но и там FieldIndex = 1 работает непонятно. Без него работает ощутимо медленней, а с ним когда начинаешь крякозябры убирать, почему-то по одному полю обрабатывается. То ли с FieldIndex = 1 надо алгоритм менять, то ли знать, куда его впихнуть. Но я многие варианты уже попробовал. Пока не получается.
| Orion9 wrote: | | SetFieldsParam("Delayed", 1) |
Пока не пробовал. Не до нее. Сейчас надо сделать чтобы все работало правильно. А в дальнейшем похоже для подсказки придется запускать отдельный экземпляр ET и временные файлы с другим названием. |
|
| Back to top |
|
 |
FallenAngel
Joined: 30 Dec 2025 Posts: 45
|
(Separately) Posted: Wed Sep 30, 2026 17:09 Post subject: |
|
|
В последнее время часто вылетает на Win11 25H2
| Code: | Имя сбойного приложения: TOTALCMD64.EXE, версия: 11.58.0.0, метка времени: 0x00000000
Имя сбойного модуля: Autorun.wdx64, версия: 2.2.21.3, метка времени: 0x68ef4c72
Код исключения: 0xc0000005
Смещение ошибки: 0x000000000005fa02
Идентификатор сбойного процесса: 0x229C
Время запуска сбойного приложения: 0x1DD50D5A31BB41E
Путь сбойного приложения: D:\soft\Total Commander 64\TOTALCMD64.EXE
Путь сбойного модуля: D:\soft\Total Commander 64\Plugins\Autorun\Autorun.wdx64
Идентификатор отчета: 0c64ebd0-8054-4fdf-8c0b-3116aec21693
Полное имя сбойного пакета:
Код приложения, связанного со сбойным пакетом: |
|
|
| Back to top |
|
 |
AkulaBig
Joined: 03 Dec 2008 Posts: 620
|
(Separately) Posted: Wed Sep 30, 2026 18:03 Post subject: |
|
|
Orion9
Вот вариант с временными файлами. Ваш вариант летает как ракета, если FieldIndex = 1. Но кривой вывод:
А если оставить -G -S, то только на английском и с наименованием группы.
А вот мой вариант с корректным выводом полей, но без FieldIndex:
 Hidden text
| Code: |
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", "CurrVal", 0)
# 0 - стандартный вид подсказки над файлами
# 1 - расширенный вид подсказки над файлами
If TypeHintsNum = 0 Then Return
If StrPos(FileGetAttr(FileName), "D") Then Return
Local iPID = 0, sOutFile = TEMP & "\out.txt", sArgFile = TEMP & "\args.txt"
iPID = ProcessGetId("exiftool.exe")
If iPID = 0 Then
FileWrite(sArgFile, "", "UTF-8 NOBOM")
ShellExec /TT /SW_HIDE %util_ET% "-stay_open True -@ ""%sArgFile%"""
EndIf
# ShellExec /SW_HIDE /WAIT %COMSPEC% "/c break > ""%sOutFile%"""
DllCall("kernel32.dll\DeleteFileW", "Wstr", sOutFile)
Local ansi
If FieldIndex = 1 Then
Local sArgs = "-lang" & auCRLF & _
"ru" & auCRLF & _
"-m" & auCRLF & _
"-q" & auCRLF & _
"-q" & auCRLF & _
"-W+!" & auCRLF & _
sOutFile & auCRLF & FileName & auCRLF & "-execute" & auCRLF
Local obj = BinaryFile(sArgFile, "a")
obj.WriteStr(sArgs, "", "UTF-8")
Free(obj)
# Проверяем наличие файла для записи данных
While 1
If FileExist(sOutFile) Then
# Читаем данные из файла
ansi = FileRead(sOutFile)
If ansi <> "" Then
# ShellExec /SW_HIDE /WAIT %COMSPEC% "/c break > ""%sOutFile%"""
DllCall("kernel32.dll\DeleteFileW", "Wstr", sOutFile)
Break
EndIf
EndIf
Sleep(10)
WEnd
EndIf
Return TrimSpaces1(StrPart(ansi, auLF, FieldIndex))
EndFunc
Func TrimSpaces1(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
|
Он работает медленно. А если прописать FieldIndex, то получается фигня:
Но с MI этот-же алгоритм работает без проблем. Очень хочется добиться быстрой и правильной работы. |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1269
|
(Separately) Posted: Thu Oct 01, 2026 13:39 Post subject: |
|
|
| FallenAngel wrote: | Имя сбойного приложения: TOTALCMD64.EXE, версия: 11.58.0.0, метка времени: 0x00000000
Имя сбойного модуля: Autorun.wdx64, версия: 2.2.21.3, метка времени: 0x68ef4c72
Код исключения: 0xc0000005 |
К сожалению, это мало о чем говорит. Ошибка произошла в модуле Autorun, но что именно случилось, не понятно.
| AkulaBig wrote: | | Он работает медленно. |
Не мудрено. У вас сейчас в этой функции 60 раз читается ini, 60 раз проверяется id процесса и 60 раз удаляется файл. И это для каждой подсказки.
| AkulaBig wrote: | | А если прописать FieldIndex, то получается фигня |
FieldIndex = 1 как раз нужен, чтобы сделать иницилизацию только один раз, когда вызывается первое поле подсказки, у меня так и сделано
| Code: | 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 FixSpaces(StrPart(gHintPipe, auLF, FieldIndex))
Return StrPart(gHintPipe, auLF, FieldIndex)
EndFunc |
Даже этот код можно попробовать оптимизировать, убрав все лишнее: т.е. убрать все, что выше If FieldIndex = 1, в само условие If FieldIndex = 1.
Объект BinaryFile должен быть в статике, чтобы он тоже не создавался 60 раз
| Code: | Static obj = BinaryFile(gExifArgs, "a") |
Free(obj) тогда не нужен.
| AkulaBig wrote: | | Ваш вариант летает как ракета |
Работает он быстро, но не стабильно. Скорее всего файл не успевает удаляться, поэтому не всегда результат в подсказке корректен. Нужно делать дополнительню проверку удаления файла, чтобы гарантировать надежность, но, понятное дело, ценой потери в скорости. Как сказал болван
| Quote: | | Если один и тот же файл постоянно перезаписывается, никогда не доверяйте успешному возврату из DeleteFileW. Либо переименовывайте файл в случайное имя перед удалением (чтобы сразу освободить оригинальное имя), либо используйте цикл с GetFileAttributesW, чтобы дождаться реального исчезновения файла с диска. |
И соответствующий код
 Hidden text | Code: | #Requires AutoHotkey v2.0
/**
* Надежно удаляет файл и ждет, пока его имя полностью освободится в системе.
* @param {String} filePath - Полный или относительный путь к файлу.
* @param {Integer} maxAttempts - Максимальное количество попыток ожидания (по умолчанию 100).
* @returns {Boolean} - true, если файл успешно и окончательно удален; false, если произошла ошибка или вышло время.
*/
ForceDeleteAndVerify(filePath, maxAttempts := 100) {
; 1. Проверяем, существует ли файл вообще
if !FileExist(filePath) {
return true
}
; 2. Пытаемся удалить файл средствами AHK (внутри вызывается DeleteFileW)
try {
FileDelete(filePath)
} catch Error as err {
; Если ошибка "Файл не найден" (код 2), значит файл уже удален
if (err.Extra == 2) {
return true
}
return false ; Другая ошибка (например, Access Denied / код 5)
}
; 3. Цикл ожидания, пока файл физически исчезнет из файловой системы
attempts := 0
while (attempts < maxAttempts) {
; Вызываем GetFileAttributesW через DllCall
; INVALID_FILE_ATTRIBUTES равен 0xFFFFFFFF (или -1 в 32-битном знаковом представлении)
attr := DllCall("Kernel32.dll\GetFileAttributesW", "Str", filePath, "UInt")
if (attr == 0xFFFFFFFF) {
lastError := DllCall("Kernel32.dll\GetLastError", "UInt")
; ERROR_FILE_NOT_FOUND = 2, ERROR_PATH_NOT_FOUND = 3
if (lastError == 2 || lastError == 3) {
return true ; Удаление наконец-то полностью завершено!
}
}
; Если файл все еще заблокирован в состоянии Pending Delete, ждем 10 мс
Sleep(10)
attempts++
}
return false ; Файл так и не исчез за отведенное время
}
; === ПРИМЕР ИСПОЛЬЗОВАНИЯ ===
targetFile := "C:\path\to\your\file.txt" ; Укажите свой путь к файлу
if ForceDeleteAndVerify(targetFile) {
MsgBox("Файл успешно и гарантированно удален! Теперь можно создавать новый с тем же именем.")
; Здесь можно безопасно делать FileAppend или FileOpen с тем же именем
} else {
MsgBox("Не удалось окончательно удалить файл (таймаут или ошибка доступа).")
}
|
| AkulaBig wrote: | | Но кривой вывод |
Вывод не кривой, а сырой (неформатированный). Я так и не понял, что хочу от этой подсказки, поэтому она осталась в недоделанном состоянии. |
|
| Back to top |
|
 |
AkulaBig
Joined: 03 Dec 2008 Posts: 620
|
(Separately) Posted: Thu Oct 01, 2026 14:19 Post subject: |
|
|
| Orion9 wrote: | | У вас сейчас в этой функции 60 раз читается ini, 60 раз проверяется id процесса и 60 раз удаляется файл. И это для каждой подсказки. |
Это я уже понял.
| Orion9 wrote: | | Я так и не понял, что хочу от этой подсказки, поэтому она осталась в недоделанном состоянии. |
В этом как-раз вся суть моего вопроса. Я-же на скрине показал ваш неформатированный вывод и какой должен быть форматированный вывод на моем скрине. М вот здесь появляется большое "но". Для такого форматированного вывода требуется прописать a = StrPart(String, ": ", 1), b = StrPart(String, ": ", 2). То-есть обработать наименование полей и поля отдельно. Тогда и от пробелов можно избавиться и от крякозябров. Но этот код работает только если нет условия If FieldIndex = 1. Стоит нам его использовать и StrPart(String, ": ", 1) выводит только наименование ОДНОГО поля! Я это тоже на скрине показал. Можно ли придумать решение этой проблемы?
То-есть неформатированный вывод, как на вашем скрине с If FieldIndex = 1 работает. Форматированный вывод, как на моем скрине с If FieldIndex = 1 не работает.
Но для MI подобный алгоритм у меня работает. Не понимаю, почему? Кажется совершенно одинаковый код самого вывода.
Добавлено спустя 35 минут:
На всякий случай решил ваш код выложить с неформатированным выводом. Может вам легче с ним будет работать. Просто он тоже обработан мной. Так как этот код у вас входит в пример для переключения между типом подсказок.
 Hidden text
| Code: |
# путь к утилите ExifTool
Global gMediaExifX32 = COMMANDER_PATH & "\Plugins\wlx\ExifToolView\exiftool.exe"
Global gHintPipe = ""
Global gExifPID = 0, gExifStay = 1, gExifOut = TEMP & "\exiftool_out.txt", gExifArgs = TEMP & "\exiftool_args.txt"
If Not ProcessExist("exiftool.exe") Then
#gExifPID = 0
FileWrite(gExifArgs, "", "UTF-8 NOBOM")
ShellExec /TT /SW_HIDE %gMediaExifX32% "-stay_open True -@ ""%gExifArgs%"""
EndIf
Func ET(FileName, FieldIndex, UnitIndex)
If StrPos(FileGetAttr(FileName), "D") Then Return
If FieldIndex = 1 Then
#ProcessExecGetOutput /C:65001 gHintPipe %gMediaExifX32% ' -G -S -lang ru "%FileName%"'
gHintPipe = GetExifInfo(FileName)
gHintPipe = StrPart(gHintPipe, ": ", 1)
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=Russian -G -S -lang ru "%FileName%"'
ProcessExecGetOutput ansi %gMediaExifX32% '-charset filename=Russian -lang ru "%FileName%"'
Else
If FileExist(gExifOut) Then
DllCall("kernel32.dll\DeleteFileW", "Wstr", gExifOut)
EndIf
#Local sArgs = "-W+!" & auCRLF & gExifOut & auCRLF & FileName & auCRLF & "-execute" & auCRLF
# Local sArgs = "-G" & auCRLF & _
# "-S" & auCRLF & _
# "-lang" & auCRLF & _
# "ru" & auCRLF & _
# "-W+!" & auCRLF & gExifOut & auCRLF & FileName & auCRLF & "-execute" & auCRLF
Local sArgs = "-lang" & auCRLF & _
"ru" & auCRLF & _
"-W+!" & auCRLF & gExifOut & auCRLF & FileName & auCRLF & "-execute" & auCRLF
Static 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, 0, "UTF-8")
DllCall("kernel32.dll\DeleteFileW", "Wstr", gExifOut)
Break
EndIf
Sleep(20) # time-out
Next
Return ansi
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
|
Я закомментил несколько ваших строк, чтобы русский язык появился. При -S названия полей могут быть только на английском. А при -G обязательно будут выводиться группы. Что, конечно, не нужно. Если эти ключи убрать и попытаться использовать StrPart(String, ": ", 1) у вас получится как у меня, вывод только одного поля. |
|
| Back to top |
|
 |
AkulaBig
Joined: 03 Dec 2008 Posts: 620
|
(Separately) Posted: Thu Oct 01, 2026 22:15 Post subject: |
|
|
Orion9
Уф, решил проблему. Всего-то переменную ansi, в которую получаем результат, надо было объявить Static, а не Local. |
|
| 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
|