Ждать свой процесс и разобрать настоящий код

Учебные задачи

Самостоятельный учебный опыт на новом собственном Windows-стенде: вычисление двух сумм в своей программе и проверка реального результата документированного API.

Где и как запускать

Полный модуль своей общей управляемой формы. Только толстый управляемый Windows x86_64 клиент; сервер без контекста возвращает только метку своей новой файловой CF.

Подготовка

  1. Только будущий опыт на полностью своей новой Windows x86_64 VM и в новом профиле, без рабочих данных. Вручную установите фактически полученную 1С 8.5.1.1343 и Python 3 для Windows. Здесь установка, запуск, создание процесса, папки или квитанции не выполнялись.

  2. Создайте свою новую пустую файловую ИБ. В конфигураторе задайте имя УчебныйЗапуск85, версию b1b4071a-7185-42b5-984c-b76f36565f56, русский встроенный язык, управляемое приложение и совместимость Не использовать. Собственная полная учебная роль/пользователь, без расширений и фоновых задач. Запускайте только толстый управляемый клиент, не сервер/веб/пакетный/мобильный режим.

  3. Только в своей VM вручную создайте новый каталог C:\OwnLaunch85_b1b4071a-7185-42b5-984c-b76f36565f56. Если он уже существует, не используйте его повторно: подготовьте новый целиком собственный стенд. Имя простое ASCII без пробелов. Это намеренно выбранный новый учебный путь, не объявление существования такого каталога на вашем компьютере.

  4. Откройте терминал в своём новом каталоге и вручную выполните python -m venv .venv. Проверьте реальное наличие .venv\Scripts\python.exe. Никакой pip-библиотеки не нужно. Сохраните весь нижний Python-блок в этом же каталоге как own_exit85.py в UTF-8; не подставляйте чужой скрипт, приложение по ассоциации или URL.

  5. В этом варианте используйте именно собственный новый каталог указанного имени на локальном C и его настоящий .venv\Scripts\python.exe. Путь неизменен в двух полных блоках, простой ASCII без пробелов и метасимволов оболочки. Произвольной командной строки и пути из поля формы нет. Если такой собственный путь подготовить нельзя, остановитесь; UNC, ссылки, URI, переменные среды и системные каталоги не подставляются.

  6. Общие → Общие формы → создайте управляемую ПультЗапуска85. Добавьте реквизиты Состояние85 — Строка длиной 0, СогласенЗапустить85 — Булево начально Ложь; выведите состояние только для просмотра и флажок. Для варианта КомандаСистемы добавьте СогласенПрочитать85 — Булево начально Ложь и его флажок.

  7. Вставьте весь основной блок ровно одного выбранного варианта в модуль этой формы, не внутрь существующей процедуры. Создайте команду ПроверитьЗапуск85, назначьте одноимённый клиентский обработчик и кнопку. Назначьте событие ПриОткрытии. Для квитанции также создайте кнопки ПроверитьКвитанцию85 и ОстановитьОжидание85 с одноимёнными действиями. Проверку квитанции вызывает только ваша вторая ручная кнопка, не таймер.

  8. Обновите только свою учебную конфигурацию F7, выполните её проверку для толстого управляемого клиента и сервера, откройте свою общую форму обычным интерактивным способом. Учебная метка и File= ограничивают контекст, но не доказывают собственность VM, каталога или интерпретатора; это отдельная ручная предпосылка.

  9. Работайте в одном спокойном собственном сеансе без других писателей папки, без изменения скрипта/интерпретатора во время опыта. Отметьте согласие на собственный запуск и нажмите кнопку один раз. В каждом новом варианте нужен новый экземпляр формы на новом собственном стенде; после СТОП повтор в том же экземпляре запрещён.

  10. Для КомандаСистемы после запуска вручную подтвердите чтение и нажмите свою вторую кнопку. Если квитанции ещё нет, показано только ожидание; по желанию явно остановите дальнейшее ожидание. Python.exe является консольной программой: КомандаСистемы может ожидать её; немедленный или неблокирующий возврат не обещан.

Перем КонтекстЗапуска85, ПопыткаЗапуска85;

&НаСервереБезКонтекста
Функция СобственныйМаркер85()
    Возврат Метаданные.Имя + "|" + Метаданные.Версия;
КонецФункции

&НаКлиенте
Функция ПроверитьСреду85()
#Если ТолстыйКлиентУправляемоеПриложение Тогда
    Среда85 = Новый СистемнаяИнформация;
    Если Среда85.ТипПлатформы <> ТипПлатформы.Windows_x86_64 Тогда
        ВызватьИсключение "СТОП: нужен свой толстый управляемый Windows x86_64 клиент 8.5.1.1343";
    КонецЕсли;
    Соединение85 = СтрокаСоединенияИнформационнойБазы();
    Если ТипЗнч(Соединение85) <> Тип("Строка") Тогда
        ВызватьИсключение "СТОП: строка соединения не получена";
    КонецЕсли;
    Если НРег(Лев(Соединение85, 5)) <> "file=" Тогда
        ВызватьИсключение "СТОП: нужна новая собственная файловая база";
    КонецЕсли;
    Маркер85 = СобственныйМаркер85();
    Возврат Маркер85;
#Иначе
    ВызватьИсключение "СТОП: другой клиентский контекст";
#КонецЕсли
КонецФункции

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    КонтекстЗапуска85 = Неопределено;
    ПопыткаЗапуска85 = Ложь;
    СогласенЗапустить85 = Ложь;
    Состояние85 = "Готов: собственный стенд, один запуск";
    Попытка
        ПроверитьСреду85();
    Исключение
        Отказ = Истина;
        ПопыткаЗапуска85 = Истина;
        Состояние85 = "СТОП: собственная среда не подтверждена";
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьФайл85(Имя85, Максимум85)
    Файл85 = Новый Файл(Имя85);
    Если Не Файл85.Существует() Тогда
        ВызватьИсключение "СТОП: своего файла нет";
    КонецЕсли;
    Если Не Файл85.ЭтоФайл() Тогда
        ВызватьИсключение "СТОП: нужен обычный собственный файл";
    КонецЕсли;
    Размер85 = Файл85.Размер();
    Если ТипЗнч(Размер85) <> Тип("Число") Тогда
        ВызватьИсключение "СТОП: размер неизвестен";
    КонецЕсли;
    Если Размер85 <= 0 Или Размер85 > Максимум85 Или НРег(Файл85.ПолноеИмя) <> НРег(Имя85) Тогда
        ВызватьИсключение "СТОП: другой путь или недопустимый размер";
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Функция ПодготовитьЗапуск85(Команда, Режим85)
    Если ТипЗнч(Команда) <> Тип("КомандаФормы") Или ПопыткаЗапуска85 <> Ложь Тогда
        ВызватьИсключение "СТОП: повтор или другой вызов";
    КонецЕсли;
    Если СогласенЗапустить85 <> Истина Тогда
        ВызватьИсключение "СТОП: сначала подтвердите собственный запуск";
    КонецЕсли;
    ПопыткаЗапуска85 = Истина;
    СогласенЗапустить85 = Ложь;
    Состояние85 = "Неизвестно: запуск ещё не проверен";
    Маркер85 = ПроверитьСреду85();
    Если Режим85 <> "exit" И Режим85 <> "receipt" Тогда
        ВызватьИсключение "СТОП: другой учебный режим";
    КонецЕсли;
    Каталог85 = "C:\OwnLaunch85_b1b4071a-7185-42b5-984c-b76f36565f56";
    Интерпретатор85 = Каталог85 + "\.venv\Scripts\python.exe";
    Скрипт85 = Каталог85 + "\own_exit85.py";
    КаталогФайл85 = Новый Файл(Каталог85);
    Если Не КаталогФайл85.Существует() Тогда
        ВызватьИсключение "СТОП: подготовьте свой новый каталог";
    КонецЕсли;
    Если Не КаталогФайл85.ЭтоКаталог() Тогда
        ВызватьИсключение "СТОП: свой каталог не подтверждён";
    КонецЕсли;
    ПроверитьФайл85(Интерпретатор85, 134217728);
    ПроверитьФайл85(Скрипт85, 65536);
    Номер85 = НРег(Строка(Новый УникальныйИдентификатор));
    Квитанция85 = "";
    СтрокаКоманды85 = Интерпретатор85 + " " + Скрипт85 + " " + Режим85 + " " + Номер85;
    Если Режим85 = "receipt" Тогда
        Квитанция85 = Каталог85 + "\receipt85_" + Номер85 + ".json";
        КвитанцияФайл85 = Новый Файл(Квитанция85);
        Если КвитанцияФайл85.Существует() Тогда
            ВызватьИсключение "СТОП: квитанция уже существует";
        КонецЕсли;
        СтрокаКоманды85 = СтрокаКоманды85 + " " + Квитанция85;
    КонецЕсли;
    К = Новый Структура("Номер,Маркер,Фаза,Режим,Каталог,СтрокаКоманды,Квитанция,СогласиеИзрасходовано,Завершено",
        Номер85, Маркер85, "Ожидание", Режим85, Каталог85, СтрокаКоманды85, Квитанция85, Истина, Ложь);
    КонтекстЗапуска85 = К;
    Возврат К;
КонецФункции

&НаКлиенте
Процедура ПроверитьПродолжение85(К, Режим85)
    Если ТипЗнч(К) <> Тип("Структура") Тогда
        ВызватьИсключение "СТОП: нет собственного состояния";
    КонецЕсли;
    Если К <> КонтекстЗапуска85 Или К.Фаза <> "Ожидание" Или К.Завершено <> Ложь
        Или К.Режим <> Режим85 Или К.СогласиеИзрасходовано <> Истина
        Или ПопыткаЗапуска85 <> Истина Или СогласенЗапустить85 <> Ложь Тогда
        ВызватьИсключение "СТОП: другая или завершённая попытка";
    КонецЕсли;
    Если НРег(Строка(Новый УникальныйИдентификатор(К.Номер))) <> К.Номер Или ПроверитьСреду85() <> К.Маркер Тогда
        ВызватьИсключение "СТОП: номер или версия изменились";
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПринятьКод85(ФактическийКод85, К)
    ПроверитьПродолжение85(К, "exit");
    Если ТипЗнч(ФактическийКод85) <> Тип("Число") Тогда
        ВызватьИсключение "СТОП: настоящий код выхода не получен";
    КонецЕсли;
    Если ФактическийКод85 <> 125 Тогда
        ВызватьИсключение "СТОП: фактический код не равен вычислению 125";
    КонецЕсли;
    К.Завершено = Истина;
    К.Фаза = "Готово";
    Состояние85 = "Фактический код выхода: " + Строка(ФактическийКод85) + "; собственное вычисление 50 + 75";
КонецПроцедуры

&НаКлиенте
Асинх Процедура ПроверитьЗапуск85(Команда)
    Попытка
        К = ПодготовитьЗапуск85(Команда, "exit");
        ФактическийКод85 = Ждать ЗапуститьПриложениеАсинх(К.СтрокаКоманды, К.Каталог, Истина);
        ПринятьКод85(ФактическийКод85, К);
    Исключение
        ПопыткаЗапуска85 = Истина;
        Если КонтекстЗапуска85 <> Неопределено Тогда
            КонтекстЗапуска85.Фаза = "СТОП";
        КонецЕсли;
        Состояние85 = "СТОП: код не проверен; повтор запрещён";
    КонецПопытки;
КонецПроцедуры
Python: own_exit85.py

Отдельный собственный файл в новой Windows VM, не модуль 1С.

Полный source-only стандартный Python helper. Здесь только AST-разбор текста; импорт, исполнение, запуск процесса и запись квитанции не выполнялись.

import json
from pathlib import Path
import sys
from uuid import UUID

OWN_ROOT = Path(r"C:\OwnLaunch85_b1b4071a-7185-42b5-984c-b76f36565f56")


def main():
    try:
        if sys.platform != "win32" or Path(__file__).resolve().parent != OWN_ROOT or Path.cwd() != OWN_ROOT:
            return 2
        if len(sys.argv) not in (3, 4):
            return 2
        mode, raw_nonce = sys.argv[1:3]
        nonce = UUID(raw_nonce)
        if nonce.int == 0 or str(nonce) != raw_nonce:
            return 2
        if mode not in ("exit", "receipt") or len(sys.argv) != (3 if mode == "exit" else 4):
            return 2
        rows = [{"Quantity": 2, "Price": 25}, {"Quantity": 3, "Price": 25}]
        for row in rows:
            if type(row["Quantity"]) is not int or type(row["Price"]) is not int:
                return 2
            row["Amount"] = row["Quantity"] * row["Price"]
        total = sum(row["Amount"] for row in rows)
        if type(total) is not int or total < 1 or total > 255:
            return 2
        if mode == "receipt":
            receipt = OWN_ROOT / f"receipt85_{nonce}.json"
            if Path(sys.argv[3]) != receipt:
                return 2
            payload = {"Version": "OwnLaunch85/1", "Nonce": str(nonce), "Mode": mode,
                       "Rows": rows, "Total": total, "PlannedExitCode": total, "Complete": True}
            with receipt.open("x", encoding="utf-8", newline="\n") as stream:
                json.dump(payload, stream, ensure_ascii=True, separators=(",", ":"))
        return total
    except (OSError, ValueError, TypeError):
        return 2


if __name__ == "__main__":
    sys.exit(main())

Разбор по шагам

  1. Форма проверяет собственный толстый Windows x86_64 клиент и файловую ИБ. На сервер не передаются пути, команды, результаты или квитанция.

  2. Перед запуском флажок согласия очищается, попытка навсегда отмечается, состояние становится Неизвестно. Существование файла проверяется раньше размера. Интерпретатор и скрипт берутся только из собственной неизменной подготовки; код ничего не устанавливает.

  3. Настоящий УникальныйИдентификатор создаёт новый номер вызова. Одна фиксированная команда содержит только абсолютные простые пути, известное слово режима и настоящий UUID. Нет пользовательской команды, перенаправления, %переменных%, cmd.exe /c или придуманного универсального экранирования.

  4. Своя программа проверяет режим/число аргументов/UUID/место запуска, создаёт две строки и вычисляет суммы 2 × 25 = 50, 3 × 25 = 75 и итог 125. Первые три варианта получают код, переданный этой программой ОС; код не назначается формой.

  5. В продолжении сравниваются собственные состояние, номер и версия, согласие и ожидающая фаза. Неопределено, ошибка или другое число — неуспех. СТОП и Готово не сбрасываются; повторного запуска и автоматического отката нет.

  6. Ждать ЗапуститьПриложениеАсинх получает три аргумента и возвращает настоящий код. Проверка продолжения выполняется уже после Ждать, не по старому значению.

Как проверить результат

  1. Без флажка первый запуск не начинается; форма не объявляет проверено. В новом экземпляре при правильной подготовке первые три варианта показывают настоящий код 125.

  2. Отсутствующий собственный интерпретатор/скрипт, другая CF/версия/клиент, иной настоящий код или Неопределено дают СТОП. Изменение учебного helper для отрицательной пробы допустимо только на новом собственном стенде: фактическое другое вычисление не принимается за 125.

  3. Повтор кнопки в том же экземпляре запрещён. После ошибки ничего не перезапускается, квитанции не удаляются, чужие процессы не завершаются. Настоящие обработчики оповещения руками не вызываются.

Ожидаемый результат

При будущем ручном получении результата проверен фактический код выхода 125 своего вычисления. Запуск здесь не проверялся.

На что обратить внимание

  1. ЗапуститьПриложение и НачатьЗапускПриложения — процедуры. Только у синхронного варианта четвёртый параметр получает выходной код. Обещание и callback тоже могут дать Неопределено. ДождатьсяЗавершения явно Истина; сервер/пакетный запуск запрещён примечанием native даже при широком перечне доступности.

  2. КомандаСистемы использует интерпретатор ОС, а три остальных API запускают приложение непосредственно. У КомандаСистемы нет выходного кода и параметра ожидания; время возврата зависит от типа запущенного приложения. Квитанция не доказывает нормальное завершение процесса, фактический код выхода, долговечное сохранение или отсутствие последующей ошибки.

  3. Простые пути исключают необходимость переносить недокументированное экранирование. Проверки пути/размера и новый UUID не гарантируют защиту от гонок, ссылок, подмены бинарника или доступов ОС. Допустим только целиком собственный новый стенд.

  4. РезультатЗапускаПриложенияМобильногоУстройства создаётся другим мобильным объектом ЗапускПриложенияМобильногоУстройства.ЗапуститьАсинх. Код выхода Windows не является этим объектом, PID или результатом Android-приложения.

Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.