Глобальный контекст.НачатьПолучениеКаталогаДокументов

Методы · BeginGettingDocumentsDir

Начинает получение стандартного каталога документов.

Синтаксис

НачатьПолучениеКаталогаДокументов(<ОписаниеОповещения>)
Полное описание, параметры и ограничения

Глобальный контекст.НачатьПолучениеКаталогаДокументов (Global context.BeginGettingDocumentsDir)

Глобальный контекст (Global context)

НачатьПолучениеКаталогаДокументов (BeginGettingDocumentsDir)

Доступен, начиная с версии 8.3.5.

Синтаксис:
НачатьПолучениеКаталогаДокументов(<ОписаниеОповещения>)
Параметры:

<ОписаниеОповещения> (обязательный)
Тип: ОписаниеОповещения.
Содержит описание процедуры, которая будет вызвана после завершения со следующими параметрами:
<ИмяКаталогаДокументов> – имя временного файла, тип Строка.

<ДополнительныеПараметры> – значение, которое было указано при создании объекта ОписаниеОповещения.

Описание:

Начинает получение стандартного каталога документов.

Доступность:

Тонкий клиент, веб-клиент, мобильный клиент, толстый клиент, мобильное приложение (клиент).

Примечание:
Для работы метода на веб-клиенте необходимо предварительно подключить расширение работы с файлами.
См. также:
Глобальный контекст, метод КаталогДокументов
Глобальный контекст, метод КаталогДокументовАсинх

Использование в версии:

Доступен, начиная с версии 8.3.5.

Описание изменено в версии 8.3.18.

Методическая информация

Практические примеры

Своя копия с суммой125: обратные вызовы и обработка ошибки

На своем новом Windows стенде создайте один новый учебный каталог и скопируйте в него только свой вымышленный JSON-документ. Научитесь получать реальные пути, отдельно запрашивать разрешение на каждую операцию и проверять файл целиком, а не только сумму125.

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

Новая собственная Windows VM, пустой профиль ОС и пустая конфигурация. ТолстыйКлиентУправляемоеПриложение8.5.1.1343; проверка меток своей конфигурации на Сервер8.5.1.1343 возвращает только Булево. Без веб/мобильного/сетевого варианта и без реальных операций сейчас.

Подготовка

  1. Выполняйте будущий ручной опыт ТОЛЬКО на НОВОЙ полностью собственной Windows VM, то есть виртуальной машине, новом пустом профиле ОС и пустой собственной CF, то есть конфигурации. Не используйте рабочую базу, личные документы или общую папку. Здесь 1С, виртуальная машина и файловые операции не запускаются. Отдельный стенд нужен для ограничения риска, а не как обещание технической изоляции.

  2. В Конфигураторе создайте пустую конфигурацию УчебноеКопирование125. В свойствах задайте Версия=4581fd24-c0a1-4484-9ad3-59c7ed73b507, Режим совместимости=Не использовать. Откройте Общие → Общие формы и создайте ровно одну управляемую форму Копирование125; поместите ее в рабочую область начальной страницы. Вставьте полный код ОДНОЙ выбранной карточки в модуль этой формы. Нужны фактические клиент и сервер 8.5.1.1343; запускайте толстый клиент управляемого приложения своей Windows VM. Веб-клиент, мобильное приложение, сетевые пути UNC и адреса HTTP/FTP/URI для этого опыта не подходят.

  3. В свойствах формы свяжите событие ПриОткрытии с процедурой ПриОткрытии(Отказ). Не вызывайте ее вручную. Создайте реквизиты: СогласенНаСвоюКопию85 — Булево с исходным значением Ложь и ручным флажком; ОтветРазрешения85 и РазрешениеNative85 — Булево; Сумма85 — Число длина15, точность2; ВерсияRuntime85, Состояние85, ПутьИсточника85 и ПутьКопии85 — Строка. Добавьте поля на форму. Всем полям, кроме флажка, задайте ТолькоПросмотр=Да. ОтветРазрешения85 показывает, получен ли ответ платформы: начальная Ложь в РазрешениеNative85 сама по себе не означает отказ.

  4. До запуска вручную создайте маленький файл UTF-8 OwnSeed125_4581fd24-c0a1-4484-9ad3-59c7ed73b507.json в стандартной папке Documents своего нового профиля. Это вымышленный учебный документ, не данные клиента. Содержимое: {"App":"УчебноеКопирование125","Version":"4581fd24-c0a1-4484-9ad3-59c7ed73b507","SeedNonce":"14818376-310e-4168-aaf0-c5b7b59c6347","RowA":{"Item":"A","Qty":1,"Price":50},"RowB":{"Item":"B","Qty":1,"Price":75},"Total":125}. Маркеры Version/SeedNonce — только метки своего учебного файла, НЕ идентификаторы ОС/пользователя/ИБ.

  5. Пути программа получает от платформы: КаталогДокументов указывает стандартную папку документов, а РабочийКаталогДанныхПользователя — рабочую папку данных данного пользователя этой базы. Не подставляйте произвольный C:\Users\... . Принимается только обычный локальный путь с буквой диска; сначала проверяется существование, затем признак каталога. Если стандартная папка документов нового профиля отсутствует, подготовьте ее своими руками или остановитесь. Получение рабочего каталога может автоматически создать его: отдельное ручное согласие требуется ДО его вызова.

  6. Прочитайте, что будет сделано, и только затем поставьте флажок СогласенНаСвоюКопию85. Вы разрешаете возможное создание рабочей папки данных, один новый дочерний каталог OwnCopy125_<UUID> и одну копию подготовленного учебного файла. UUID здесь означает новый уникальный идентификатор имени каталога, не системный идентификатор пользователя. Согласие используется один раз и флажок снимается. Это отдельное решение человека: синхронный ЗапроситьРазрешениеПользователя в толстом/тонком клиенте всегда возвращает Истина и не доказывает ни согласие человека, ни права ОС, ни показ диалога.

  7. Запрос разрешения описывает ровно одну операцию. Внешний Массив содержит один внутренний Массив: сначала точное имя метода, затем его параметры в том же порядке, что и в вызове. Для СоздатьКаталог это имя и путь; для КопироватьФайл — имя, исходный путь и путь новой копии. У методов Начать... параметр ОписаниеОповещения в этот массив не включается. После создания каталога для копирования отправляется НОВЫЙ запрос. Поиск файлов, маски, удаление, перенос и запуск программ здесь не нужны.

  8. Разрешение действует только до соответствующего вызова или окончания текущего вызова встроенного языка. Поэтому после ответа проверяются его тип Булево и значение Истина, еще раз читается свой исходный файл и проверяется отсутствие занятого имени, затем сразу вызывается соответствующий метод. Между ответом и вызовом нет обращения к серверу или другого Ждать. Разрешение не сохраняется для следующей кнопки или следующего обратного вызова.

  9. Новый дочерний каталог должен отсутствовать до создания и действительно быть каталогом после него. Само отсутствие исключения недостаточно: СоздатьКаталог может не сообщить ошибку, если каталог уже есть. КопироватьФайл способен перезаписывать существующий файл, поэтому занятый путь приемника дает STOP перед вызовом. Проверка не гарантирует атомарную защиту от одновременного вмешательства другой программы, символических ссылок или подмены пути; в новом учебном стенде не допускайте таких вмешательств.

  10. Исходник и копия читаются полностью. Проверяются все шесть полей JSON и типы их значений: App, Version, SeedNonce, RowA, RowB, Total. В каждой из двух строк проверяются Item, Qty и Price: A,1,50 и B,1,75; пересчитанная сумма должна дать 125. Затем сравниваются целые байты обоих файлов через одинаковое преобразование Base64Строка, включая его переносы строк MIME. Размер ограничен 65536 байтами. Совпадения лишь итоговой суммы недостаточно.

  11. В вариантах с Ждать и обратными вызовами методы создания и копирования возвращают Строку — фактический путь. Его сравнивают с заранее вычисленным путем своего каталога или копии, затем реально перечитывают результат. Синхронные СоздатьКаталог/КопироватьФайл значения не возвращают; не присваивайте им выдуманный результат Булево. Успех определяется проверками каталога, байтов и содержимого.

  12. После отказа, исключения, неожиданного ответа, изменения файла или повторного запуска состояние этого экземпляра остается STOP. Автоматического повтора, удаления и восстановления нет; созданные материалы остаются. ЧтениеJSON.Закрыть только освобождает чтение, а не удаляет файлы. Неизвестный исход не называется успехом. Код не обещает копирование прав доступа исходника или техническую приватность. Для нового опыта вручную подготовьте новый экземпляр формы и свои учебные материалы.

  13. На вкладке Команды формы создайте единственную команду КопироватьCallbacks85. В свойстве Действие назначьте одноименную процедуру КопироватьCallbacks85(Команда) из кода. Добавьте кнопку, укажите эту команду в ИмяКоманды. Запускайте нажатием кнопки, не ручным вызовом процедуры. Этот вариант продолжает работу только из настоящих обратных вызовов платформы. Нормальный обработчик принимает два параметра: результат и сохраненное состояние опыта. Обработчик ошибки принимает три. Состояние ожидания устанавливается ДО Начать..., чтобы немедленный ответ не был затерт последующей записью.

  14. Экспортные нормальные обработчики ПолученыДокументы85, ПолученРабочий85, РазрешеноСоздание85, СозданКаталог85, РазрешеноКопирование85 и СкопированПакет85 принимают ровно два параметра. ОшибкаПакета85 принимает ИнформацияОбОшибке, Булево СтандартнаяОбработка и сохраненное состояние — ровно три параметра. Новый ОписаниеОповещения задает имя, ЭтотОбъект своей формы, состояние, имя обработчика ошибки и снова свою форму. Все десять полей состояния сверяются: уникальный номер, этап, версия, пути, исходные байты и согласие. Неопределено допустимо лишь для еще не полученного собственного значения на раннем этапе. Стандартное отображение ошибки не отключается. В справке двух методов получения каталогов есть фраза «имя временного файла»: код не полагается на нее и проверяет, что возвращенная строка указывает существующий каталог.

&НаКлиенте
Перем Остановка85, Этап85, СогласиеИспользовано85, Версия85, Номер85;
&НаКлиенте
Перем Документы85, Рабочий85, Каталог85, Источник85, Приемник85, Образец85;

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    Если СогласиеИспользовано85 <> Неопределено Тогда
        Отказ = Истина;
        Возврат;
    КонецЕсли;
    Остановка85 = Истина;
    СогласиеИспользовано85 = Ложь;
    СогласенНаСвоюКопию85 = Ложь;
    ОтветРазрешения85 = Ложь;
    РазрешениеNative85 = Ложь;
    Сумма85 = 0;
    Попытка
        Версия85 = ПроверитьКлиент85();
        Если ПодтвердитьСвоюCF85() <> Истина Тогда
            ВызватьИсключение "Не подтверждена собственная новая CF";
        КонецЕсли;
        ВерсияRuntime85 = Версия85;
        Этап85 = "Готов";
        Остановка85 = Ложь;
        Состояние85 = "Прочитайте опыт: отдельное согласие требуется ДО возможного создания UserData";
    Исключение
        Остановить85(ОписаниеОшибки());
        Отказ = Истина;
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура Остановить85(Причина)
    Остановка85 = Истина;
    Этап85 = "STOP";
    СогласенНаСвоюКопию85 = Ложь;
    Состояние85 = "STOP этого экземпляра, без повторов/удаления/восстановления. " + Причина;
КонецПроцедуры

&НаКлиенте
Функция ПроверитьКлиент85()
    #Если ТолстыйКлиентУправляемоеПриложение Тогда
        Среда = Новый СистемнаяИнформация;
        Версия = Среда.ВерсияПриложения;
        Возврат Версия;
    #Иначе
        ВызватьИсключение "Не этот клиент: web/mobile/remoteFS fallback запрещен";
    #КонецЕсли
КонецФункции

&НаСервереБезКонтекста
Функция ПодтвердитьСвоюCF85()
    #Если Сервер Тогда
        Если Метаданные.ОбщиеФормы.Количество() <> 1 Или Метаданные.ОбщиеФормы.Найти("Копирование125") = Неопределено Тогда
            ВызватьИсключение "Не совпали свой сервер/runtime/CF marker/единственная форма";
        КонецЕсли;
        Возврат Истина;
    #Иначе
        ВызватьИсключение "Нужен настоящий сервер своей CF";
    #КонецЕсли
КонецФункции

&НаКлиенте
Процедура НачатьОпыт85(Команда, Имя)
    Если Остановка85 <> Ложь Или Этап85 <> "Готов" Тогда
        ВызватьИсключение "Повтор/остановленный экземпляр запрещен";
    КонецЕсли;
    Если ТипЗнч(Команда) <> Тип("КомандаФормы") Или Команда <> Команды.Найти(Имя)
        Или ПроверитьКлиент85() <> Версия85 Или ПодтвердитьСвоюCF85() <> Истина Тогда
        ВызватьИсключение "Не своя реальная команда/CF/runtime";
    КонецЕсли;
    Если СогласиеИспользовано85 <> Ложь Или ТипЗнч(СогласенНаСвоюКопию85) <> Тип("Булево")
        Или СогласенНаСвоюКопию85 <> Истина Тогда
        ВызватьИсключение "Нужно отдельное ручное согласие владельца всей новой лаборатории";
    КонецЕсли;
    СогласиеИспользовано85 = Истина;
    СогласенНаСвоюКопию85 = Ложь;
    Номер85 = Строка(Новый УникальныйИдентификатор);
    Если СтрДлина(Номер85) <> 36 Или Номер85 = "00000000-0000-0000-0000-000000000000" Тогда
        ВызватьИсключение "Нет собственного nonce имени нового child";
    КонецЕсли;
    Этап85 = "ПУТИ";
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьПродолжение85(Фаза)
    Если Остановка85 <> Ложь Или Этап85 <> Фаза Или СогласиеИспользовано85 <> Истина
        Или ПроверитьКлиент85() <> Версия85 Тогда
        ВызватьИсключение "STOP/повтор/измененная фаза/consent/runtime";
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Функция ПроверитьКаталог85(Имя)
    Если ТипЗнч(Имя) <> Тип("Строка") Тогда
        ВызватьИсключение "Native каталог не Строка";
    КонецЕсли;
    Если СтрДлина(Имя) < 3 Или Сред(Имя, 2, 2) <> ":\" Или СтрНайти(Имя, "..") > 0
        Или СтрНайти(Имя, "/") > 0 Тогда
        ВызватьИсключение "Только обычный локальный Windows drive path, не URI/UNC/relative";
    КонецЕсли;
    ФайлКаталога = Новый Файл(Имя);
    Есть = ФайлКаталога.Существует();
    Если ТипЗнч(Есть) <> Тип("Булево") Или Есть <> Истина Тогда
        ВызватьИсключение "Полученный native каталог реально не существует";
    КонецЕсли;
    ЭтоКаталог = ФайлКаталога.ЭтоКаталог();
    Если ТипЗнч(ЭтоКаталог) <> Тип("Булево") Или ЭтоКаталог <> Истина Тогда
        ВызватьИсключение "Получена не директория";
    КонецЕсли;
    Полное = ФайлКаталога.ПолноеИмя;
    Если Прав(Полное, 1) <> "\" Тогда
        Полное = Полное + "\";
    КонецЕсли;
    Возврат Полное;
КонецФункции

&НаКлиенте
Процедура ПринятьКаталоги85(КаталогДокументовПолученный85, Рабочий)
    ПроверитьПродолжение85("ПУТИ");
    Документы85 = ПроверитьКаталог85(КаталогДокументовПолученный85);
    Рабочий85 = ПроверитьКаталог85(Рабочий);
    Источник85 = Документы85 + "OwnSeed125_4581fd24-c0a1-4484-9ad3-59c7ed73b507.json";
    Каталог85 = Рабочий85 + "OwnCopy125_" + Номер85;
    Приемник85 = Каталог85 + "\OwnCopy125.json";
    Снимок = ПрочитатьПакет85(Источник85);
    Образец85 = Снимок.Encoded;
    ПутьИсточника85 = Источник85;
    ПутьКопии85 = Приемник85;
    Этап85 = "СОЗДАТЬ";
КонецПроцедуры

&НаКлиенте
Функция ПроверитьСтроку85(СтрокаПакета, Код, Цена)
    Если ТипЗнч(СтрокаПакета) <> Тип("Структура") Тогда
        ВызватьИсключение "Собственная строка не Структура";
    КонецЕсли;
    Если СтрокаПакета.Количество() <> 3 Или Не СтрокаПакета.Свойство("Item")
        Или Не СтрокаПакета.Свойство("Qty") Или Не СтрокаПакета.Свойство("Price") Тогда
        ВызватьИсключение "Нужны ровно Item/Qty/Price";
    КонецЕсли;
    Если ТипЗнч(СтрокаПакета.Item) <> Тип("Строка") Или СтрокаПакета.Item <> Код
        Или ТипЗнч(СтрокаПакета.Qty) <> Тип("Число") Или СтрокаПакета.Qty <> 1
        Или ТипЗнч(СтрокаПакета.Price) <> Тип("Число") Или СтрокаПакета.Price <> Цена Тогда
        ВызватьИсключение "Изменены полные типы/значения своей строки";
    КонецЕсли;
    Возврат СтрокаПакета.Qty * СтрокаПакета.Price;
КонецФункции

&НаКлиенте
Функция ПрочитатьПакет85(Имя)
    Если Имя <> Источник85 И Имя <> Приемник85 Тогда
        ВызватьИсключение "Не один из двух собственных заранее определенных файлов";
    КонецЕсли;
    ФайлПакета = Новый Файл(Имя);
    Есть = ФайлПакета.Существует();
    Если ТипЗнч(Есть) <> Тип("Булево") Или Есть <> Истина Тогда
        ВызватьИсключение "Нет собственного файла";
    КонецЕсли;
    ЭтоФайл = ФайлПакета.ЭтоФайл();
    Если ТипЗнч(ЭтоФайл) <> Тип("Булево") Или ЭтоФайл <> Истина Тогда
        ВызватьИсключение "Не обычный файл";
    КонецЕсли;
    Родитель = ?(Имя = Источник85, Документы85, Каталог85 + "\");
    Если ФайлПакета.Путь <> Родитель Или ФайлПакета.ПолноеИмя <> Имя Тогда
        ВызватьИсключение "Не совпал сохраненный собственный путь";
    КонецЕсли;
    Размер = ФайлПакета.Размер();
    Если ТипЗнч(Размер) <> Тип("Число") Или Размер <= 0 Или Размер > 65536 Или Размер <> Цел(Размер) Тогда
        ВызватьИсключение "Только маленький непустой собственный seed";
    КонецЕсли;
    Данные = Новый ДвоичныеДанные(Имя);
    Если Данные.Размер() <> Размер Тогда
        ВызватьИсключение "Размер изменился во время чтения";
    КонецЕсли;
    Код = Base64Строка(Данные);
    Если ТипЗнч(Код) <> Тип("Строка") Или Код = "" Тогда
        ВызватьИсключение "Не получены целые собственные байты";
    КонецЕсли;
    Чтение = Новый ЧтениеJSON;
    Чтение.ОткрытьФайл(Имя);
    Попытка
        Пакет = ПрочитатьJSON(Чтение);
    Исключение
        Чтение.Закрыть();
        ВызватьИсключение;
    КонецПопытки;
    Чтение.Закрыть();
    Если ТипЗнч(Пакет) <> Тип("Структура") Тогда
        ВызватьИсключение "Seed JSON не Структура";
    КонецЕсли;
    Если Пакет.Количество() <> 6 Или Не Пакет.Свойство("App") Или Не Пакет.Свойство("Version")
        Или Не Пакет.Свойство("SeedNonce") Или Не Пакет.Свойство("RowA") Или Не Пакет.Свойство("RowB")
        Или Не Пакет.Свойство("Total") Тогда
        ВызватьИсключение "Нужны ровно шесть полей собственного seed";
    КонецЕсли;
    Если ТипЗнч(Пакет.App) <> Тип("Строка") Или Пакет.App <> "УчебноеКопирование125"
        Или ТипЗнч(Пакет.Version) <> Тип("Строка") Или Пакет.Version <> "4581fd24-c0a1-4484-9ad3-59c7ed73b507"
        Или ТипЗнч(Пакет.SeedNonce) <> Тип("Строка") Или Пакет.SeedNonce <> "14818376-310e-4168-aaf0-c5b7b59c6347"
        Или ТипЗнч(Пакет.Total) <> Тип("Число") Или Пакет.Total <> 125 Тогда
        ВызватьИсключение "Не совпали свои App/version/seed label/typed total";
    КонецЕсли;
    Итог = ПроверитьСтроку85(Пакет.RowA, "A", 50) + ПроверитьСтроку85(Пакет.RowB, "B", 75);
    Если Итог <> 125 Или Итог <> Пакет.Total Тогда
        ВызватьИсключение "Полные две строки не дали125";
    КонецЕсли;
    Возврат Новый Структура("Encoded,Total", Код, Итог);
КонецФункции

&НаКлиенте
Процедура ПроверитьОперацию85(Создание)
    ПроверитьПродолжение85(?(Создание, "СОЗДАТЬ", "КОПИРОВАТЬ"));
    Снимок = ПрочитатьПакет85(Источник85);
    Если Снимок.Encoded <> Образец85 Или Снимок.Total <> 125 Тогда
        ВызватьИсключение "Целый исходный seed изменился";
    КонецЕсли;
    ФайлКаталога = Новый Файл(Каталог85);
    Если Создание Тогда
        Есть = ФайлКаталога.Существует();
        Если ТипЗнч(Есть) <> Тип("Булево") Или Есть <> Ложь Тогда
            ВызватьИсключение "Коллизия ownGUIDchild: не используем существующий каталог";
        КонецЕсли;
    Иначе
        Если ПроверитьКаталог85(Каталог85) <> Каталог85 + "\" Тогда
            ВызватьИсключение "Нет именно своего созданного каталога";
        КонецЕсли;
    КонецЕсли;
    ФайлПриемника = Новый Файл(Приемник85);
    Есть = ФайлПриемника.Существует();
    Если ТипЗнч(Есть) <> Тип("Булево") Или Есть <> Ложь Тогда
        ВызватьИсключение "Коллизия приемника: Copy умеет перезаписывать, здесь STOP";
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Функция Вызовы85(ИмяМетода, Создание)
    Если Создание Тогда
        Если ИмяМетода <> "СоздатьКаталог" И ИмяМетода <> "СоздатьКаталогАсинх"
            И ИмяМетода <> "НачатьСозданиеКаталога" Тогда
            ВызватьИсключение "Не разрешенное имя native create";
        КонецЕсли;
    ИначеЕсли ИмяМетода <> "КопироватьФайл" И ИмяМетода <> "КопироватьФайлАсинх"
        И ИмяМетода <> "НачатьКопированиеФайла" Тогда
        ВызватьИсключение "Не разрешенное имя native copy";
    КонецЕсли;
    Вызов = Новый Массив;
    Вызов.Добавить(ИмяМетода);
    Если Создание Тогда
        Вызов.Добавить(Каталог85);
    Иначе
        Вызов.Добавить(Источник85);
        Вызов.Добавить(Приемник85);
    КонецЕсли;
    Если Вызов.Количество() <> ?(Создание, 2, 3) Тогда
        ВызватьИсключение "Не совпали полные позиционные аргументы";
    КонецЕсли;
    Вызовы = Новый Массив;
    Вызовы.Добавить(Вызов);
    Если Вызовы.Количество() <> 1 Тогда
        ВызватьИсключение "Только один точный вызов в новом запросе";
    КонецЕсли;
    Возврат Вызовы;
КонецФункции

&НаКлиенте
Процедура ПринятьРазрешение85(Ответ)
    Если ТипЗнч(Ответ) <> Тип("Булево") Тогда
        ВызватьИсключение "Разрешение native не Bool";
    КонецЕсли;
    ОтветРазрешения85 = Истина;
    РазрешениеNative85 = Ответ;
    Если Ответ <> Истина Тогда
        ВызватьИсключение "NativeFalse: действие не выполняется";
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьСоздание85()
    ПроверитьПродолжение85("СОЗДАТЬ");
    Если ПроверитьКаталог85(Каталог85) <> Каталог85 + "\" Тогда
        ВызватьИсключение "Не подтвержден созданный собственный каталог";
    КонецЕсли;
    Этап85 = "КОПИРОВАТЬ";
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьКопию85()
    ПроверитьПродолжение85("КОПИРОВАТЬ");
    Если ПодтвердитьСвоюCF85() <> Истина Тогда
        ВызватьИсключение "После копирования не подтвержден свой сервер";
    КонецЕсли;
    Исходный = ПрочитатьПакет85(Источник85);
    Скопированный = ПрочитатьПакет85(Приемник85);
    Если Исходный.Encoded <> Образец85 Или Скопированный.Encoded <> Образец85
        Или Исходный.Total <> 125 Или Скопированный.Total <> 125 Тогда
        ВызватьИсключение "Целые source/output bytes или typed125 не совпали";
    КонецЕсли;
    Сумма85 = Скопированный.Total;
    Этап85 = "Проверено";
    Состояние85 = "Собственная копия: целые байты MIMEBase64 и все typed поля совпали,50+75=125. Файлы оставлены, без cleanup";
КонецПроцедуры

&НаКлиенте
Функция СвоеОписание85(Имя)
    Состояние = Новый Структура("Nonce,Phase,Version,Documents,Work,Child,Source,Target,Encoded,Consent",
        Номер85, Этап85, Версия85, Документы85, Рабочий85, Каталог85, Источник85, Приемник85, Образец85, СогласиеИспользовано85);
    Возврат Новый ОписаниеОповещения(Имя, ЭтотОбъект, Состояние, "ОшибкаПакета85", ЭтотОбъект);
КонецФункции

&НаКлиенте
Процедура ПроверитьПоле85(Состояние, Имя, Ожидаемое)
    Если Не Состояние.Свойство(Имя, Значение) Тогда
        ВызватьИсключение "Нет собственного callback поля";
    КонецЕсли;
    Если ТипЗнч(Значение) <> ТипЗнч(Ожидаемое) Или Значение <> Ожидаемое Тогда
        ВызватьИсключение "Не совпало полное type/value собственного callback поля";
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьОповещение85(Состояние, Фаза)
    ПроверитьПродолжение85(Фаза);
    Если ТипЗнч(Состояние) <> Тип("Структура") Тогда
        ВызватьИсключение "Owncallback state не Структура";
    КонецЕсли;
    Если Состояние.Количество() <> 10 Тогда
        ВызватьИсключение "Нужны ровно десять своих callback полей";
    КонецЕсли;
    ПроверитьПоле85(Состояние, "Nonce", Номер85);
    ПроверитьПоле85(Состояние, "Phase", Фаза);
    ПроверитьПоле85(Состояние, "Version", Версия85);
    ПроверитьПоле85(Состояние, "Documents", Документы85);
    ПроверитьПоле85(Состояние, "Work", Рабочий85);
    ПроверитьПоле85(Состояние, "Child", Каталог85);
    ПроверитьПоле85(Состояние, "Source", Источник85);
    ПроверитьПоле85(Состояние, "Target", Приемник85);
    ПроверитьПоле85(Состояние, "Encoded", Образец85);
    ПроверитьПоле85(Состояние, "Consent", Истина);
КонецПроцедуры

&НаКлиенте
Процедура КопироватьCallbacks85(Команда)
    Попытка
        НачатьОпыт85(Команда, "КопироватьCallbacks85");
        Этап85 = "ЖДЕМ_DOCS";
        НачатьПолучениеКаталогаДокументов(СвоеОписание85("ПолученыДокументы85"));
    Исключение
        Остановить85(ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура ПолученыДокументы85(ИмяКаталога, Состояние) Экспорт
    Если Остановка85 <> Ложь Тогда
        Возврат;
    КонецЕсли;
    Попытка
        ПроверитьОповещение85(Состояние, "ЖДЕМ_DOCS");
        Документы85 = ПроверитьКаталог85(ИмяКаталога);
        Этап85 = "ЖДЕМ_WORK";
        НачатьПолучениеРабочегоКаталогаДанныхПользователя(СвоеОписание85("ПолученРабочий85"));
    Исключение
        Остановить85(ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура ПолученРабочий85(ИмяКаталога, Состояние) Экспорт
    Если Остановка85 <> Ложь Тогда
        Возврат;
    КонецЕсли;
    Попытка
        ПроверитьОповещение85(Состояние, "ЖДЕМ_WORK");
        Этап85 = "ПУТИ";
        ПринятьКаталоги85(Документы85, ИмяКаталога);
        ПроверитьОперацию85(Истина);
        Этап85 = "ЖДЕМ_РАЗР_CREATE";
        НачатьЗапросРазрешенияПользователя(СвоеОписание85("РазрешеноСоздание85"), Вызовы85("НачатьСозданиеКаталога", Истина));
    Исключение
        Остановить85(ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура РазрешеноСоздание85(Ответ, Состояние) Экспорт
    Если Остановка85 <> Ложь Тогда
        Возврат;
    КонецЕсли;
    Попытка
        ПроверитьОповещение85(Состояние, "ЖДЕМ_РАЗР_CREATE");
        ПринятьРазрешение85(Ответ);
        Этап85 = "СОЗДАТЬ";
        ПроверитьОперацию85(Истина);
        Этап85 = "ЖДЕМ_CREATE";
        НачатьСозданиеКаталога(СвоеОписание85("СозданКаталог85"), Каталог85);
    Исключение
        Остановить85(ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура СозданКаталог85(Созданный, Состояние) Экспорт
    Если Остановка85 <> Ложь Тогда
        Возврат;
    КонецЕсли;
    Попытка
        ПроверитьОповещение85(Состояние, "ЖДЕМ_CREATE");
        Если ТипЗнч(Созданный) <> Тип("Строка") Или Созданный <> Каталог85 Тогда
            ВызватьИсключение "Native callbackcreate не вернул именно свой путь";
        КонецЕсли;
        Этап85 = "СОЗДАТЬ";
        ПроверитьСоздание85();
        ПроверитьОперацию85(Ложь);
        Этап85 = "ЖДЕМ_РАЗР_COPY";
        НачатьЗапросРазрешенияПользователя(СвоеОписание85("РазрешеноКопирование85"), Вызовы85("НачатьКопированиеФайла", Ложь));
    Исключение
        Остановить85(ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура РазрешеноКопирование85(Ответ, Состояние) Экспорт
    Если Остановка85 <> Ложь Тогда
        Возврат;
    КонецЕсли;
    Попытка
        ПроверитьОповещение85(Состояние, "ЖДЕМ_РАЗР_COPY");
        ПринятьРазрешение85(Ответ);
        Этап85 = "КОПИРОВАТЬ";
        ПроверитьОперацию85(Ложь);
        Этап85 = "ЖДЕМ_COPY";
        НачатьКопированиеФайла(СвоеОписание85("СкопированПакет85"), Источник85, Приемник85);
    Исключение
        Остановить85(ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура СкопированПакет85(Скопированный, Состояние) Экспорт
    Если Остановка85 <> Ложь Тогда
        Возврат;
    КонецЕсли;
    Попытка
        ПроверитьОповещение85(Состояние, "ЖДЕМ_COPY");
        Если ТипЗнч(Скопированный) <> Тип("Строка") Или Скопированный <> Приемник85 Тогда
            ВызватьИсключение "Native callbackcopy не вернул именно свой путь";
        КонецЕсли;
        Этап85 = "КОПИРОВАТЬ";
        ПроверитьКопию85();
    Исключение
        Остановить85(ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура ОшибкаПакета85(Ошибка, СтандартнаяОбработка, Состояние) Экспорт
    Если ТипЗнч(СтандартнаяОбработка) <> Тип("Булево") Тогда
        СтандартнаяОбработка = Истина;
        Остановить85("Не Bool параметр стандартной обработки native ошибки");
        Возврат;
    КонецЕсли;
    СтандартнаяОбработка = Истина;
    Если Остановка85 <> Ложь Тогда
        Возврат;
    КонецЕсли;
    Попытка
        ПроверитьОповещение85(Состояние, Этап85);
        Если ТипЗнч(Ошибка) <> Тип("ИнформацияОбОшибке") Или ТипЗнч(Ошибка.Описание) <> Тип("Строка") Тогда
            ВызватьИсключение "Не native ИнформацияОбОшибке";
        КонецЕсли;
        Остановить85("Native error: " + Ошибка.Описание);
    Исключение
        Остановить85(ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

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

  1. Подготовьте свой новый стенд, учебный JSON и форму строго по разделу подготовки. Откройте форму: сначала проверяются версия платформы и метки своей конфигурации; каталогов и копии на этом этапе программа не создает.

  2. Прочитайте предупреждение и поставьте флажок. Нажмите КопироватьCallbacks85 один раз. Программа получает стандартные каталоги от платформы и строит имя нового OwnCopy125_<UUID>; случайное имя появляется только при запуске, заранее не подставляйте его в код.

  3. Сначала полностью читается исходный JSON и проверяется сумма50+75=125. На создание дочернего каталога запрашивается отдельное разрешение. Перед вызовом проверяются ответ, неизменность исходника и отсутствие занятого имени, после вызова — существование настоящего каталога.

  4. На копирование запрашивается новое отдельное разрешение. Проверки повторяются непосредственно перед операцией; копируется только указанный учебный файл в новый приемник. В вариантах Ждать/Начать... отдельно проверяется возвращенный путь.

  5. После копирования исходник и результат читаются снова: сравниваются все байты, шесть полей документа и обе вложенные строки. Изучите ПутьИсточника85, ПутьКопии85, Сумма85 и Состояние85. Файлы остаются на стенде; дальнейшую уборку этот код не выполняет.

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

  1. Опыт без согласия: в новом экземпляре формы НЕ ставьте флажок, нажмите КопироватьCallbacks85. Должен появиться STOP; рабочий каталог через метод не запрашивается, дочерний каталог и копия не создаются, Сумма85 остается0. Надписи Проверено быть не должно.

  2. Нормальный опыт: заново откройте подготовленную форму, проверьте правильный JSON, поставьте флажок и нажмите КопироватьCallbacks85. ПутьКопии85 должен реально указывать новый OwnCopy125_<UUID>\OwnCopy125.json в полученном рабочем каталоге. Ожидаются Сумма85=125 и Состояние85, начинающееся словами «Собственная копия» и сообщающее совпадение байтов и полей. В отладчике можно дополнительно посмотреть Этап85="Проверено"; это внутренняя переменная, не реквизит формы. Одно лишь отсутствие ошибки не достаточно.

  3. Откройте свои исходный файл и копию только на новом стенде. Исходник должен остаться тем же: App=УчебноеКопирование125, Version=4581fd24-c0a1-4484-9ad3-59c7ed73b507, SeedNonce=14818376-310e-4168-aaf0-c5b7b59c6347, RowA={Item:A,Qty:1,Price:50}, RowB={Item:B,Qty:1,Price:75}, Total=125. У копии должны совпасть все шесть полей, три поля каждой строки и типы значений; код дополнительно сверяет целые байты.

  4. Испорченный исходник: только в отдельном новом учебном опыте измените в файле одно поле Total на126, не исправляя строки. В другом отдельном опыте верните правильный файл и измените лишь RowA.Price на51. Оба запуска с флажком должны дать STOP ДО создания дочернего каталога и копии; Проверено и125 как подтвержденного итога быть не должно. Затем руками восстановите свой учебный файл и подготовьте новый экземпляр.

  5. Занятый приемник: только на отдельном новом стенде поставьте точку останова отладчика после создания дочернего каталога, но до запроса разрешения на копирование. По вычисленному ПутьКопии85 вручную создайте свой маленький файл-заглушку, продолжите выполнение. Ожидается STOP перед КопироватьФайл; заглушка не должна быть заменена и Проверено не появляется. Не подменяйте сам путь в программе и не испытывайте это в рабочих каталогах.

  6. Отрицательный ответ платформы: если настоящий ответ запроса или обратного вызова равен Ложь, соответствующая операция не должна начаться и результатом не может быть Проверено. Не вызывайте обработчики вручную и не подставляйте ложный ответ. Синхронный запрос в толстом клиенте всегдаИстина, поэтому отказ этим способом там не воспроизводится; отсутствие реального отрицательного ответа честно отмечайте как непроверенный случай.

  7. Повтор: после завершения или STOP нажмите КопироватьCallbacks85 еще раз в том же экземпляре. Ожидается STOP без новой операции. Не пытайтесь снять остановку изменением переменных. Все отрицательные опыты проводятся лишь на своей новой виртуальной машине; для каждого нужен новый экземпляр и вручную подготовленные материалы.

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

После будущего ручного запуска на своем новом стенде: один новый каталог, одна копия, неизменный исходник, совпавшие байты и полный документ с суммой125. Отказ, неизвестный результат или ошибка не являются успехом. Сейчас выполнены только проверки исходника и контрактов справки; запуск в1С не проверялся.

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

  1. ЗапроситьРазрешениеПользователя устарел начиная с8.3.15. В тонком/толстом клиенте он всегдаИстина: не считайте это человеческим согласием или доказательством прав ОС.

  2. РабочийКаталогДанныхПользователя может создавать каталог. Поэтому даже получение этого пути требует заранее прочитанного предупреждения и отдельного ручного согласия в учебном опыте.

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

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

  5. Возвращенный путь создания/копирования — Строка, не Булево. В справке обратных вызовов каталогов есть неточная фраза о временном файле: обязательно проверьте, что получен именно каталог. Закрытие ЧтениеJSON освобождает чтение, а не удаляет файл.

  6. STOP относится к текущему экземпляру. После ошибки материалы могли остаться; отсутствие обратного вызова не доказывает успех. Повтор, уборка и восстановление не автоматизированы, новый опыт начинается только после ручной подготовки.

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

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

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

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

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