Как получить текущий каталог выполняемого файла для внешних обработок в 1С 8.3 на управляемых формах?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке внешних обработок для 1С 8.3 на управляемых формах часто возникает необходимость определить каталог, из которого запускается файл обработки. Эта задача становится критически важной, когда обработка должна взаимодействовать с другими файлами, расположенными рядом, например, с внешними библиотеками (DLL), текстовыми файлами настроек или дополнительными данными. Однако стандартные методы 1С, такие как КаталогТекущейБазы() или ТекущийКаталог(), не предоставляют нужной информации, поскольку они возвращают каталог информационной базы или текущий рабочий каталог процесса, но не путь к файлу самой обработки.

Давайте подробно рассмотрим, как мы можем решить эту проблему, учитывая различные сценарии запуска внешних обработок в управляемых формах.

Особенности работы с файлами в 1С и клиент-серверное взаимодействие

Прежде чем погрузиться в решения, мы должны понимать ключевые особенности архитектуры 1С 8.3, особенно при работе с управляемыми формами и в клиент-серверном варианте. Внешние обработки могут запускаться в следующих режимах:

  1. Толстый клиент: При запуске обработки через меню "Файл -> Открыть" файл обработки остаётся на диске пользователя, и его путь относительно легко получить.
  2. Тонкий клиент или веб-клиент: При работе в тонком или веб-клиенте, а также когда обработка добавляется как "Дополнительный отчет или обработка", файл обработки копируется во временный каталог на клиентской машине или даже выполняется из кэша. Прямой доступ к файловой системе клиента из кода 1С в этих режимах ограничен или отсутствует вовсе.
  3. Файловая информационная база: В этом случае все данные хранятся в одном файле на диске, и иногда внешние обработки могут быть расположены рядом с этим файлом.
  4. Серверная информационная база: Здесь обработка может выполняться как на клиенте, так и на сервере. При этом серверная часть кода не имеет представления о расположении файла обработки на клиенте.

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

Получение каталога внешней обработки, открытой через "Файл -> Открыть"

Если ваша внешняя обработка запускается пользователем вручную через меню "Файл -> Открыть" в толстом клиенте, мы можем достаточно просто получить её путь. Для этого мы используем функции, которые доступны на стороне клиента и позволяют работать с путями к файлам.

Использование КаталогФайла() и ЭтотОбъект.ИмяФайла

В контексте формы внешней обработки, запущенной таким образом, свойство ИмяФайла объекта обработки содержит полный путь к файлу .epf. Используя функцию КаталогФайла(), мы можем извлечь из этого полного пути только каталог.

Рассмотрим пример кода:


Функция ПолучитьКаталогВнешнейОбработки_ФайлОткрыть()
    // Проверяем, что код выполняется на клиенте,
    // так как на сервере эта информация недоступна.
    Если НЕ ЭтоКлиент() Тогда
        Возврат Неопределено; // Сервер не знает о расположении файла на клиенте
    КонецЕсли;

    // В толстом клиенте, при открытии через "Файл -> Открыть",
    // свойство ИмяФайла формы обработки содержит полный путь.
    // Если обработка запускается как основная (не дополнительная)
    // и свойство доступно в контексте
    Если ТипЗнч(ЭтотОбъект) = Тип("ВнешняяОбработкаОбъект") И ЭтоКлиент() Тогда
        Попытка
            // ЭтотОбъект.ИмяФайла доступно в модуле объекта внешней обработки
            // или через форму, если она передается в качестве параметра.
            Возврат КаталогФайла(ЭтотОбъект.ИмяФайла);
        Исключение
            // В некоторых случаях (например, если обработка загружена из базы),
            // ИмяФайла может быть недоступно или пустым.
            Возврат Неопределено;
        КонецПопытки;
    КонецЕсли;

    // Для универсальности и доступа из модуля формы
    // мы можем получить путь через ПутьКВнешнейОбработке.
    // Это свойство более надежно для управляемых форм,
    // запущенных через "Файл -> Открыть".
    Попытка
        Возврат КаталогФайла(ВнешниеОбработки.ПутьКВнешнейОбработке);
    Исключение
        Возврат Неопределено;
    КонецПопытки;
КонецФункции

Важно: Метод ВнешниеОбработки.ПутьКВнешнейОбработке (обращение к глобальному контексту клиента) наиболее надёжен для получения пути к файлу, если обработка открыта именно через "Файл -> Открыть". Мы всегда должны помнить, что этот метод работает только на клиенте, поскольку сервер не имеет представления о расположении файла на машине пользователя.

Работа с дополнительными отчетами и обработками

Ситуация значительно усложняется, когда внешняя обработка регистрируется в информационной базе как "Дополнительный отчет или обработка". В этом случае 1С копирует файл .epf во временный каталог на клиентской машине или в кэш. Соответственно, "родного" каталога у файла обработки в привычном понимании больше нет, и методы, описанные выше, не будут работать или вернут путь к временному расположению.

Если вашей обработке необходимо работать с сопутствующими файлами (например, DLL-библиотеками или файлами настроек), которые должны "лежать рядом" с ней, то для дополнительных обработок этот подход не годится. Нам придётся использовать альтернативные механизмы.

Альтернативные механизмы для дополнительных обработок

Для дополнительных обработок нам нужно обеспечить, чтобы сопутствующие файлы были доступны. Вот несколько подходов:

  1. Макеты в конфигурации или обработке: Если файлы не слишком велики и не являются бинарными (или могут быть преобразованы в двоичные данные), мы можем сохранить их в качестве макетов прямо в конфигурации или самой внешней обработке. Это наиболее чистый и управляемый способ распространения сопутствующих файлов.
  2. Двоичные данные в регистрах сведений: Для более крупных или часто обновляемых файлов, которые не являются частью основной конфигурации, мы можем хранить их в регистре сведений в виде двоичных данных. Это позволяет централизованно управлять файлами и обновлять их без изменения конфигурации.
  3. Серверное хранение: Если файлы нужны только на сервере или доступны по сети, мы можем хранить их на серверном диске или в сетевой папке, доступной для сервера 1С.
  4. Параметры обработки: Мы можем передавать пути к необходимым файлам в качестве параметров при запуске обработки.

Давайте подробнее остановимся на первом и втором подходах, так как они наиболее универсальны для управляемых форм.

Использование макетов для хранения сопутствующих файлов

Мы можем добавить в нашу внешнюю обработку (или в конфигурацию) макет, который будет содержать необходимые нам данные. Например, это может быть XML-файл с настройками или даже бинарные данные, которые затем будут записаны на диск.

Разберем по шагам, как это сделать:

  1. Добавляем макет: Откройте внешнюю обработку в конфигураторе. В дереве объектов обработки найдите ветку "Макеты". Добавьте новый макет, выберите его тип (например, "Двоичные данные", "Текстовый документ", "XML-документ") и загрузите в него ваш файл.
  2. Получаем данные из макета: В коде обработки мы можем получить содержимое макета как двоичные данные.
  3. Сохраняем данные во временный файл: Полученные двоичные данные мы можем записать во временный каталог на клиентской машине.

Посмотрим на пример кода для сохранения двоичных данных из макета во временный файл:


Функция СохранитьФайлИзМакетаВоВременныйКаталог(ИмяМакета, ИмяФайлаДляСохранения)
    Если НЕ ЭтоКлиент() Тогда
        // На сервере нет файловой системы клиента,
        // но можно сохранить на сервер, если нужно.
        // Для клиентской работы - Возврат Неопределено
        Возврат Неопределено;
    КонецЕсли;

    Попытка
        // Получаем макет по имени
        Макет = ЭтотОбъект.ПолучитьМакет(ИмяМакета);

        Если Макет = Неопределено Тогда
            Сообщить("Макет '" + ИмяМакета + "' не найден.");
            Возврат "";
        КонецЕсли;

        // Получаем двоичные данные из макета
        ДвоичныеДанные = Макет.ПолучитьДвоичныеДанные();

        Если ДвоичныеДанные = Неопределено Тогда
            Сообщить("Не удалось получить двоичные данные из макета '" + ИмяМакета + "'.");
            Возврат "";
        КонецЕсли;

        // Создаем путь к временному файлу
        ПутьКВременномуКаталогу = КаталогВременныхФайлов();
        ПолныйПутьКВременномуФайлу = ПутьКВременномуКаталогу + ИмяФайлаДляСохранения;

        // Записываем двоичные данные во временный файл
        ДвоичныеДанные.Записать(ПолныйПутьКВременномуФайлу);

        Сообщить("Файл '" + ИмяФайлаДляСохранения + "' успешно сохранен в: " + ПолныйПутьКВременномуФайлу);
        Возврат ПолныйПутьКВременномуФайлу;

    Исключение
        Сообщить("Ошибка при сохранении файла из макета: " + ОписаниеОшибки());
        Возврат "";
    КонецПопытки;
КонецФункции

// Пример использования:
// Если мы хотим использовать DLL-библиотеку MyLib.dll, которая хранится в макете "MyLibDLL"
// ПутьКDLL = СохранитьФайлИзМакетаВоВременныйКаталог("MyLibDLL", "MyLib.dll");
// Если Не ПустаяСтрока(ПутьКDLL) Тогда
//     // Теперь можно работать с DLL по пути ПутьКDLL
// КонецЕсли;

Этот подход позволяет нам "вынимать" необходимые файлы из обработки при её запуске и использовать их во временном каталоге. Это очень удобно для небольших вспомогательных файлов или DLL.

Использование двоичных данных из регистра сведений

Для более крупных или часто обновляемых файлов, которые нецелесообразно хранить в макетах самой обработки, мы можем использовать регистры сведений. Например, мы можем создать регистр сведений "ФайлыВнешнихОбработок" с измерениями "ИмяФайла" и ресурсом "ДвоичныеДанныеФайла".

Проанализируем шаги:

  1. Создаем регистр сведений: В конфигурации создаем регистр сведений, например, "ХранилищеФайловДляОбработок", с полями:
    • Измерение: ИмяФайла (Строка)
    • Ресурс: ДвоичныеДанные (ХранилищеЗначения)
  2. Загружаем файлы в регистр: Создайте обработку или используйте стандартный функционал для загрузки файлов в этот регистр.
  3. Читаем и сохраняем файл: В нашей внешней обработке мы можем запросом получить двоичные данные из регистра и затем сохранить их во временный каталог на клиенте.

Посмотрим на пример кода для получения и сохранения файла из регистра сведений:


Функция ПолучитьФайлИзРегистраВоВременныйКаталог(ИмяФайлаВРегистре)
    Если НЕ ЭтоКлиент() Тогда
        Возврат Неопределено;
    КонецЕсли;

    Попытка
        // Выполняем запрос для получения двоичных данных из регистра
        Запрос = Новый Запрос;
        Запрос.Текст =
            "ВЫБРАТЬ ПЕРВЫЕ 1
            |    ХранилищеФайловДляОбработок.ДвоичныеДанные
            |ИЗ
            |    РегистрСведений.ХранилищеФайловДляОбработок КАК ХранилищеФайловДляОбработок
            |ГДЕ
            |    ХранилищеФайловДляОбработок.ИмяФайла = &ИмяФайла";

        Запрос.УстановитьПараметр("ИмяФайла", ИмяФайлаВРегистре);

        РезультатЗапроса = Запрос.Выполнить();
        Выборка = РезультатЗапроса.Выбрать();

        Если Выборка.Следующий() Тогда
            ЗначениеХранилища = Выборка.ДвоичныеДанные;
            Если ЗначениеХранилища = Неопределено Тогда
                Сообщить("В регистре 'ХранилищеФайловДляОбработок' для файла '" + ИмяФайлаВРегистре + "' не найдены двоичные данные.");
                Возврат "";
            КонецЕсли;

            // Получаем сами двоичные данные
            ДвоичныеДанные = ЗначениеХранилища.Получить();

            // Создаем путь к временному файлу
            ПутьКВременномуКаталогу = КаталогВременныхФайлов();
            ПолныйПутьКВременномуФайлу = ПутьКВременномуКаталогу + ИмяФайлаВРегистре;

            // Записываем двоичные данные во временный файл
            ДвоичныеДанные.Записать(ПолныйПутьКВременномуФайлу);

            Сообщить("Файл '" + ИмяФайлаВРегистре + "' успешно сохранен из регистра в: " + ПолныйПутьКВременномуФайлу);
            Возврат ПолныйПутьКВременномуФайлу;
        Иначе
            Сообщить("Файл '" + ИмяФайлаВРегистре + "' не найден в регистре сведений 'ХранилищеФайловДляОбработок'.");
            Возврат "";
        КонецЕсли;

    Исключение
        Сообщить("Ошибка при получении файла из регистра: " + ОписаниеОшибки());
        Возврат "";
    КонецПопытки;
КонецФункции

// Пример использования:
// Если нам нужна DLL-библиотека MyBigLib.dll, хранится в регистре
// ПутьКDLL = ПолучитьФайлИзРегистраВоВременныйКаталог("MyBigLib.dll");
// Если Не ПустаяСтрока(ПутьКDLL) Тогда
//     // Теперь можно работать с DLL по пути ПутьКDLL
// КонецЕсли;

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

Универсальный подход (компромиссное решение)

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

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

  1. Сначала мы попытаемся получить путь как для обработки, открытой через "Файл -> Открыть".
  2. Если этот способ не сработал (например, обработка является дополнительной), то мы переходим к механизмам извлечения файлов из макетов или регистра сведений.

Рассмотрим, как могла бы выглядеть такая функция:


Функция ПолучитьДоступныйПутьКСопутствующемуФайлу(ИмяФайлаДляПоиска, ИмяМакетаСФайлом = "", ИмяФайлаВРегистре = "")
    Если НЕ ЭтоКлиент() Тогда
        Возврат Неопределено; // Этот код предназначен для клиента
    КонецЕсли;

    // 1. Попытка получить путь, если обработка открыта через "Файл -> Открыть" (толстый клиент)
    Попытка
        КаталогОбработки = КаталогФайла(ВнешниеОбработки.ПутьКВнешнейОбработке);
        Если Не ПустаяСтрока(КаталогОбработки) И ФайлСуществует(КаталогОбработки + ИмяФайлаДляПоиска) Тогда
            Сообщить("Файл найден рядом с обработкой, открытой через 'Файл -> Открыть'.");
            Возврат КаталогОбработки + ИмяФайлаДляПоиска;
        КонецЕсли;
    Исключение
        // Игнорируем ошибку, если свойство недоступно, переходим к следующему способу
    КонецПопытки;

    // 2. Если файл не найден рядом с открытой обработкой или это дополнительная обработка,
    // пытаемся извлечь из макета
    Если Не ПустаяСтрока(ИмяМакетаСФайлом) Тогда
        ПутьИзМакета = СохранитьФайлИзМакетаВоВременныйКаталог(ИмяМакетаСФайлом, ИмяФайлаДляПоиска);
        Если Не ПустаяСтрока(ПутьИзМакета) Тогда
            Сообщить("Файл успешно извлечен из макета обработки.");
            Возврат ПутьИзМакета;
        КонецЕсли;
    КонецЕсли;

    // 3. Если и из макета не удалось (или макет не указан), пытаемся извлечь из регистра сведений
    Если Не ПустаяСтрока(ИмяФайлаВРегистре) Тогда
        ПутьИзРегистра = ПолучитьФайлИзРегистраВоВременныйКаталог(ИмяФайлаВРегистре);
        Если Не ПустаяСтрока(ПутьИзРегистра) Тогда
            Сообщить("Файл успешно извлечен из регистра сведений.");
            Возврат ПутьИзРегистра;
        КонецЕсли;
    КонецЕсли;

    Сообщить("Не удалось получить доступ к файлу '" + ИмяФайлаДляПоиска + "' ни одним из доступных способов.");
    Возврат "";
КонецФункции

// Пример использования:
// ПутьКМоейБиблиотеке = ПолучитьДоступныйПутьКСопутствующемуФайлу("MyCustom.dll", "МакетМоейDLL", "MyCustom.dll");
// Если Не ПустаяСтрока(ПутьКМоейБиблиотеке) Тогда
//     // Далее работаем с библиотекой по полученному пути
// КонецЕсли;

В этой функции СохранитьФайлИзМакетаВоВременныйКаталог и ПолучитьФайлИзРегистраВоВременныйКаталог — это функции, которые мы уже рассмотрели ранее. Такой подход обеспечивает максимальную гибкость и надёжность для большинства сценариев.

Важные моменты и лучшие практики

Таким образом, мы выяснили, что прямой универсальный способ получить "родной" каталог внешней обработки для всех сценариев в 1С 8.3 УФ отсутствует. Однако, применяя комбинацию методов — прямое получение пути для обработок, открытых вручную, и извлечение файлов из макетов или регистров сведений для дополнительных обработок — мы можем успешно решить задачу взаимодействия с сопутствующими файлами и библиотеками. Это обеспечивает гибкость и надёжность наших разработок в различных условиях эксплуатации 1С.

← На главную