1

Тема: AHK: Вывод StdOut в переменную скрипта

Помогите пожалуйста сделать вывод данных из консольного приложения в переменную скрипта. Хочу сделать обработчик mqtt команд, используя консольную утилиту mosquitto_sub.exe Суть в том, что утилита запускается, подключается к серверу и ждёт команды. То есть она не закрывается, а постоянно запущена. Как только команда получена, в окне утилиты появляется текст с командой. Мне надо, чтобы скрипт ahk периодически, например, раз в секунду сканировал окно утилиты и содержимое передавал в переменную ahk. Дальше я буду парсить результат. Спасибо!

2

Re: AHK: Вывод StdOut в переменную скрипта

Проверьте с помощью Window Spy, определяется ли ClassNN контрола, в котором появляется текст, и сам этот текст. Если да, тогда его можно получить с помощью ControlGetText.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

3

Re: AHK: Вывод StdOut в переменную скрипта

Нет, утилита консольная и ControlGetText в её окне не работает.

4

Re: AHK: Вывод StdOut в переменную скрипта

Ну можно непосредственно получать StdOut скриптом:

CMD := "ping -n 10 8.8.8.8"
shell := ComObjCreate("WScript.Shell")
exec := shell.Exec(CMD)
Sleep, 1000

while !exec.StdOut.AtEndOfStream {
   str := exec.StdOut.ReadLine()
   ToolTip % Decoding(str, "cp866")
}

Decoding(text, from, to = "CP0")  {
   VarSetCapacity(var, StrPut(text, to)*((to = "utf-16" || to = "cp1200") ? 2 : 1), 0)
   StrPut(text, &var, to)
   Return StrGet(&var, from)
}

Замените ping -n 10 8.8.8.8 на mosquitto_sub.exe.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

5

Re: AHK: Вывод StdOut в переменную скрипта

Спасибо огромное, то что надо! Я тоже пробовал типа: result :=  ComObjCreate("WScript.Shell").Exec("mosquitto_sub.exe -h 192.168.1.1 -p 1883 -t cmnd/sonoff/POWER").StdOut.ReadAll(),
но результат выводился только после закрытия mosquitto_sub.exe
Не подскажете ещё, как запустить CMD := "mosquitto_sub.exe -h 192.168.1.1 -p 1883 -t cmnd/sonoff/POWER" в скрытом окне?

6

Re: AHK: Вывод StdOut в переменную скрипта

При использовании метода exec такой возможности нет, но можно скрыть после запуска через WinHide. В коде Sleep, 1000 скорее всего лишнее.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

7

Re: AHK: Вывод StdOut в переменную скрипта

ok, я понял. Вместо Sleep, 1000 сделал:

WinWait, ahk_class ConsoleWindowClass
WinHide, ahk_class ConsoleWindowClass

Теперь и ожидание процесса и скрытие окна получилось) Ещё раз спасибо за помощь!!!

8 (изменено: teadrinker, 2019-03-19 15:52:30)

Re: AHK: Вывод StdOut в переменную скрипта

Ещё другой подход есть:

obj := {base:{__Set: Func("StdOutHandling")}}
CmdRet("ping -n 10 8.8.8.8", obj)
ToolTip
MsgBox, % obj.StdOut

StdOutHandling(this, key, value) {
   if (key = "_StdOut") {
      ToolTip % value  ; здесь можно совершать какие-то действия со значением, например, сохранять в другом ключе
      this.StdOut .= value 
      Return 0
   }
}

CmdRet(sCmd, obj)
{
   static STARTF_USESTDHANDLES := 0x100, CREATE_NO_WINDOW := 0x08000000
   
   DllCall("CreatePipe", PtrP, hPipeRead, PtrP, hPipeWrite, UInt, 0, UInt, 0)
   DllCall("SetHandleInformation", Ptr, hPipeWrite, UInt, 1, UInt, 1)
   
   VarSetCapacity(pi, A_PtrSize*2 + 4*2, 0)  ; _PROCESS_INFORMATION
   VarSetCapacity(si, sisize := A_PtrSize*4 + 4*8 + A_PtrSize*5, 0)
   NumPut(sisize, si)
   NumPut(STARTF_USESTDHANDLES, si, A_PtrSize*4 + 4*7)
   NumPut(hPipeWrite, si, A_PtrSize*4 + 4*8 + A_PtrSize*3)
   NumPut(hPipeWrite, si, A_PtrSize*4 + 4*8 + A_PtrSize*4)

   if !DllCall("CreateProcess", UInt, 0, Ptr, &sCmd, UInt, 0, UInt, 0, Int, True
                              , UInt, CREATE_NO_WINDOW, UInt, 0, UInt, 0, Ptr, &si, Ptr, &pi)  {
      DllCall("CloseHandle", Ptr, hPipeRead)
      DllCall("CloseHandle", Ptr, hPipeWrite)
      MsgBox, CreateProcess is failed
      Return
   }
   DllCall("CloseHandle", Ptr, hPipeWrite)
   VarSetCapacity(sTemp, 4096), nSize := 0
   while DllCall("ReadFile", Ptr, hPipeRead, Ptr, &sTemp, UInt, 4096, UIntP, nSize, UInt, 0)
      sOutput .= (obj._StdOut := StrGet(&sTemp, nSize, "CP866"))
   
   DllCall("CloseHandle", Ptr, NumGet(pi, 0))
   DllCall("CloseHandle", Ptr, NumGet(pi, A_PtrSize))
   DllCall("CloseHandle", Ptr, hPipeRead)
   Return sOutput
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

9

Re: AHK: Вывод StdOut в переменную скрипта

Здорово, буду изучать!

10

Re: AHK: Вывод StdOut в переменную скрипта

teadrinker
Нормально, это твой вариант этого, или есть отличия?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

11

Re: AHK: Вывод StdOut в переменную скрипта

Возможно и этот был взят за первооснову, а может и нет, уже не помню. Помню, что что-то подправлял и что-то выкидывал.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

12

Re: AHK: Вывод StdOut в переменную скрипта

Если вспомнишь отличия, то хорошо бы добавить в ту же тему.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

13

Re: AHK: Вывод StdOut в переменную скрипта

У меня убрана обработка ситуации, когда в запущенное консольное приложение можно отправлять несколько команд одну за другой, как в этом примере:

CmdLine = nslookup
Input =                ; Ввод нескольких команд.
(
mail.ru
yandex.ru
google.com
)

Ret := RunCon(CmdLine, Input, Output)
MsgBox, %Output%
MsgBox, Код выхода: %Ret%

Такой вариант редко нужен.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

14

Re: AHK: Вывод StdOut в переменную скрипта

teadrinker пишет:

Возможно и этот был взят за первооснову, а может и нет, уже не помню.

Судя по названию (CmdRet) первооснова была с англофорума. Там я видел функцию с таким названием.

15

Re: AHK: Вывод StdOut в переменную скрипта

sergeich пишет:

Вместо Sleep, 1000 сделал:

WinWait, ahk_class ConsoleWindowClass
WinHide, ahk_class ConsoleWindowClass

Вероятно, во избежание ложных срабатываний лучше как-то так

WinWait % "ahk_pid " exec.ProcessID
WinHide

16

Re: AHK: Вывод StdOut в переменную скрипта

YMP, да, и алгоритм другой.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

17 (изменено: sergeich, 2019-03-20 21:30:48)

Re: AHK: Вывод StdOut в переменную скрипта

Обнаружил, при выполнении:


....
exec := shell.Exec(CMD)
while !exec.StdOut.AtEndOfStream {
   str := exec.StdOut.ReadLine()
....
}

невозможно выполнять другие действия в скрипте, например, назначенная горячая клавиша на выход не работает до тех пор, пока не закроется запущенная программа, из которой идет выход StdOut. Даже контекстное меню при клике по иконке в трее не открывается. Возможно как то выйти из этого положения?

18

Re: AHK: Вывод StdOut в переменную скрипта

Используйте второй вариант, он вроде не морозит скрипт.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

19

Re: AHK: Вывод StdOut в переменную скрипта

В смысле, не можете завершить скрипт из меню иконки в трее?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

20 (изменено: sergeich, 2019-03-20 21:29:52)

Re: AHK: Вывод StdOut в переменную скрипта

Сделал горячую клавишу на выход:


#x::
Process, Close, mosquitto_pub.exe
Process, Close, mosquitto_sub.exe
ExitApp

При нажатии, ничего не происходит, после первого же вывода в StdOut, горячая клавиша срабатывает и приложение закрывается. Контекстное меню тоже не открывается.. В общем так же как в первом варианте, только окно консольного приложения запускается скрытым, что хорошо)

21

Re: AHK: Вывод StdOut в переменную скрипта

Решение будет зависеть от того, что конкретно нужно делать во время работы функции. В общем случае придётся разбивать на два потока тем или иным способом. Ищите по форуму про многопоточность.
Чтобы запостить код, есть тег [cоde].

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

22

Re: AHK: Вывод StdOut в переменную скрипта

Хорошо, попробую поискать про многопоточность, спасибо!

23

Re: AHK: Вывод StdOut в переменную скрипта

Попробуйте перед циклом вставить:

		Critical, off
		Thread, Priority,-100

24

Re: AHK: Вывод StdOut в переменную скрипта

Попробовал, но всё равно не выполняется горячая клавиша