Autorun

Обсуждение только плагинов и утилит для Total Commander.

Модераторы: Avada, CaptainFlint, Nik, d-view, Моторокер

Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

AkulaBig
Как-то я забыл, что есть вариант с DllCall. Можно заменить ShellExec на

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

DllCall("kernel32.dll\DeleteFileW", "Wstr", gExifOut)
И вот так, кажись, лучше стало. Но "дичь" все-равно творится. Думаю, есть какая-то глубокая проблема в самом Autorun. Как-то он неповоротливо работает с наборами колонок. Не зря вы писали, что WinScriptAdv может дать ему фору. Скорее всего без пояснений от автора не обойтись.

Можно еще попробовать писать в файл через DllCall вместо объекта BinaryFile. Есть у меня подозрения, что этот объект тоже медленно разворачивается. Изначально хотел через FileWrite делать, но оказалось, что эта функция не может записать в файл аргументов (gExifArgs) из-за ошибки доступа, поэтому и пришлось использовать BinaryFile с опцией "a". Еще одна проблема Loopback на заметку. Но ведь можно и через DllCall попробовать, ничто вроде не мешает. Правда придется с параметрами разбираться, чтобы не словить ту же ошибку, что и FileWrite. Пример с такой записью у меня остался, но его придется адаптировать, наверное

[cut]

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

Func WriteTest()
    Local GENERIC_WRITE = 0x40000000, CREATE_ALWAYS = 2, FILE_ATTRIBUTE_NORMAL = 128
    Local bytes = 0
    Local out = "текст для записи"
    Local hFile, nBytes = StrLen(out)
    hFile = DllCall("CreateFileW", _
            "wstr",  file, _
            "dword", GENERIC_WRITE, _
            "dword", 0, _
            "ptr",   0, _
            "dword", CREATE_ALWAYS, _
            "dword", FILE_ATTRIBUTE_NORMAL, _
            "ptr",   0, "handle")    
    DllCall("WriteFile", "handle", hFile, 'str', out, 'dword', nBytes, "dword*", @bytes, 'ptr', 0)
    DllCall("CloseHandle", "handle", hFile)
EndFunc
[/cut]
Возможно, это поднимет скорость, но мне кажется, если делать всерьез, то лучше, наверное, через WinScriptAdv - Autorun пока не показывает надежности.
AkulaBig писал(а):Файл очищается с помощью команды break. Не знал о таком ее применении.
Тоже не знал. Может просто болванится? Я не проверял )
AkulaBig писал(а):Интересно, чтобы -execute сработало файл именно удалять нужно? А может достаточно изменения?
Да можно, конечно. Просто удаление файла гарантирует, что в новом файле будут актуальные данные. Если не удалять, где гарантии, что все будет записываться правильно. Это нужно как-то проверять.
AkulaBig
Сообщения: 639
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

Orion9 писал(а):Как-то я забыл, что есть вариант с DllCall.
Я с утра тоже об этом подумал.
Orion9 писал(а):Можно еще попробовать писать в файл через DllCall вместо объекта BinaryFile.
А вот про это не знал. Нигде до этого не приходилось этот объект использовать.
Orion9 писал(а):если делать всерьез, то лучше, наверное, через WinScriptAdv - Autorun пока не показывает надежности.
У меня это уже сделано в рабочей сборке. Другое дело, что скорость работы ET и там хочется увеличить, но работает. Еще надо учитывать, что скорость обработки разных расширений разная. djvu, pdf тяжелые. То-есть вы сейчас можете мне выложить скорость обработки 100 doc, которая будет в 10 раз меньше скорости обработки двух pdf.
Orion9 писал(а):Это нужно как-то проверять.
Проверю. Это самое простое на данный момент.
AkulaBig
Сообщения: 639
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

В общем вот полностью рабочее решение:

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

Func ET(FileName, FieldIndex, UnitIndex)
	If StrPos(FileGetAttr(FileName), "D") Then Return

	Local ExifToolPID = 0, ExifToolOut = TEMP & "\exiftool_out.txt", ExifToolArgs = TEMP & "\exiftool_args.txt"

	ExifToolPID = ProcessGetId("exiftool.exe")
	If ExifToolPID = 0 Then
		FileWrite(ExifToolArgs, "", "UTF-8 NOBOM")
		ShellExec /TT /SW_HIDE %util_ET% "-stay_open True -@ ""%ExifToolArgs%"""
	EndIf

	ShellExec /SW_HIDE /WAIT %COMSPEC% "/c break > ""%ExifToolOut%"""

	Local sArgs = "-f" & auCRLF & _
		"-s3" & auCRLF & _
		"-m" & auCRLF & _
		"-q" & auCRLF & _
		"-q" & auCRLF & _
		"-Title" & auCRLF & _
		"-W+!" & auCRLF & _
		ExifToolOut & auCRLF & FileName & auCRLF & "-execute" & auCRLF

	Local obj = BinaryFile(ExifToolArgs, "a")
	obj.WriteStr(sArgs, "", "UTF-8")
	Free(obj)

	# ждем, пока ExifTool создаст файл (цикл ожидания)
	Local WaitCount = 0
	While Not FileExist("%ExifToolOut%")
		Sleep 50
		WaitCount = WaitCount + 1
		ansi = FileRead(ExifToolOut)
		if WaitCount > 50 then Break
	Wend

	Return ansi
EndFunc
Никакого интереса оно не представляет. Я и без -stay_open так могу. Зато теперь все понятно. Проблема Ауторан в том, что он почему-то выводит данные не для каждого файла, а для всех сразу. Поэтому идет задержка для всех файлов, а потом данные выводятся мгновенно.
Время ожидания задается кодом ожидания. Если его убрать, данные выводятся сразу, но пустыми. Пришлось поставить 2,5 сек, чтобы все данные прочитались. Ну и обратите внимание на мелочи. /WAIT ставить обязательно. Оно никак не влияет на первоначальную задержку. Break отлично работает. Нет файла, создает его. Есть файл, очищает его. Преимущество в том, что не надо делать проверку и код сокращается до одной строки.
Осталось только проверить работу с au3. Вдруг там что-то -stay_open изменит.
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

AkulaBig
Вчера небольшую фигню написал.

Ошибка с доступом была не с FileWrite, а с FileAppend: именно эта функция предназначена для записи в конец файла, но через нее не удалось решить. Вероятно, есть какая-то проблема с правами, через BinaryFile получается же. В общем, это остается Loopback на заметку. Хотя если он вернётся, первым партийным заданием для него будет научить нейросеть работать с Autorun :D Тогда код можно будет тянуть, как с конвеера ) Возможно, этот код не будет полностью рабочим, но в качестве заготовок сойдет.

Сейчас для Autohotkey эта схема работает идеально. Достаточно просто спростить, и будет ответ:

[cut]

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

Использование WriteFile через DllCall — это отличный способ работать с файлами на низком уровне, минуя стандартные буферы AHK.Ниже полный пример для AutoHotkey v2, который открывает файл (или создает его), перемещает указатель в конец (для режима Append) и записывает текст.autohotkey; Настройки
FilePath := A_ScriptDir "\example_log.txt"
TextToWrite := "Новая строка лога через WriteFileW`r`n"

; 1. Открываем файл через CreateFileW
; Параметры: путь, доступ (0x40000000 = Generic_Write), общий доступ, 
; создание (4 = Open_Always), флаги (128 = Normal), шаблон
hFile := DllCall("kernel32.dll\CreateFileW", 
    "Str", FilePath,           ; lpFileName
    "UInt", 0x40000000,        ; dwDesiredAccess (GENERIC_WRITE)
    "UInt", 7,                 ; dwShareMode (Read/Write/Delete)
    "Ptr", 0,                  ; lpSecurityAttributes
    "UInt", 4,                 ; dwCreationDisposition (OPEN_ALWAYS)
    "UInt", 128,               ; dwFlagsAndAttributes (NORMAL)
    "Ptr", 0, "Ptr")           ; hTemplateFile

if (hFile = -1) {
    MsgBox "Не удалось открыть файл. Ошибка: " A_LastError
    return
}

; 2. Перемещаем указатель в конец файла (режим Append)
; Параметры: дескриптор, смещение, направление (2 = FILE_END)
DllCall("kernel32.dll\SetFilePointer", "Ptr", hFile, "Int", 0, "Ptr", 0, "UInt", 2)

; 3. Подготовка данных для записи (Unicode)
; Рассчитываем размер строки в байтах (длина * 2 для UTF-16)
BytesToWrite := StrLen(TextToWrite) * 2
Written := Buffer(4, 0) ; Буфер для получения количества записанных байт

; 4. Запись в файл через WriteFile
Success := DllCall("kernel32.dll\WriteFile", 
    "Ptr", hFile,              ; hFile
    "Str", TextToWrite,        ; lpBuffer
    "UInt", BytesToWrite,      ; nNumberOfBytesToWrite
    "Ptr", Written.Ptr,        ; lpNumberOfBytesWritten
    "Ptr", 0)                  ; lpOverlapped

; 5. Закрываем дескриптор (обязательно!)
DllCall("kernel32.dll\CloseHandle", "Ptr", hFile)

if Success
    MsgBox "Данные успешно добавлены в файл."
else
    MsgBox "Ошибка записи: " A_LastError
Используйте код с осторожностью.Что здесь происходит:CreateFileW: Ключевой момент — флаг OPEN_ALWAYS (4). Он открывает файл, если он есть, или создает новый, если его нет.SetFilePointer: Без этой функции WriteFile просто перезапишет начало файла. Флаг FILE_END (2) прыгает в самый конец, реализуя логику Append.Unicode: Мы используем WriteFile и передаем строку напрямую. Поскольку AHK v2 работает в Unicode, StrLen * 2 дает точный размер данных в байтах.CloseHandle: Если забыть закрыть дескриптор, файл будет "заблокирован" системой до завершения работы скрипта.⚠️ Важное замечание по кодировкеЭтот метод записывает "чистый" UTF-16 (Little Endian), который использует Windows. Если вам нужен UTF-8 или файл с BOM-меткой, перед записью строку нужно конвертировать через StrPut в отдельный буфер.Нужно ли добавить в пример конвертацию в UTF-8 перед записью?

Чтобы корректно работать с файлом, который может быть открыт другим процессом, нужно правильно настроить параметр dwShareMode в функции CreateFileW.В предыдущем примере мы использовали 7, что является комбинацией всех прав доступа. Вот как это работает:🛠 Ключевой параметр: dwShareModeЕсли другой процесс уже открыл файл, ваш DllCall вернет ошибку -1, если вы не укажете те же (или более широкие) права совместного доступа, которые запросил первый процесс.FILE_SHARE_READ (1): Разрешить другим читать файл.FILE_SHARE_WRITE (2): Разрешить другим писать в файл.FILE_SHARE_DELETE (4): Разрешить другим удалять или переименовывать файл.Итог (7): Максимальная совместимость.Обновленный код (AHK v2) с проверкой занятостиautohotkeyFilePath := A_ScriptDir "\shared_log.txt"
Text := "Запись в потенциально открытый файл`r`n"

; Пытаемся открыть файл с полным совместным доступом (7)
hFile := DllCall("kernel32.dll\CreateFileW", 
    "Str", FilePath, 
    "UInt", 0x40000000, ; GENERIC_WRITE
    "UInt", 7,          ; dwShareMode: READ(1) | WRITE(2) | DELETE(4)
    "Ptr", 0, 
    "UInt", 4,          ; OPEN_ALWAYS
    "UInt", 128,        ; NORMAL
    "Ptr", 0, "Ptr")

if (hFile = -1) {
    ErrorNum := A_LastError
    if (ErrorNum = 32) ; ERROR_SHARING_VIOLATION
        MsgBox "Файл жестко заблокирован другим процессом (Sharing Violation)."
    else
        MsgBox "Ошибка открытия: " ErrorNum
    return
}

; Блокировка области файла (опционально)
; Чтобы два процесса не писали одновременно в одну точку, 
; можно временно заблокировать хвост файла через LockFileEx.

; Переходим в конец
DllCall("kernel32.dll\SetFilePointer", "Ptr", hFile, "Int", 0, "Ptr", 0, "UInt", 2)

; Запись
Written := Buffer(4, 0)
DllCall("kernel32.dll\WriteFile", "Ptr", hFile, "Str", Text, "UInt", StrLen(Text)*2, "Ptr", Written.Ptr, "Ptr", 0)

; Закрываем
DllCall("kernel32.dll\CloseHandle", "Ptr", hFile)
Используйте код с осторожностью.⚠️ Ограничения "Совместного доступа"Жесткая блокировка: Если другой процесс открыл файл с dwShareMode := 0, вы не сможете открыть его даже для чтения, пока тот процесс не закроет дескриптор. Тут WinAPI бессилен, нужно только ждать.Смещение указателя: Когда два процесса пишут в конец одного файла одновременно, может возникнуть ситуация "гонки".Решение: Используйте специальное смещение 0xFFFFFFFF в OVERLAPPED структуре или SetFilePointer непосредственно перед записью.Сетевые папки: На сетевых дисках блокировки могут работать с задержкой из-за кеширования Windows.💡 СоветЕсли вы часто сталкиваетесь с ошибкой 32 (Sharing Violation), попробуйте обернуть CreateFileW в небольшой цикл Loop с Sleep 100 и 5–10 попытками. Это стандартная практика для работы с логами, которые могут быть заняты антивирусом или си
[/cut]
А вот если бы он сразу выдавал готовый код, насколько это облегчило бы жизнь

[cut]

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

Func AppendToFile(FilePath, TextToWrite)
    FilePath = TEMP "\example_log.txt"
    TextToWrite = "Новая строка лога через WriteFileW`r`n"
    
    Static dwShareMode = 7 # Read/Write/Delete
    Static GENERIC_WRITE = 0x40000000, OPEN_ALWAYS = 4, NORMAL = 128
    
    hFile := DllCall("kernel32.dll\CreateFileW", _
        "Str", FilePath, _
        "UInt", GENERIC_WRITE, _
        "UInt", dwShareMode, _
        "Ptr", 0, _
        "UInt", 4, _
        "UInt", 128, _
        "Ptr", 0, "Ptr")
    
    If hFile = -1 Then Return -1
    
    # перемещение указателя в конец файла
    # дескриптор, смещение, направление (2 = FILE_END)
    DllCall("kernel32.dll\SetFilePointer", "Ptr", hFile, "Int", 0, "Ptr", 0, "UInt", 2)
    
    # размер строки в байтах (длина * 2 для UTF-16)
    BytesToWrite = StrLen(TextToWrite) * 2
    Written = 0 
    
    Success = DllCall("kernel32.dll\WriteFile", _
        "Ptr", hFile, _
        "WStr", TextToWrite, _
        "UInt", BytesToWrite, _
        "UInt*", @Written, _
        "Ptr", 0)
    
    DllCall("kernel32.dll\CloseHandle", "Ptr", hFile)
    
    If Success Then
       Return 0
    Else
       Return -2
    EndIf      
EndFunc
[/cut]
Я хотел было доделать этот пример до конца, но потом понял, что для работы с файлом ExifTool строку для записи надо еще в UTF-8 переводить. А объект BinaryFile сам это делает. В общем, решил в итоге перевести его в статик, чтобы он не создавался при каждом вызове, это должно немного поднять скорость. Сейчас весь фрагмент, очищенный от комментариев, выглядит так

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

If FileExist(gExifOut) Then
   DllCall("kernel32.dll\DeleteFileW", "Wstr", gExifOut)
EndIf
Local sArgs = "-G0"   & auCRLF & _            
              "-lang" & auCRLF & _
              "ru"    & auCRLF & _                     
              "-W+!"  & auCRLF & gExifOut & auCRLF & FileName & auCRLF & "-execute" & auCRLF       
Static obj = BinaryFile(gExifArgs, "a")    
obj.WriteStr(sArgs, "", "UTF-8")
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)
Next
Return ansi
Работает значительно лучше и стабильнее, но все-равно могут прошмыгивать пустые позиции, хоть и мало.
AkulaBig писал(а):Зато теперь все понятно. Проблема Ауторан в том, что он почему-то выводит данные не для каждого файла, а для всех сразу.
Причем это характерно только для 64-битной версии, в 32-битной такого нет. Об этом я в свое время писал Loopback, но он тогда не ответил. Кроме того, в обеих версиях при прокрутке панели ползунком повляются белые прямоугольные артефакты и начинается какая-та "дичь". В общем, есть проблемы. Очень всё сыро выглядит.
AkulaBig писал(а):Break отлично работает. Нет файла, создает его. Есть файл, очищает его.
Хех. Не подвёл болван!
AkulaBig писал(а): Осталось только проверить работу с au3. Вдруг там что-то -stay_open изменит.
Изменит однозначно. Но я бы vbs не скидывал со счетов. И сильно по поводу отключения VBScript на некоторых машинах не парился. На таких компах и сборкам делать нечего.
AkulaBig
Сообщения: 639
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

Orion9 писал(а):Причем это характерно только для 64-битной версии, в 32-битной такого нет.
Ах тыж, блин. А я столько времени потратил на попытку сделать код в Ауторан. В этом и есть вся причина. Попробовал в х32. Работает не хуже, чем на au3. Ну тогда вообще нет никакого смысла что-то городить. Понятно, что пока сансей не исправит глюк, про Ауторан можно забыть. Вот отлично работающий в х32 код, без всяких -stay_open:

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

Func ET1(FileName, FieldIndex, UnitIndex)
	Local pipe
	If StrPos(FileGetAttr(FileName), "D") Then Return
	ProcessExecGetOutput pipe %util_ET% '-T -m -q -q -Title "%FileName%"'
	If Not StrPos(pipe, "Error:") Then Return FixCPET(pipe)
EndFunc

Func ET(FileName, FieldIndex, UnitIndex)
	If StrPos(FileGetAttr(FileName), "D") Then Return

    Static a = List(), u = List()
    Local ansi, utf8, wrong = Chr(0xFFFD)

	Local param = " -f -s3 -m -q -q -Title "
	ClipPut("")

ShellExec("~/SW_HIDE /WAIT", COMSPEC, '/c ' & util_ET & param & '"' & FileName & '"' & ' | clip')

	ansi = ClipGet()
	ClipPut("")
	If Not StrPos(pipe, "Error:") Then Return FixCPET(pipe)
EndFunc
Единственное, огромная просьба к вам. Сами понимаете, в буфер приходит OEM. То-есть FixCPET(pipe) сначала надо из 866 перекодировать в 1251, а затем в утф. На au3 я это реализовал. Ниже увидите в коде. Можете помочь сделать это в Ауторан? Хочется закончить этот код. Пусть он будет не рабочий пока, но вдруг пригодится. Конечно я пока не буду писать код разделения значений полей. Но хочу чтобы база была сделана.
Orion9 писал(а):Изменит однозначно.
На данный момент я решил отказаться от реализации этой идеи. Очень мне не нравится, что все держится на wait. Мне кажется тогда надо ожидание выполнять не через временные интервалы, а через сравнение значений. Иначе это какая-то чудовищная потери скорости. Ладно, решу, тестить или не тестить.
Orion9 писал(а):Но я бы vbs не скидывал со счетов.
Ха, ха, ха. А я его не скинул со счетов. Я вам намекал на то, что такое накодировал. Но вы мою последнюю сборку не смотрели. Я просто хотел чтобы вы в работе посмотрели, да и код не по теме. Но тогда выкладываю здесь под катом:
[cut]

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

#NoTrayIcon

#include <Encoding.au3>

Local $program, $param, $filename, $iPID, $sOutput, $sUTF8_String, $aArray, $content, $content1, $content2, $content3, $content4, $content5, $content6, $content7, $content8, $content9, $content10, $content11, $content12, $content13, $content14, $content15, $content16, $content17, $content18, $content19, $content20, $content21, $content22, $content23, $content24, $content25, $content26, $content27, $content28, $content29, $content30, $content31

If StringInStr(FileGetAttrib($filename), "D") Then Exit

$program = EnvGet("util_ET")
$param = " -f -s3 -m -q -q -Title -Author -Subject -Description -Creator -Year -Company -FileCreateDate -FileModifyDate -LastModifiedBy -Paragraphs -Document-statisticParagraph-count -Lines -Pages -PageCount -Document-statisticPage-count -Words -Document-statisticWord-count -Characters -Document-statisticCharacter-count -Document-statisticTable-count -Document-statisticCell-count -Software -Application -CreatorTool -AppVersion -PDFVersion -DjVuVersion -Producer -Publisher -Generator -Security -DocSecurity -Encryption -Comments "

Local $VbsObj = ObjCreate("ScriptControl")
If @error Or Not FileExists("c:\Windows\System32\vbscript.dll") Then
	$iPID = Run(@ComSpec & " /C " & chr(34) & chr(34) & $program & chr(34) & $param & chr(34) & $filename & chr(34), "", @SW_HIDE, 0x2)
	While 1
		$sOutput &= StdoutRead($iPID)
		If @error Then ExitLoop
	WEnd
Else
	$VbsObj.Language = "VBScript"
	Local $Code = ""
	$Code &= 'On Error Resume Next' & @LF
	
	$Code &= 'Function ExifTool(program, param, filename)' & @LF
	$Code &= 'Dim objShell : Set objShell = CreateObject("WScript.Shell")' & @LF
	$Code &= 'objShell.Run "%COMSPEC% /c " & chr(34) & chr(34) & program & chr(34) & param & chr(34) & filename & chr(34) & " | clip" & chr(34), 0, True' & @LF
	$Code &= 'strOutput = CreateObject("htmlfile").ParentWindow.ClipboardData.GetData("text")' & @LF
	$Code &= 'With CreateObject("ADODB.Stream")' & @LF
	$Code &= '.Charset = "cp866"' & @LF
	$Code &= '.Open' & @LF
	$Code &= '.WriteText strOutput' & @LF
	$Code &= '.Position = 0' & @LF
	$Code &= '.Charset = "Windows-1251"' & @LF
	$Code &= 'ExifTool = .ReadText' & @LF
	$Code &= 'End With' & @LF
	$Code &= 'Set objShell = Nothing' & @LF
	$Code &= 'Set objWshExec = Nothing' & @LF
	$Code &= 'End Function' & @LF
	
	$VbsObj.AddCode($Code)
	$sOutput = $VbsObj.Run("ExifTool", $program, $param, $filename)
EndIf

; MsgBox(1, "", $sOutput)

$sOutput = StringReplace($sOutput, "-", " ")

$aArray = StringSplit($sOutput, @LF)

$sUTF8_String = _Encoding_IsUTF8Format($sOutput)
If $sUTF8_String Then
	$content = BinaryToString($aArray[1], 4)

Else
	$content = BinaryToString($aArray[1], 1)

EndIf

ConsoleWrite($content)
[/cut]
Из кода удалил поля по 34, чтобы не захломлять код.
Обратите внимание, не забыл я про vbs. Теперь он работает у меня в au3 :) Правда это только код для красоты. Надо либо au3 x32 использовать. Либо перенаправить на system32. Ну или использовать ТС х32. Известная проблема х64 систем. Ну и я про перекодировку. Как видите, я читаю из буфера 866 в 1251, а далее в утф. Вот хотелось-бы реализовать это в Ауторан. Если найдете минутку, помогите, пожалуйста.
Совсем забыл. Я-же добавил в WinScriptsAdv количество полей. А то 21 поле совсем мало. Сделал 40 вроде. На оф. форуме Гислера ссылку дал.
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

Даёшь 15000 строк на Autorun! :mrgreen:
https://wdho.ru/kMV2
https://www.upload.ee/files/19326966/TC_11.57.7z.html

По сравнению с предыдущей версией добавлено всего 500 строк, не густо за три месяца. Но если я продолжу в том же духе еще 30 лет, как Гислер, это будет 200000 строк! :mrgreen:
AkulaBig писал(а):сначала надо из 866 перекодировать в 1251, а затем в утф.
Всё так же через объект Buffer. Закинуть в нужной кодировке и вынуть в нужной кодировке

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

Local nSize = StrLen(text)
Local buf = Buffer(nSize)
buf.Zero()
buf.SetStr(ansi, 0, nSize, "CP:866")
utf8 = buf.GetStr(0, nSize, "CP:65001")    
Free(buf)
AkulaBig писал(а):На данный момент я решил отказаться от реализации этой идеи. Очень мне не нравится, что все держится на wait.
И все-таки опция -stay_open даёт прирост в скорости, даже значительный. А через файл пришлось делать по необходимости. Лучше сразу через stdout считывать. Был пример для au3, можно в теории попробовать.
AkulaBig писал(а):Если найдете минутку
Ну, если код выше не поможет, то только до лучших времён. Я на каникулы! :D
AkulaBig
Сообщения: 639
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

Orion9 писал(а):Ну, если код выше не поможет, то только до лучших времён.
Так конечно я в первую очередь попробовал.
Orion9 писал(а):Я на каникулы!
Понятно. Хорошего отдыха.
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

AkulaBig писал(а):Так конечно я в первую очередь попробовал.
Не работает?
AkulaBig
Сообщения: 639
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

Orion9 писал(а):Не работает?
Нет. Да ладно, на данном этапе это не важно.
Попробовал реализовать код на au3. Пока толком не работает. Но зато стал понятен алгоритм, в котором видно, что ET необходимо для каждого файла запустить, а потом закрыть. То-есть предполагаемое ускорение может быть только внутри данных для одного файла. А если ET не закрывать, она запускается для каждого файла. Попытка написать условие, если процесс запущен, по новой ET не запускать, приводит к тому, что скрипт не работает.
В общем для wdx-плагина алгоритм не рабочий.
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

AkulaBig
А если попробовать вариант с переключением кодовой страницы?

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

ShellExec("~/SW_HIDE /WAIT", COMSPEC, '/c chcp 65001>nul&&' & util_ET & param & '"' & FileName & '"' & ' | clip')
Должно и с пробелами прокатить

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

ShellExec("~/SW_HIDE /WAIT", COMSPEC, '/c chcp 65001 && ' & util_ET & param & '"' & FileName & '"' & ' | clip')
Возможно, придется экранировать кавычки в именах файлов, но работать по идее должно.
AkulaBig
Сообщения: 639
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

Orion9
Надо сначала чтобы сансей ошибку устранил.
Я тут решил ход конем сделать. Запуск ET сделать через Ауторан. Параметр TT несомненно удобная штука. А обработку через au3.

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

SetEnv ExifToolPID "0"
SetEnv ExifToolArgs "%TEMP%\exiftool_args.txt"
ShellExec /TT /SW_HIDE %util_ET% "-stay_open True -@ ""%ExifToolArgs%"""
ETPID = ProcessGetId("exiftool.exe") 
SetEnv ExifToolPID %ETPID%
Но пока скрипт на au3 не могу заставить вывести правильное значение. Он работает, но выдает текст об ошибки получения данных. Текст из скрипта, а не системный.
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

AkulaBig писал(а):Запуск ET сделать через Ауторан. Параметр TT несомненно удобная штука.
Да, очень удобная. Главное, чтобы процесс ET висел, а общаться с ним можно разными способами. Наиболее продвинутый вариант от ИИ был как раз для au3. Надеюсь, у вас получится. Ведь скорость должна кратно возрасти!
AkulaBig
Сообщения: 639
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

Orion9 писал(а):Надеюсь, у вас получится.
Возможно дело в том, при использовании Run в au3 задается вывод в нужный поток. Используется и IN и OUT. Хотя... В общем глухо как в танке. Потерзаю конечно еще.
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

AkulaBig
К сожалению, на счет au3 не могу ничего сказать, но сделал тест скорости на Autorun. Там речь действительно идет даже не о сверхзвуке, а о космических скоростях :D

Win+[ запуск exiftool для каждого файла. Win+] держит процесс открытым и взаимодействует с ним через файл аргументов. Вывод попадает во временный файл, откуда затем считывается. Если всё ровно, то байты обоих выводов должны совпасть, что и происходит. Но есть проблема с русскими именами файлов, пока не стал с этим разбираться.

Работает только на выделенных файлах. Попробуйте. Как у вас прирост?

[cut]

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

SetHotkeyAction /K:W /V:219 TestExiftoolSpeed 0
SetHotkeyAction /K:W /V:221 TestExiftoolSpeed 1

Static sExif = COMMANDER_PATH & "\Plugins\wlx\ExifToolView\exiftool.exe"
Static sExifOut = TEMP & "\exiftool_out.txt", sExifArgs = TEMP & "\exiftool_args.txt"

Func TestExiftoolSpeed(StayOpen)
    Local aSel = List(), sFile
    Local sPath = RequestCopyDataInfo("SP"), j, files = 0, str
    
    aSel.Text = GetSelectedItems(3, 0)
    
    If StayOpen = 1 And Not ProcessExist("exiftool.exe") Then
       FileWrite(sExifArgs, "", "UTF-8 NOBOM")       
       ShellExec /TT /SW_HIDE %sExif% "-stay_open True -@ ""%sExifArgs%""" 
       Sleep 100
       Local nPID = ProcessGetId("exiftool.exe") 
       If nPID = 0 Then Return MsgBox("Процесс ExifTool не запущен")
    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 & _
             "Объем данных: " & SizeFormat(StrLen(str), 0, 'B', 2) & auCRLF & _             
             "Время операции: " &  StrFormat("%.3f", T2) & " sec")
    Free(aSel)
    ClipPut(str)
EndFunc

Func ExiftoolInfo(FileName, StayOpen)
    If Not StayOpen Then
       ProcessExecGetOutput /C:65001 out %sExif% ' -charset filename=utf8 -G -S -lang ru "%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(20)
       Next
    EndIf   
   Return out
EndFunc
[/cut]
AkulaBig
Сообщения: 639
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

Orion9
Попробую, как время выберу. Сейчас надо понять, почему данные не читаются.
Ответить