Orion9

|
Posted: Thu May 14, 2026 00:08 Post subject: |
|
|
| AkulaBig wrote: | | Попробую, как время выберу |
Я просто подумал, что если такая скорость устроит, то нет смысла заморачиваться с чтением из stdout. Выигрыш все-равно будет минимальный. Болван уже дал решение, как считать данные с чужой консоли, но адаптировать это решение под Autorun лень, да и нет смысла. Прирост в скорости и так очевиден — через временный файл работает быстро.
 Hidden text Если чужой процесс уже вывел текст в окно консоли, этот текст находится в экранном буфере (Screen Buffer). Чтобы прочитать его через API, используется AttachConsole в связке с GetStdHandle и ReadConsoleOutputCharacterW.Ниже представлен рабочий скрипт для AutoHotkey v2, который подключается к консоли чужого процесса по его PID, считывает весь текст из его экранного буфера и отключается.
| Code: | #Requires AutoHotkey v2.0
; --- ТЕСТОВЫЙ ЗАПУСК (для демонстрации) ---
; Запустим скрытый cmd.exe, который сделает вывод, чтобы нам было что читать
DetectHiddenWindows(true)
Run(A_ComSpec " /c dir C:\", , "Hide", &targetPID)
WinWait("ahk_pid " targetPID)
Sleep(500) ; Даем команде dir время отработать и заполнить буфер
; --- ОСНОВНОЙ ВЫЗОВ ФУНКЦИИ ---
textOutput := ReadConsoleBufferByPID(targetPID)
MsgBox(textOutput, "Результат чтения чужой консоли")
; Закрываем тестовый процесс
ProcessClose(targetPID)
ExitApp
; --- ФУНКЦИЯ ДЛЯ ЧТЕНИЯ БУФЕРА ЧУЖОГО ПРОЦЕССА ---
ReadConsoleBufferByPID(pid) {
; 1. Отключаемся от нашей текущей консоли (если она была)
DllCall("FreeConsole")
; 2. Привязываемся к консоли чужого процесса по его PID
if !DllCall("AttachConsole", "UInt", pid) {
err := DllCall("GetLastError")
return "Ошибка: Не удалось вызвать AttachConsole. Код ошибки: " err
}
; 3. Получаем дескриптор буфера вывода (STD_OUTPUT_HANDLE = -11)
hStdOut := DllCall("GetStdHandle", "Int", -11, "Ptr")
if (hStdOut == -1 || hStdOut == 0) {
DllCall("FreeConsole")
return "Ошибка: Не удалось получить GetStdHandle."
}
; 4. Получаем размеры экранного буфера консоли
; Структура CONSOLE_SCREEN_BUFFER_INFO занимает 22 байта
csbi := Buffer(22, 0)
if !DllCall("GetConsoleScreenBufferInfo", "Ptr", hStdOut, "Ptr", csbi) {
err := DllCall("GetLastError")
DllCall("FreeConsole")
return "Ошибка: Не удалось получить инфо о буфере. Код ошибки: " err
}
; Читаем размеры буфера из структуры (размер по оси X и Y)
dwSizeX := NumGet(csbi, 0, "Short")
dwSizeY := NumGet(csbi, 2, "Short")
; Общее количество символов для чтения
totalChars := dwSizeX * dwSizeY
if (totalChars <= 0) {
DllCall("FreeConsole")
return ""
}
; 5. Выделяем буфер под текст (2 байта на символ для UTF-16/Unicode)
textBuffer := Buffer((totalChars + 1) * 2, 0)
; Координаты начала чтения (0, 0) — упакованы в 4 байта (DWORD)
dwReadCoord := 0
; 6. Читаем символы из консоли
bytesRead := 0
if !DllCall("ReadConsoleOutputCharacterW",
"Ptr", hStdOut,
"Ptr", textBuffer,
"UInt", totalChars,
"UInt", dwReadCoord,
"UInt*", &bytesRead := 0)
{
err := DllCall("GetLastError")
DllCall("FreeConsole")
return "Ошибка при чтении буфера ReadConsoleOutputCharacter. Код: " err
}
; 7. Обязательно освобождаем чужую консоль
DllCall("FreeConsole")
; 8. Преобразуем буфер в строку AHK
rawText := StrGet(textBuffer, bytesRead, "UTF-16")
; Форматируем текст: разбиваем сплошную строку обратно на строки по ширине консоли
formattedText := ""
Loop dwSizeY {
offset := ((A_Index - 1) * dwSizeX) + 1
line := SubStr(rawText, offset, dwSizeX)
; Убираем лишние пробелы в конце строки, которые консоль добавляет для заполнения экрана
line := RTrim(line, " `t`r`n")
if (line != "")
formattedText .= line "`n"
}
return RTrim(formattedText, "`n")
}
|
Кстати, в Autohotkey можно попробовать считать данные StdOut через ComObject. Не уверен, что получится с ExifTool, но был такой пример в этом топике. Там, кстати, и перевод из досовской кодировки используется. Я вам, наверное, ерунду написал про
| Code: | buf.SetStr(ansi, 0, nSize, "CP:866")
utf8 = buf.GetStr(0, nSize, "CP:65001") |
|
|