Имя: Пароль:
1C
1С v8
Взаимодействие 1С и консольного приложения
0 same_prog_1c
 
01.03.20
18:22
Всем привет форумчане!
Есть простое консольное приложение, которое например при запуске выводит сообщение "Введите число", пользователь вводит число, нажимает Enter, программа выводит "Вы ввели число такое-то". Задача стоит так, что нужно написать код в 1С, который программно будет запускать приложение через командную строку, считывать вывод этого приложения, отправлять что-то на ввод, и опять считывать и т.д., то есть нужно чтобы 1С взаимодействовала с этим приложением. Мучаюсь уже несколько дней, никак не могу решить данную задачу.

Нашел инфу по Wscript.Shell, вроде кое что получилось, но есть проблемы...
Если я пишу код такой:

    WshShell = Новый COMОбъект("Wscript.Shell");
    WshExec = WshShell.Exec("cmd.exe /C ""D:\ngrok.exe""");
    
    OutStream = WshExec.StdOut;
    Стр = OutStream.ReadAll();

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

WshExec = WshShell.Exec("cmd.exe /C ""D:\ngrok.exe""");

меняю на

WshExec = WshShell.Exec("cmd.exe /C ""D:\ngrok.exe http 777""");

то уже в переменной стр будет пусто. Я уверен что я где-то рядом... Но до конца не получается. Может я что-то в строке не правильно прописываю? А вот на ввод данных вообще не получилось ничего отправить, для этого есть объект StdIn. Кто нибудь сталкивался с подобным??? Очень прошу помочь разобраться в вопросе.
1 ДенисЧ
 
01.03.20
18:26
2 same_prog_1c
 
01.03.20
18:30
(1) очень умно конечно, кинуть спамную ссылку написанную в пьяном бреду. Если по делу нечего ответить зачем вообще что-то писать?
3 Лодырь
 
01.03.20
18:30
Перенаправление ввода/вывода тебе не поможет? а уже например с файл ввода/вывода мучать в 1с
4 same_prog_1c
 
01.03.20
18:32
(3) нет, вся соль в том, что приложение работает только из под командной строки ака cmd. Имне его обязательно нужно запустить, считать инфу, отправить команду, и опять считать инфу. Да, многие скажут зачем такие заморочки? Объяснять очень долго.
5 Fram
 
01.03.20
18:37
(4) и параметры с командой строки это приложение читать не умеет?
6 Лодырь
 
01.03.20
18:38
(4) Так я тебе об этом и говорю. Запиши данные в файл. запусти приложение с перенаправлением ввода. считай данные из файла в приложении, выведи вывод в файл, считай данные из файла в 1с
https://celitel.info/klad/bathelp/redirect.htm
7 same_prog_1c
 
01.03.20
18:39
(5) нет, почему же? Как раз на примере выше я и пишу, не понятно почему без указания параметров в переменной есть информация, а вот когда параметры указывает в выводе пусто. Если просто в cmd ввести команду D:\ngrok.exe http 777 то приложение запустится и выведет информацию на экран
8 ДенисЧ
 
01.03.20
18:41
Просто в консоли D:\ngrok.exe http 777 > 111 что-нибудь выводит в файл?
9 same_prog_1c
 
01.03.20
18:41
(6) по идее и без файлов должно работать через StdIn и StdOut. И еще вопрос в том что может получится так, что за один сеанс нужно будет несколько раз что-то ввести и считать
10 same_prog_1c
 
01.03.20
18:45
(8) неа, только пустой файл создает
11 ДенисЧ
 
01.03.20
18:47
(10) Значит, программа выдаёт ответ не в stdout. Так что твоим методом ты её не поймаешь.
Ради експеримента можно попробовать stderr поймать, но тут вряд ли. Скорее она пишет напрямую в консоль, а не в стандартный поток.
12 same_prog_1c
 
01.03.20
18:48
(11) А как мне из консоли это перехватить?
13 same_prog_1c
 
01.03.20
18:48
Вот тут мануал есть по этой теме http://calendar.vpogiba.info/wg/wsh/WshShell.htm#Exec
14 same_prog_1c
 
01.03.20
18:51
Вот этот код работает на ура например

WshShell = Новый COMОбъект("WScript.Shell");
WshExec = WshShell.Exec("notepad");
Если AppActivate(WshExec.ProcessID) Тогда
   WshShell.SendKeys ("0123456789");
КонецЕсли;

Я думал может запускать также батник например и отправлять команды? Но тогда не могу считать что она выводит. И кстати если батник запускаю через 1с, черный экран, а если из вмнды все работает
15 Fram
 
01.03.20
18:53
Какой то подпроцесс может используется
16 acht
 
01.03.20
18:56
(14) Если почитать в гугле и попробовать понять, чем ngrok.exe занимается, то ожиданий от него консольного вывода поубавится. Надеюсь.

В общем ты в (4) правильно сказал - "Объяснять очень долго".
Страдай.
17 ДенисЧ
 
01.03.20
18:58
Погуглил... Если приложение пишет напрямую на консоль, а не в стандартный поток - то ловить его вывод - овчинка выделки...
18 ДенисЧ
 
01.03.20
18:58
"Особо стоит упомянуть Web Interface http://127.0.0.1:4040 утилиты ngrok. Очень подробный лог. Возможность повторить запрос пользователя без участия пользователя, кнопка Replay. Ну и хорошо отображен ответ, заголовок. Очень удобно смотреть ответ от RestApi вашего сайта, красиво показывает JSON. Как по мне очень удобно."

(с)
19 same_prog_1c
 
01.03.20
19:00
(16) слушай мэн, ты смотришь не в корень вопроса!!! Возьми любую другую утилиту! Не обязательно ngrok, результат тот же! Я его просто для пример написал. И причем тут чем он занимается? Порт он пробрасывает и в консоль выдает информацию, так вот ее считать не получилось. Еще раз повторюсь, можно взять любое другое приложение.
20 same_prog_1c
 
01.03.20
19:02
Должна же быть возможность у windows api запустить приложение и считывать и отправлять данные в процесс, это же простое взаимодействие, через винду все работает, значит и через код должно быть также
21 Garykom
 
гуру
01.03.20
19:05
22 Garykom
 
гуру
01.03.20
19:05
(20) Усе есть только ты ограничен 1С и com/ole
23 acht
 
01.03.20
19:11
(21) слушай мэн... Возьми любую другую утилиту! Не обязательно ngrok

(:
24 Garykom
 
гуру
01.03.20
19:12
(23) ?
25 Лодырь
 
01.03.20
19:13
(24) он говорит что хочет решить вопрос в общем случае
26 Garykom
 
гуру
01.03.20
19:17
(25) Так см (22) в общем случае.

Можно в самом самом крайнем случае с консолью просто как с окном Windows работать по дескриптору.
27 acht
 
01.03.20
19:26
(20) > через винду все работает, значит и через код должно быть

Вот и сделай это все сначала из батника. Который "через винду" работает.
28 acht
 
01.03.20
19:29
(26) А еще можно повторить весь функционал требуемой утилиты самостоятельно, например на Go, дадада.
Ну хорошо, на внешней компоненте. Нам же в конце концов надо от 1С хоть что-то оставить...
29 Garykom
 
гуру
01.03.20
19:44
(28) Нафига повторять когда можно:
Раз https://i.paste.pics/e20d84ffacaf99d5227a9a04f47ae75c.png
И два https://i.paste.pics/f4364e8b5cf9f7248a7d637894b63e1b.png

Как видим все перехватывается и возвращается в коде от консольной.
Тут

fmt.Println(string(convert(41, out)))

Это и есть вывод, на вход массив байт что выдала консольная, далее в нужную кодовую страницу в строку перевожу и вывожу уже в свой консольный.
В другом проекте у меня это используется для анализа вывода что там утилита хочет.
30 Garykom
 
гуру
01.03.20
19:45
(0) Дарю:


package main

import (
    "bytes"
    "fmt"
    "io/ioutil"
    "os"
    "os/exec"
    "path/filepath"

    //"syscall"
    "golang.org/x/text/encoding/charmap"
    "golang.org/x/text/transform"
)

func convert(i int, s []byte) []byte {
    var reader *transform.Reader
    switch i {
    case 1:
        reader = transform.NewReader(bytes.NewReader(s), charmap.ISO8859_1.NewDecoder())
    case 2:
        reader = transform.NewReader(bytes.NewReader(s), charmap.ISO8859_2.NewDecoder())
    case 3:
        reader = transform.NewReader(bytes.NewReader(s), charmap.ISO8859_3.NewDecoder())
    case 4:
        reader = transform.NewReader(bytes.NewReader(s), charmap.ISO8859_4.NewDecoder())
    case 5:
        reader = transform.NewReader(bytes.NewReader(s), charmap.ISO8859_5.NewDecoder())
    case 6:
        reader = transform.NewReader(bytes.NewReader(s), charmap.ISO8859_6.NewDecoder())
    case 7:
        reader = transform.NewReader(bytes.NewReader(s), charmap.ISO8859_7.NewDecoder())
    case 8:
        reader = transform.NewReader(bytes.NewReader(s), charmap.ISO8859_8.NewDecoder())
    case 9:
        reader = transform.NewReader(bytes.NewReader(s), charmap.ISO8859_9.NewDecoder())
    case 10:
        reader = transform.NewReader(bytes.NewReader(s), charmap.ISO8859_10.NewDecoder())
    case 11:
        reader = transform.NewReader(bytes.NewReader(s), charmap.ISO8859_13.NewDecoder())
    case 12:
        reader = transform.NewReader(bytes.NewReader(s), charmap.ISO8859_14.NewDecoder())
    case 13:
        reader = transform.NewReader(bytes.NewReader(s), charmap.ISO8859_15.NewDecoder())
    case 14:
        reader = transform.NewReader(bytes.NewReader(s), charmap.ISO8859_16.NewDecoder())
    case 15:
        reader = transform.NewReader(bytes.NewReader(s), charmap.KOI8R.NewDecoder())
    case 16:
        reader = transform.NewReader(bytes.NewReader(s), charmap.KOI8U.NewDecoder())
    case 17:
        reader = transform.NewReader(bytes.NewReader(s), charmap.Macintosh.NewDecoder())
    case 18:
        reader = transform.NewReader(bytes.NewReader(s), charmap.MacintoshCyrillic.NewDecoder())
    case 19:
        reader = transform.NewReader(bytes.NewReader(s), charmap.Windows874.NewDecoder())
    case 20:
        reader = transform.NewReader(bytes.NewReader(s), charmap.Windows1250.NewDecoder())
    case 21:
        reader = transform.NewReader(bytes.NewReader(s), charmap.Windows1251.NewDecoder())
    case 22:
        reader = transform.NewReader(bytes.NewReader(s), charmap.Windows1252.NewDecoder())
    case 23:
        reader = transform.NewReader(bytes.NewReader(s), charmap.Windows1253.NewDecoder())
    case 24:
        reader = transform.NewReader(bytes.NewReader(s), charmap.Windows1254.NewDecoder())
    case 25:
        reader = transform.NewReader(bytes.NewReader(s), charmap.Windows1255.NewDecoder())
    case 26:
        reader = transform.NewReader(bytes.NewReader(s), charmap.Windows1256.NewDecoder())
    case 27:
        reader = transform.NewReader(bytes.NewReader(s), charmap.Windows1257.NewDecoder())
    case 28:
        reader = transform.NewReader(bytes.NewReader(s), charmap.Windows1258.NewDecoder())
    case 29:
        reader = transform.NewReader(bytes.NewReader(s), charmap.XUserDefined.NewDecoder())
    case 30:
        reader = transform.NewReader(bytes.NewReader(s), charmap.CodePage037.NewDecoder())
    case 31:
        reader = transform.NewReader(bytes.NewReader(s), charmap.CodePage437.NewDecoder())
    case 32:
        reader = transform.NewReader(bytes.NewReader(s), charmap.CodePage850.NewDecoder())
    case 33:
        reader = transform.NewReader(bytes.NewReader(s), charmap.CodePage852.NewDecoder())
    case 34:
        reader = transform.NewReader(bytes.NewReader(s), charmap.CodePage855.NewDecoder())
    case 35:
        reader = transform.NewReader(bytes.NewReader(s), charmap.CodePage858.NewDecoder())
    case 36:
        reader = transform.NewReader(bytes.NewReader(s), charmap.CodePage860.NewDecoder())
    case 37:
        reader = transform.NewReader(bytes.NewReader(s), charmap.CodePage862.NewDecoder())
    case 38:
        reader = transform.NewReader(bytes.NewReader(s), charmap.CodePage863.NewDecoder())
    case 39:
        reader = transform.NewReader(bytes.NewReader(s), charmap.CodePage865.NewDecoder())
    case 40:
        reader = transform.NewReader(bytes.NewReader(s), charmap.CodePage865.NewDecoder())
    case 41:
        reader = transform.NewReader(bytes.NewReader(s), charmap.CodePage866.NewDecoder())
    case 42:
        reader = transform.NewReader(bytes.NewReader(s), charmap.CodePage1047.NewDecoder())
    case 43:
        reader = transform.NewReader(bytes.NewReader(s), charmap.CodePage1140.NewDecoder())
    }

    d, _ := ioutil.ReadAll(reader)

    return d
}

func getExecutablePath() string {
    ex, err := os.Executable()
    if err != nil {
        fmt.Println(err)
    }
    exPath := filepath.Dir(ex)
    return exPath
}

func test() {
    apps := getExecutablePath() + "\\" + "ngrok.exe"

    var args []string
    args = append(args, "")

    cmd := exec.Command(apps, args...)
    //cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
    out, err := cmd.Output()
    if err != nil {
        fmt.Println("Error: " + err.Error())
    }

    fmt.Println(string(convert(41, out)))
}

func main() {
    test()
}


Если конечно сможешь заюзать
31 same_prog_1c
 
01.03.20
19:50
(29) я же писал выше, что через винду работает. Еще раз говорю, батник написал, если запустить через винду работает, запускаем через 1С уже ничего нет. Зачем извращаться и писать код через другой язык? В 1С же есть сом , можно же заюзать windows API. Что в апи виня такого не предусмотрено что ли?
32 Garykom
 
гуру
01.03.20
19:52
(31) Потому что ты неправильно через 1С запускаешь ))
И с windows api 1С напрямую не умеет только через прокладки в виде ВК или COM

Ну нет у тебя готового COMОбъекта для задачи, чтобы возвращал что консольная выдает.
33 Garykom
 
гуру
01.03.20
20:00
(32)+ На golang можно написать утилиту (обычный exe) которую можно запустить с параметрами "ИмяУтилитыКоторуюЗапустить", "ФайлЧтоЕйПередатьНаВход" и "ФайлКудаСохранитьВыводЗапущеннойУтилиты" и все.

Это для 1С решает проблему твою из 1С банально юзать чтение/запись текстовых файлов и ЗапуститьПриложение или КомандаСистемы.
Даже перекодировку утилита на себя возьмет не придется в 1С этим заморачиваться если кириллица.
34 Garykom
 
гуру
01.03.20
20:02
(33)+ А что еще круче то Golang позволяет легко создать/поднять http-сервис.
И 1С сможет через HTTPСоединение запускать и получать вывод проги даже по сети или через инет ))
35 same_prog_1c
 
01.03.20
20:02
(32) Блин, я раньше учил С++, есть всего 3 дескриптора файла, StdIn, StdOut, StdErr. Если мы пишем прогу хэлоу ворд типа, то в ней мы используем эти дескрипторы, но вывод она делает в консоль, т.к. она из консоли и запущена, без консоли она работать не умеет, более того, я же писал что мне удалось получить информацию из StdOut, но только при запуске файла без параметров, т.е. код ниже работает!

    WshShell = Новый COMОбъект("Wscript.Shell");
    WshExec = WshShell.Exec("cmd.exe /C ""D:\ngrok.exe""");
    
    OutStream = WshExec.StdOut;
    Стр = OutStream.ReadAll();

В стр будет тоже что и у тебя в консоли выводилось. Не бывает других дескрипторов, и не нужен специальный объект com для считывания консоли, с чего вы так решили?
36 same_prog_1c
 
01.03.20
20:03
(33) не пойдет, мне нужно каждый раз разное количество раз читать консоль и разное кол-во раз отправлять команды
37 acht
 
01.03.20
20:04
Garykom> На golang можно написать утилиту...

https://cs5.pikabu.ru/images/big_size_comm/2015-12_6/1451495908113110417.jpg
(:
38 Garykom
 
гуру
01.03.20
20:04
(35) Ты прикалываешь?
У тебя Новый COMОбъект("Wscript.Shell"); в коде и есть специальный объект для "считывания с консоли".

Предлагаю выкинуть этот Новый COMОбъект и использовать просто ЗапуститьПриложение(ПромежуточнаяEXE).
39 Garykom
 
гуру
01.03.20
20:05
(37) При переходе на линукс или андроид Новый COMОбъект в 1С не работают.
Так что все равно придется заюзать некую иную магию.
40 Garykom
 
гуру
01.03.20
20:07
(36) Да хоть сколько угодно раз ЗапуститьПриложение()
Если же надо не закрывая приложение ему на вход новое подавать и читать вывод то смотри (34)
41 Garykom
 
гуру
01.03.20
20:09
(40)+ Например некоторые консольные да этого требуют там не запустил-отработало а спрашивает ответа и ждет его в консоли.
Тот же mysql и прочие.

Тут ты с 1С ну никак и один хрен придется что то ваять внешнее.
42 same_prog_1c
 
01.03.20
20:17
Ок, давайте попробуем по другому... Абстрагируйтесь от других приложений, осей и прочего... Есть программа, работает только через CMD, вида ххххххх\myprog.exe param1 которая выводит на экран то что вы ввели на клавиатуре только что... Задача заключается в том чтобы запустить эту программу или "подключиться" к уже открытому окну, просмотреть что она уже вывела, отправить команду на ввод, еще раз счиать результат, и таких операций может быть любое количество, именно по этому мне нужно контролировать выполнение проги и понимать что она выводит и как отрабатывает мои команды.
43 Garykom
 
гуру
01.03.20
20:19
(42) Т.е. программа не закрываясь выводит в консоль и ждет нового ввода?
44 same_prog_1c
 
01.03.20
21:35
(43) да
45 Garykom
 
гуру
01.03.20
22:19
(44) Тогда тебе нужны пайпы (pipes)

Я бы задачу решал так https://golang.org/pkg/os/exec/#Cmd.StdoutPipe

Для знающих дельфи есть вариант http://www.delphisources.ru/pages/faq/base/stdin_stdout.html
Можно наваять ВК для 1С.

Имхо слишком замахнулись, задачка не сложная но для типового 1Сника не решаемая.
46 same_prog_1c
 
01.03.20
22:38
Вот https://yadi.sk/d/n4pzGDt7HaODhg на питоне накидал простую консольную прогу, это уже готовый exe, вот нужно чтобы можно было из 1С добиться того же самого (управления) как если бы вы просто его из под винды запустили и работали. Я думаю так проще чем с ngrok пример приводить
47 same_prog_1c
 
01.03.20
22:42
(45) так вот в том то и проблема, что в задаче нужна вся структура БД, но приложение которое нужно использовать сществует только и только в консоле, переписать/найти другую версию и т.д. не подходит. Поэтому да, это грабли, я понимаю... Я сам не первый год кодирую, поэтому и обратился сюда за помощью, т.к. не могу пока решить задачу
48 Garykom
 
гуру
01.03.20
22:58
(46) (47) Если ты знаешь питон вот и делай это на питоне а для 1С сделай из питона интерфейс как хочешь/сможешь.
По тупому через текстовые файлы например или через http (но тут минус питона что он требует вебсервер а сам не умеет как нода или голанг).
49 same_prog_1c
 
01.03.20
23:01
(48) уже разобрался, скоро напишу решение сюда, все работает как я писал вначале статьи, просто особенности есть...
50 Zerga
 
01.03.20
23:10
И это блин форум по 1С?
https://oscript.io/syntax/page/Процесс
51 acht
 
01.03.20
23:14
(50) А ты думаешь - это канал об аниме^woscript?
52 same_prog_1c
 
01.03.20
23:16
Собственно код ниже... В чем была особенность?
1. Нужно было запускать через cmd с ключом
2. Если вы читаете текст через StdOut то при попытке прочесть все, или большее количество знаков чем на экране, или прочитаете строку после которой программа ожидает ввод текста, то управление в 1С не передастся пока    не закроете программу и ничего ввести не сможете...

В общем через жопу как-то, но исхитриться можно, я своей цели добился... Может кому поможет, всем спасибо за помощь!

        WshShell = Новый COMОбъект("Wscript.Shell");
    
    WshExec = WshShell.Exec("cmd.exe /C ""D:\55.exe""");
    
    InStream = WshExec.StdIn;
    InStream.WriteLine("same text zzzz");
    
    OutStream = WshExec.StdOut;
    Стр = OutStream.ReadAll(); //вариации ReadLine() или Read(КолВо)
53 same_prog_1c
 
01.03.20
23:18
(51) Вообще-то это расширение, где на языке 1С пишешь скрипты, очень интересная хрень, только узнал о такой
54 acht
 
01.03.20
23:21
(53) Ученый на с++ открыл для себя факт, что ввода-вывод буферизуется! А в (31) утверждал, что батник написал!

Дык возрадуемся!
55 palsergeich
 
01.03.20
23:22
(53) Это не расширение, а самостоятельный продукт с похожим синтаксисом
56 Garykom
 
гуру
01.03.20
23:23
(52) Там должен быть для OutStream признак что есть что читать новое или читай Read(1) пока не EOF
57 Garykom
 
гуру
01.03.20
23:25
(56)+ ага OutStream.AtEndOfStream
58 Garykom
 
гуру
01.03.20
23:25
59 same_prog_1c
 
02.03.20
00:14
(54) это и через батник работает, снчала писал батником, потом путь к exe написал, результат один и тот же! Хватит язвить, как школьник, противно, вот серьезно. Если детство еще в одном месте играет, то ты не по адресу зашел. Если ты думаешь что ты мега юморной и остальным тут весело, то я думаю ты заблуждаешься. Прочитал все твои комментарии в ветке, ты явно ПРИДУРОК КОТОРЫЙ ТОЛЬКО ФЛУДИТ, ИДИ НА УЙХ! И не мешай нормальным людям общаться. Не хотел грубить, но твои комменты все таки заставили это сделать.
60 acht
 
02.03.20
12:11
(59) Копытца-то не сбил, ножками так топать?
Пользователь не знает, чего он хочет, пока не увидит то, что он получил. Эдвард Йодан