Как открыть книгу Excel через COM в 1С монопольно с блокировкой для других пользователей?

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

При программной обработке табличных документов часто возникает необходимость заблокировать исходный файл от одновременного редактирования пользователем. Если файл открывается в фоновом режиме через COMОбъект("Excel.Application"), разработчик ожидает, что при попытке интерактивного открытия Excel выведет стандартное предупреждение о занятости файла другим процессом. Однако на практике интерактивный Excel нередко открывает такой файл без предупреждений, что приводит к ошибкам при сохранении или чтении данных в 1С.

Разберем причины такого поведения, изучим методы управления режимом доступа через COM и рассмотрим надежные альтернативные способы контроля блокировок средствами платформы 1С.

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

Проанализируем технические причины, из-за которых при фоновом открытии через COM файл не блокируется должным образом:

  1. Отсутствие регистрации в таблице активных объектов (ROT): Когда экземпляр Excel.Application инициализируется с параметром Visible = Ложь, он может не зарегистрировать открытую книгу в глобальной таблице активных объектов Windows. Интерактивный экземпляр Excel при запуске не находит информацию о занятости файла и пытается открыть его заново.
  2. Механизм временных файлов блокировки: Для информирования пользователей о монопольном режиме Excel создает скрытый файл-владелец вида ~$ИмяФайла.xlsx в той же директории. Если фоновый процесс или пользователь не имеют полных прав на создание временных файлов в каталоге, файл блокировки не формируется.
  3. Особенности работы под одной учетной записью: Если интерактивный пользователь и фоновый сеанс 1С работают в рамках одной сессии операционной системы, Excel может перехватить существующий дескриптор без вывода системных диалоговых окон.

Использование методов COM-объекта для установки режима доступа

Посмотрим на пример инициализации COM-объекта и попытку явного переключения прав доступа с помощью метода ChangeFileAccess объекта книги.


// Инициализация COM-объекта Excel
Приложение = Новый COMОбъект("Excel.Application");
Приложение.Visible = Ложь;
Приложение.DisplayAlerts = Ложь;

ПутьКФайлу = "C:\Files\Реестр.xlsx";
Книга = Приложение.WorkBooks.Open(ПутьКФайлу);

// Проверяем статус открытия и пытаемся установить режим записи
Если Книга.ReadOnly Тогда
    // xlReadWrite = 2, Notify = Истина (в COM передается -1 или True)
    Mode = 2;
    Notify = Истина;
    Попытка
        Книга.ChangeFileAccess(Mode, , Notify);
    Исключение
        Сообщить("Не удалось заблокировать файл на запись: " + ОписаниеОшибки());
    КонецПопытки;
КонецЕсли;

Приложение.DisplayAlerts = Истина;

Параметр DisplayAlerts временно отключает системные диалоги, чтобы выполнение кода 1С не зависало на модальных окнах Excel. Однако отключение предупреждений в момент открытия может подавлять и штатные механизмы регистрации блокировок, поэтому включать DisplayAlerts = Истина следует сразу после настройки режима доступа.

Проверка занятости файла средствами файловой системы 1С

Поскольку поведение COM-объекта Excel сильно зависит от установленной версии офисного пакета и разрядности операционной системы, полагаться исключительно на методы OLE небезопасно. Разберем практический способ проверки доступности файла средствами встроенного языка 1С перед обращением к тяжелым внешним объектам.

Попробуем выполнить монопольный захват файла на уровне операционной системы:


Функция ФайлЗаблокирован(Знач ПолноеИмяФайла)
    
    Файл = Новый Файл(ПолноеИмяФайла);
    Если Не Файл.Существует() Тогда
        Возврат Ложь;
    КонецЕсли;
    
    // Проверяем наличие временного файла блокировки Excel
    ИмяФайлаБлокировки = Файл.Путь + "~$" + Файл.Имя;
    ФайлБлокировки = Новый Файл(ИмяФайлаБлокировки);
    Если ФайлБлокировки.Существует() Тогда
        Возврат Истина;
    КонецЕсли;
    
    // Пробуем кратковременно переименовать файл для проверки файлового дескриптора
    ВременноеИмя = Файл.Путь + "test_lock_" + Файл.Имя;
    Попытка
        ПереместитьФайл(ПолноеИмяФайла, ВременноеИмя);
        ПереместитьФайл(ВременноеИмя, ПолноеИмяФайла);
        Возврат Ложь;
    Исключение
        // Если файл занят любым процессом, ОС выбросит исключение
        Возврат Истина;
    КонецПопытки;

КонецФункции

Рассмотрим порядок применения этой проверки:

  1. Перед вызовом WorkBooks.Open вызываем функцию ФайлЗаблокирован().
  2. Если функция возвращает Истина, выводим пользователю понятное сообщение и прерываем операцию, не создавая висящих процессов в диспетчере задач.
  3. Если файл свободен, переходим к его программному открытию.

Безопасная работа через временную копию

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


КаталогВременный = КаталогВременныхФайлов();
ИмяВременногоФайла = КаталогВременный + "temp_" + НомерВерсии + ".xlsx";

КопироватьФайл(ПутьКИсходномуФайлу, ИмяВременногоФайла);

// Работаем с изолированной копией через COM
Приложение = Новый COMОбъект("Excel.Application");
Приложение.Visible = Ложь;
Книга = Приложение.WorkBooks.Open(ИмяВременногоФайла);

// Чтение данных...

Книга.Close(Ложь);
Приложение.Quit();
Приложение = Неопределено;

УдалитьФайлы(ИмяВременногоФайла);

Такой подход полностью исключает конфликты между пользователем и кодом 1С: пользователь может свободно вносить правки в рабочий документ, пока 1С считывает данные из снимка.

Отказ от COM в пользу встроенных механизмов платформы

Выделим главное ограничение COM-автоматизации: зависимость от разрядности клиента, нестабильность фоновых процессов EXCEL.EXE при аварийных завершениях и несовместимость с серверами на базе Linux. Для чтения и формирования файлов Excel в платформе 1С предусмотрен встроенный объект ТабличныйДокумент.

Посмотрим, как считать файл без использования внешних библиотек:


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

Метод Прочитать() объекта ТабличныйДокумент открывает файл на чтение, быстро извлекает данные и сразу освобождает дескриптор, предотвращая конфликты блокировок.

← На главную