1 (изменено: 404, 2014-12-17 01:30:07)

Тема: VBS:Как при помощи VBS получить текст из окна консольного приложения?

Нужно из VBScript получить текст из окна консольного приложения, назовём его "abcd.exe" (старая 16-бит DOS программа).

Пробую с помощью DynamicWrapperX и функций WinAPI: GetStdHandle и ReadConsoleOutputCharacter:

Set ws = WScript.CreateObject("WScript.Shell")

Set DX = CreateObject("DynamicWrapperX")

DX.Register "kernel32.dll",  "ReadConsoleOutputCharacter","i=hSlpL",   "r=l" 
DX.Register "kernel32.dll",  "GetStdHandle",              "i=l",       "r=h"

ws.Run("abcd.exe") :WScript.Sleep 2000

sh = DX.GetStdHandle(-11)

n = 100
s = Space(n)

coord = Space(2)
DX.NumPut 0, coord, 0, "n"
DX.NumPut 0, coord, 2, "n"

res = DX.ReadConsoleOutputCharacter(sh, s, n, coord, n)

msgbox(s)

Но GetStdHandle возвращает 0, т. е. не удаётся получить указатель на буфер экрана окна консоли. Дело тут не в программе "abcd.exe", пробовал и с cmd.exe, результат тот же.

Соответственно, ReadConsoleOutputCharacter возвращает False.

Смущает, что у GetStdHandle нет среди аргументов указателя на окно или процесс.

Также пробовал запускать программу "abcd.exe" с помощью Exec, чтобы потом прочитать её StdOut. Но она открывается, и сразу закрывается

Есть идеи?

2 (изменено: Flasher, 2014-12-16 22:52:16)

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

404 пишет:

Также пробовал запускать программу "abcd.exe" с помощью Exec, чтобы потом прочитать её StdOut. Но она открывается, и сразу закрывается

Лучше код с программой покажите. А так, примеров с StdOut.ReadAll на форуме много.

3 (изменено: 404, 2014-12-16 23:10:03)

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

Flasher пишет:
404 пишет:

Также пробовал запускать программу "abcd.exe" с помощью Exec, чтобы потом прочитать её StdOut. Но она открывается, и сразу закрывается

Лучше код с программой покажите.

Ну вот:

Set ws = CreateObject("WScript.Shell")

Set ex = ws.Exec("abcd.exe")

Do While ex.Status = 0
  WScript.Sleep 100
Loop

MsgBox ex.StdOut.ReadAll

При этом программа "abcd.exe" открывается, и сразу закрывается; MsgBox выдаёт пустую строку.

Если вместо "abcd.exe" запустить, например, "ping 127.0.0.1", работает нормально.

4

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

Значит, она ничего и не выводит без ключей и параметров. ping.exe - чем не программа? И где можно скачать abcd.exe?

5 (изменено: 404, 2014-12-17 02:43:45)

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

Flasher пишет:

Значит, она ничего и не выводит без ключей и параметров.

Выводит. Если просто её запустить, не из скрипта, она нормально работает. Как минимум выводит экран приветствия и ожидает ввода с клавиатуры.

6 (изменено: 404, 2014-12-17 05:01:57)

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

Заработал такой код

Set ws = WScript.CreateObject("WScript.Shell")

Set DX = CreateObject("DynamicWrapperX")

DX.Register "user32.dll",   "GetForegroundWindow",                    "r=h"
DX.Register "user32.dll",   "GetWindowThreadProcessId",  "i=hL",      "r=l"
DX.Register "kernel32.dll", "AttachConsole",             "i=l",       "r=l"
DX.Register "kernel32.dll", "GetStdHandle",              "i=l",       "r=h"
DX.Register "kernel32.dll", "ReadConsoleOutputCharacter","i=hSlpL",   "r=l"

ws.Run("abcd.exe") :WScript.Sleep 2000

wh = DX.GetForegroundWindow()
pid= 0
wh = DX.GetWindowThreadProcessId(wh, pid)
res= DX.AttachConsole(pid)
sh = DX.GetStdHandle(-11)

n = 100
s = Space(n)

x = 10 :y = 3  'координаты экрана, откуда надо начинать чтение
coord = y*2^16 + x

res = DX.ReadConsoleOutputCharacter(sh, s, n, coord, n)

msgbox(s)

:)

7 (изменено: Flasher, 2014-12-17 02:50:59)

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

Система "ниппель", конечно, но вот что у меня вышло:

With CreateObject("WScript.Shell")
  If InStrRev(WScript.FullName, "WScript.exe") Then
    .Run "CScript.exe //NoLogo """ & WScript.ScriptFullName & """", 0
  Else
    Set Exe = .Exec("RADMODLS.EXE")
    For i = 1 to 12
      Exe.StdIn.WriteLine "N"
    Next
    .PopUp Exe.StdOut.ReadAll
  End If
End With

Хотя я вообще не понял, зачем нужно подобные программы выводить в окно, к тому же существенно ограниченное по высоте.

8 (изменено: 404, 2014-12-17 02:44:07)

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

Flasher пишет:

вот что у меня вышло:

Э-мм, а у меня это не работает.
Всегда выполняется условие If InStrRev(WScript.FullName, "WScript.exe").
Если конструкцию If убрать и оставить только кусок Set Exe = .Exec… MsgBox Exe.StdOut.ReadAll, то программа запускается и тут же закрывается, а скрипт выдаёт ошибку:
Ошибка: Идёт закрытие канала.
Код: 800700E8
Источник: (null)

ОС Windows 7 32-бит, пользователь с правами администратора.

9

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

Скрипт должен лежать в той же папке, что и программа, запускать обычным вызовом по Enter/даблклик.

10

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

Flasher пишет:

Скрипт должен лежать в той же папке, что и программа, запускать обычным вызовом по Enter/даблклик.

Да, всё так и делаю.

11

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

Кавычку добавил. Проверьте. В пути, наверно, пробелы есть.

12 (изменено: 404, 2014-12-17 02:46:07)

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

Flasher пишет:

Кавычку добавил. Проверьте. В пути, наверно, пробелы есть.

Теперь заработало. Почти ) Показывает MsgBox только после того, как через диспетчер задач убить процесс ntvdm.exe :-/

UPD: А, всё, заработало нормально. Один подвисший ntvdm.exe в списке процессов мешал.

Большое спасибо.

13 (изменено: Flasher, 2014-12-17 02:45:59)

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

Я там малюсенькую правку ранее вносил, после кот. не должно этого быть.

Какой-то один подвисший ntvdm.exe в списке процессов мешал.

Есть убрать, то с первого раза и старый вариант сработает. Нужно использовать текущий.

14

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

Зaменил MsgBox, пусть хоть побольше влезает.

15 (изменено: 404, 2014-12-17 03:28:07)

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

А как в некоторый момент, до завершения работы программы, прочитать n последних символов вывода?
С помощью .StdOut.Read(n) или ReadLine листать с начала… но не соображу, как определить, где "текущий конец" StdOut.

16

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

Сразу никак (точнее проблематично). Конкретно тут нужно подсчитать число пропускаемых строк сначала и пройтись циклом For/to, вызывая Exe.StdOut.SkipLine, а потом уже читать через ReadAll.

17

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

Ok.

18 (изменено: Flasher, 2014-12-17 03:57:25)

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

+ Либо так:
n = 5 ' число последних строк

With CreateObject("WScript.Shell")
  If InStrRev(WScript.FullName, "WScript.exe") Then
    .Run "CScript.exe //NoLogo """ & WScript.ScriptFullName & """", 0
    WScript.Quit
  Else
    Set Exe = .Exec("RADMODLS.EXE")
    For i = 1 to 12 : Exe.StdIn.WriteLine "N" : Next
    All = Split(Exe.StdOut.ReadAll, vbnewline) : Max = Ubound(All)
    For i = Max - n to Max - 1 : S = S & vbNewLine & All(i) : Next
    .Popup Mid(S, 3)
  End If
End With

19 (изменено: 404, 2014-12-17 04:02:46)

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

Но тут вы запускаете Exe.StdOut.ReadAll уже после завершения работы программы?

Дело в следующем.
Я сейчас ввожу в программу данные просто через эмуляцию ввода с клавиатуры и пауз WScript.Sleep t
В некоторый момент программа начинает расчёт, который может длиться 2 секунды, а может 20 минут. Я сейчас вычисляю требуемую паузу "на глазок". А вместо этого хотел следить, когда программа сообщит на экране об окончании расчёта, и затребует дальнейший ввод с клавиатуры.
Т. е. хотел циклически Do While… WScript.Sleep 100 :Loop проверять последнюю выведенную на экран строку.

С помощью варианта с WinAPI:ReadConsoleOutputCharacter вроде получается.

20

Re: VBS:Как при помощи VBS получить текст из окна консольного приложения?

После завершения всех действий кроме закрытия, разумеется.
Если консоль не требует скрытия, то зачем вообще какие-то иные окна?
Можно вводить данные через InputBox и передавать через WriteLine. Только нужно заведомо знать на каком этапе выводить информацию, знать число последующих строк.