Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   AutoIt (http://forum.oszone.net/forumdisplay.php?f=103)
-   -   [решено] Обмен данными с консольным приложением (http://forum.oszone.net/showthread.php?t=205012)

Coutty 17-04-2011 20:14 1660407

Обмен данными с консольным приложением
 
Вложений: 1
Хочу написать свой GUI к консольному приложению, однако организовать обмен данными не получается.
Код:

#include <Constants.au3>

AutoItSetOption("ProvideRunStdout", 1)
AutoItSetOption("ProvideRunStdin", 1)

$PID = Run("gnugo.exe --mode gtp", '', @SW_HIDE, $STDOUT_CHILD + $STDIN_CHILD)
StdinWrite($PID, "version")  ; запрашиваем версию программы
MsgBox(0,0, StdoutRead($PID))  ; и выводим его в окне сообщения

Если запускать программу из консоли с данными параметрами, то там будет пустая строка, ожидающая ввода команд. Например, на запрос version она выдаёт = 3.6. На одни запросы ответ мгновенный, на другие - "после раздумий". Но даже с простым запросом версии ничего не получается. Скрипт просто не передаёт данные программе.

Нашёл на форуме другой вариант:
Код:

#include <Constants.au3>
#include <Encoding.au3>

AutoItSetOption("ProvideRunStdout", 1)
AutoItSetOption("ProvideRunStdin", 1)

Local $PID = Run(@ComSpec & " /C gnugo.exe --mode gtp", '', @SW_HIDE, $STDOUT_CHILD + $STDIN_CHILD + $STDERR_CHILD)
Local $line

StdinWrite($PID, "version")  ; запрашиваем версию программы
While 1
    $line = StdoutRead($PID) ; и ждём ответа
    If @error Then ExitLoop
WEnd

While 1
    $line = StderrRead($PID)
    If @error Then ExitLoop
    MsgBox(0, "STDERR read:", $line)
WEnd

MsgBox(0,0, _Encoding_866To1251($line))

Здесь вообще никакой реакции - скрипт повисает в памяти вместе с программой.

Подскажите, пожалуйста, что делать) Скрипты и программа прилагаются.

Как разукрашивать скрипты для форума - не знаю, поэтому использую тэг code.

kaster 17-04-2011 20:59 1660431

Вот небольшой пример, попробуй вставить свою программу и посмотреть
Код:

; Demonstrates StdoutRead()
#include <Constants.au3>
#include <Encoding.au3>
#include <GUIConstantsEx.au3>
$myapp = 'ping ya.ru'
$hGUI = GUICreate('My Apps output stream', 500, 200)
$hEdit = GUICtrlCreateEdit('', 10, 10, 480, 150)
$hButtonStart = GUICtrlCreateButton('Start', 10, 170, 235, 20)
$hButtonStop = GUICtrlCreateButton('Stop', 255, 170, 235, 20)
;$hButtonEnd =
GUISetState()

Do
        $msg = GUIGetMsg()
        Switch $msg
                Case $hButtonStart
                        Local $pid = Run($myapp, '', @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)
                        GUICtrlSetData($hEdit, '')
                        While 1
                                $msg = GUIGetMsg()
                                $line = StdoutRead($pid)
                                If @error OR $msg = $hButtonStop Then
                                        ProcessClose($pid)
                                        GUICtrlSetData($hEdit, GUICtrlRead($hEdit) & '-------------- Stopped -----------------')
                                        ExitLoop
                                EndIf
                                If $line Then GUICtrlSetData($hEdit, GUICtrlRead($hEdit) & _Encoding_OEM2ANSI($line))
                        Wend
        EndSwitch
Until $msg = $GUI_EVENT_CLOSE


kaster 17-04-2011 21:22 1660443

что-то не сразу сообразил, что программа требует интеракцию с пользователем. посмотрю, что можно сделать

kaster 17-04-2011 22:25 1660502

видно, это особенности приложения, но оно не дает взаимодействовать с собой при вызове из скрипта перенаправленными потоками, при первом же приглашении на ввод данных закрывается. вот макет gui, может кто сможет разобраться, так хотя бы GUI не надо будет делать :)
Код:

; Demonstrates StdoutRead()
#include <Constants.au3>
#include <Encoding.au3>
#include <GUIConstantsEx.au3>
$myapp = 'gnugo'
$hGUI = GUICreate('My Apps output stream', 500, 200)
$hEditOut = GUICtrlCreateEdit('', 10, 10, 235, 150)
$hEditIn = GUICtrlCreateEdit('', 255, 10, 235, 150)
$hButtonStart = GUICtrlCreateButton('Start', 10, 170, 150, 20)
$hButtonSend = GUICtrlCreateButton('Send comm', 175, 170, 150, 20)
$hButtonStop = GUICtrlCreateButton('Stop', 340, 170, 150, 20)
GUISetState()

Do
        $msg = GUIGetMsg()
        Switch $msg
                Case $hButtonStart
                        Local $pid = Run($myapp, @ScriptDir, @SW_HIDE, $STDOUT_CHILD)
                        GUICtrlSetData($hEditOut, '')
                        GUICtrlSetState($hButtonStart, $GUI_DISABLE)
                        _OutWait()
                Case $hButtonSend
                        StdInWrite($pid, GUICtrlRead($hEditIn) & @CRLF)
                        GUICtrlSetData($hEditIn, '')
                        _OutWait()
        EndSwitch
Until $msg = $GUI_EVENT_CLOSE

Func _OutWait()
        While ProcessExists($pid)
                $msg = GUIGetMsg()
                $line = StdoutRead($pid)
                If $msg = $hButtonStop Then
                        ProcessClose($pid)
                        GUICtrlSetData($hEditOut, GUICtrlRead($hEditOut) & '-------------- Stopped -----------------')
                        GUICtrlSetState($hButtonStart, $GUI_ENABLE)
                        ExitLoop
                EndIf
                If $line Then GUICtrlSetData($hEditOut, GUICtrlRead($hEditOut) & _Encoding_OEM2ANSI($line))
                If StringRegExp($line, '\(\d\):') Then ExitLoop
        Wend
EndFunc


Coutty 18-04-2011 03:59 1660637

Да, прочитать первичные данные мне удавалось (если вызывать gnugo без параметров), но вот передать что-то... В --mode gtp вообще ничего не выходит (ну здесь-то просто не выдаёт окно приветствия).
Цитата:

Цитата kaster
что-то не сразу сообразил, что программа требует интеракцию с пользователем »

Да. Надо:
1. Запустить
2. Передать команду (version или, например, d4, если без параметров запускать)
3. Прочитать ответ
4. Ожидать следующей команды
Дальше, надеюсь, разберусь.
Цитата:

Цитата kaster
видно, это особенности приложения, но оно не дает взаимодействовать с собой при вызове из скрипта перенаправленными потоками »

Существует уже куча GUI различной сложности на разных языках (по крайней мере на Java и C++) и даже есть возможность подключения по технологии клиент-сервер, значит как-то всё должно работать. Но нет той оболочки, которая нужна мне.

kaster 18-04-2011 05:43 1660654

Цитата:

Цитата Coutty
Существует уже куча GUI различной сложности на разных языках »

я имел в виду особенность именно в AutoIt, т.к. после перехвата потока программа сразу завершается

Coutty 18-04-2011 18:26 1661121

О! Добился прогресса. Удалось получить ответ от программы.
Код:

#include <Constants.au3>

AutoItSetOption("ProvideRunStdout", 1)
AutoItSetOption("ProvideRunStdin", 1)

$PID = Run("gnugo.exe --mode gtp", '', @SW_HIDE, $STDIN_CHILD + $STDOUT_CHILD)
Sleep(1000)                            ; даём время gnugo для запуска
StdinWrite($PID, "version" & @CRLF)    ; запрашиваем номер версии

$line = StdoutRead($PID, 1)            ; читаем поток
MsgBox(0,0, $line)

Основные изменения:
1. Даю время на запуск программы. Можно и увеличить на несколько секунд, ничего страшного.
2. При передаче команды добавляем <Enter> (@CRLF)
3. При чтении ответа указываем второй параметр. В справке написано, что это означает максимальное количество прочитываемых символов, но почему-то и 1, и 100 дают одинаковый результат - читается всё.

Итак, ответ получен. Но возникла сложность на следующем этапе - если теперь передать вторую команду
Код:

StdinWrite($PID, "showboard" & @CRLF)
$line = StdoutRead($PID, 1)
MsgBox(0,0, $line)

то ответ получаем тот же, что и на первую. Даже если поставить секундный интервал ожидания между ними.
Если же вставить "заглушку" StdinWrite($PID), то скрипт завершается на этой инструкции.

Если передавать сразу две команды:
Код:

StdinWrite($PID, "version" & @CRLF & "showboard" & @CRLF)
то получаем ответ на обе, но следующий отдельный запрос выдаёт повтор.

kaster 18-04-2011 21:35 1661232

Coutty, у меня твой код ничего не показывает. пустой msgbox

Coutty 19-04-2011 03:51 1661430

Весьма странно, у меня и сегодня работает...
Но, наверное, не стоило начинать это на AutoIt. Вот только с C# я тем более не разобрался >_<

Coutty 19-04-2011 19:40 1661905

Мммм... можно сказать, что решилось.
1. Отсылаю команду №1
2. Читаю ответ
3. Отсылаю команду №2
4. Жду 0,5 сек.
5. Читаю ответ

Так ответы получаются разные. Но тоже не совсем гладко. Второй ответ включает в себя и первый тоже. Таким образом, возникает проблема разбора. Вот если бы предыдущий ответ удалялся...
К счастью, протокол GTP предусматривает нумерацию запросов и ответов, т.ч. здесь всё-таки можно что-то придумать.

"Окончательный" код

Код:

#include <Constants.au3>

AutoItSetOption("ProvideRunStdout", 1)
AutoItSetOption("ProvideRunStdin", 1)

$PID = Run("gnugo.exe --mode gtp", '', @SW_HIDE, $STDIN_CHILD + $STDOUT_CHILD)
Sleep(1000)  ; даём время на запуск
StdinWrite($PID, "1 version" & @CRLF)  ; передаём первую команду

$line = StdoutRead($PID, 1) ; читаем ответ
MsgBox(0,0, $line)


StdinWrite($PID, "2 showboard" & @CRLF) ; передаём вторую команду
Sleep(500) ; выжидаем

$line = StdoutRead($PID, 1) ; читаем ответ
MsgBox(0,0, $line)



Время: 14:46.

Время: 14:46.
© OSzone.net 2001-