При интеграции 1С с Microsoft Excel через COM-соединение разработчики нередко сталкиваются с задачей выборочной защиты листа: необходимо заблокировать формулы и структуру таблицы, оставив определенный диапазон ячеек доступным для редактирования пользователю. Однако при попытке массово снять флаг блокировки с диапазона строк или колонок часто возникает исключение: «Нельзя установить свойство Locked класса Range» (ошибка времени выполнения COM / ошибка 1004). При этом изменение свойства для одной отдельной ячейки через коллекцию Cells отрабатывает без сбоев. Проанализируем причины такого поведения и разберем надежные способы решения этой проблемы.
Выясним причину, по которой Excel блокирует прямое присвоение значения свойству Locked у целого диапазона. Рассмотрим основные факторы:
Locked. Одиночная ячейка вне объединения меняется без проблем, но для диапазона возникает конфликт объектной модели.Unprotect() без передачи параметров не снимает защиту, если на листе установлен пароль. В режиме фоновой автоматизации через COM диалоговое окно ввода пароля не появляется, защита остается активной, и любая попытка изменить атрибут блокировки ячеек вызывает исключение.Если в вашем диапазоне присутствуют объединенные ячейки, разберем по шагам, как правильно обойти это ограничение. Мы можем либо временно отменить объединение, либо обращаться к объединенной области через свойство MergeArea.
Посмотрим на пример временного разъединения ячеек перед снятием защиты:
Лист = ЭксельКнига.Sheets(1);
Лист.Unprotect();
Область = Лист.Range("A1:B5");
Область.UnMerge();
Область.Locked = Ложь;
Если же структура документа требует сохранения объединения, применим поэлементный обход с обращением к MergeArea:
Лист = ЭксельКнига.Sheets(1);
Лист.Unprotect();
Для НомерСтроки = 1 По 5 Цикл
Для НомерКолонки = 1 По 2 Цикл
ТекущаяЯчейка = Лист.Cells(НомерСтроки, НомерКолонки);
ТекущаяЯчейка.MergeArea.Locked = Ложь;
КонецЦикла;
КонецЦикла;
Проанализируем ситуацию, когда лист защищен паролем. Метод Unprotect() требует передачи правильной парольной строки. Если пароль не передан или передан неверно, лист остается заблокированным. Рассмотрим правильный синтаксис вызова:
ПарольЛиста = "МойПароль123";
Лист = ЭксельКнига.Sheets(1);
Лист.Unprotect(ПарольЛиста);
Лист.Range("A1:B5").Locked = Ложь;
Лист.Protect(ПарольЛиста);
При записи макроса в Excel действия пользователя транслируются через объект выделения. В некоторых версиях MS Office модель COM требует явной активации листа и фокуса на диапазоне для корректного применения стилей и защитных свойств. Рассмотрим обходной путь через вызов Select():
Лист = ЭксельКнига.Sheets(1);
Лист.Activate();
Лист.Range("A1:B5").Select();
Лист.Application.Selection.Locked = Ложь;
Вместо непосредственного изменения свойства Locked у каждой ячейки мы можем использовать штатный механизм диапазонов, разрешенных для редактирования. В объектной модели Excel за это отвечает коллекция AllowEditRanges. Это позволяет оставить ячейки заблокированными на системном уровне, но открыть доступ к их редактированию в рамках защищенного листа.
Посмотрим на пример добавления диапазона:
Лист = ЭксельКнига.Sheets(1);
Лист.Unprotect("ПарольЛиста");
// Добавляем диапазон в список разрешенных областей
Лист.Protection.AllowEditRanges.Add("РазрешеннаяОбласть", Лист.Range("A1:B5"));
Лист.Protect("ПарольЛиста");
Рассмотрим подробнее ограничения COM-технологии. Использование COMОбъект("Excel.Application") жестко привязывает решение к операционной системе Windows и установленному пакету Microsoft Office. Это решение не будет работать на серверах под управлением Linux, а также создает риск зависания процессов EXCEL.EXE при сбоях фоновых заданий.
Платформа 1С:Предприятие умеет напрямую работать с файлами формата XLSX через объект ТабличныйДокумент. Разберем кроссплатформенный вариант установки защиты и разблокировки ячеек без привлечения сторонних приложений:
ТабДок = Новый ТабличныйДокумент;
ТабДок.Прочитать(ПутьКФайлу);
// Снимаем защиту с нужного диапазона ячеек
ОбластьРедактирования = ТабДок.Область("R1C1:R5C2");
ОбластьРедактирования.Защита = Ложь;
// Включаем общую защиту табличного документа
ТабДок.Защита = Истина;
// Сохраняем результат обратно в формат Excel
ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.XLSX);
Такой подход обеспечивает высокую скорость обработки данных, исключает утечки памяти COM-процессов и гарантирует стабильную работу как в файловом, так и в клиент-серверном варианте на любой операционной системе.