Как программно изменить свойство 'Только для чтения' у COM-объекта Excel для файлов на SharePoint в 1С?

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

При работе с файлами Excel, расположенными на сервере Microsoft SharePoint, через COM-объект из платформы 1С, часто возникает ситуация, когда книга открывается в режиме "Только для чтения", даже если у пользователя есть полные права на редактирование. Это может значительно затруднить или сделать невозможным автоматическое заполнение и сохранение данных в таких файлах. Давайте разберем эту проблему и найдем эффективные решения.

Анализируем исходную проблему: почему Excel открывается в режиме 'Только для чтения' из SharePoint?

Когда мы открываем файл Excel с сервера SharePoint стандартным клиентским приложением Excel, мы часто видим информационное сообщение: "Мы открыли эту книгу с сервера в режиме только для чтения". Рядом с ним обычно располагается кнопка "Редактировать книгу". При нажатии на эту кнопку происходит дополнительная проверка прав доступа к каталогу на SharePoint, и если у пользователя есть необходимые права, книга переводится в режим редактирования.

Ситуация усложняется, когда мы пытаемся автоматизировать этот процесс из 1С с использованием COM-объектов Excel. При открытии файла по его сетевому пути (например, \\portal\Shared Documents\ExcelFile.xlsx или http://portal/Shared Documents/ExcelFile.xlsx) свойство ReadOnly COM-объекта книги оказывается установленным в значение Истина, даже если вручную файл можно отредактировать.

Важным наблюдением является то, что если мы просто скопируем тот же файл на рабочий стол или в другую локальную папку, то он открывается и редактируется без каких-либо проблем, и сообщение о режиме "Только для чтения" не появляется. Это указывает на то, что проблема связана не с самим файлом, а с механизмом взаимодействия Excel с SharePoint.

Причина такого поведения кроется в особенностях взаимодействия Excel, особенно версий 2010 и выше, с серверами SharePoint, которые управляют версиями документов и совместным доступом. SharePoint использует протокол WebDAV для взаимодействия с клиентскими приложениями, и Microsoft Office может задействовать локальный кэш документов Office. Это приводит к тому, что по умолчанию файл может быть открыт в режиме "Только для чтения", пока система явно не подтвердит готовность к редактированию и не заблокирует файл на сервере.

Рассматриваем начальные попытки решения и их ограничения

На первом этапе обычно предпринимаются несколько очевидных попыток решить проблему, которые, к сожалению, не приводят к желаемому результату:

Попытка 1: Использование параметра ReadOnly=False при открытии книги

Мы можем попытаться передать третий параметр ReadOnly=False при вызове метода Excel.WorkBooks.Open(), предполагая, что это сразу откроет книгу в режиме редактирования. В 1С, поскольку именованные параметры не поддерживаются для COM-объектов напрямую, это будет выглядеть как передача логического значения Ложь на третью позицию:


ПутьКФайлу = "\\portal\Shared Documents\ExcelFile.xlsx";
Excel = СоздатьCOMОбъектExcel();
Книга = Excel.WorkBooks.Open(ПутьКФайлу,,False); // Третий параметр False для ReadOnly

К сожалению, этот подход не срабатывает. После выполнения этого кода свойство Книга.ReadOnly все равно остается равным Истина. Это подтверждает, что Excel игнорирует этот параметр для файлов SharePoint, ожидая явного подтверждения намерений редактировать файл.

Попытка 2: Использование метода Книга.ChangeFileAccess(2)

Следующей логичной попыткой может быть использование метода Книга.ChangeFileAccess(). Этот метод позволяет программно изменить режим доступа к файлу. Параметр 2 соответствует режиму "Чтение и запись" (xlReadWrite), а 4 — "Только для чтения" (xlReadOnly). Мы можем попробовать вызвать его так:


// ... код открытия книги ...
Книга.ChangeFileAccess(2); // Попытка перевести книгу в режим чтения и записи

Однако, как было замечено, после вызова Книга.ChangeFileAccess(2) COM-объект Книга может потеряться и принять значение Неопределено. Это происходит потому, что, согласно документации Microsoft, "если вы измените файл с 'только для чтения' на 'чтение и запись', Microsoft Excel должен загрузить новую копию файла, чтобы убедиться, что при открытии файла в режиме 'только для чтения' не было внесено никаких изменений". Такая перезагрузка файла приводит к тому, что текущий COM-объект становится недействительным, и связь с ним теряется. Теоретически, после этого нужно было бы снова получить объект книги из коллекции Excel.WorkBooks, но это создает дополнительные сложности и не является прямым решением проблемы.

Основное решение: использование метода Книга.LockServerFile()

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

Выясняем причину: различия в поведении MS Excel до 2010 и после 2010 года

Ключевым моментом является различие в поведении версий Microsoft Excel:

  1. В MS Excel до 2010 года: При создании COM-объекта файла проверка прав на редактирование выполнялась практически мгновенно. Это означало, что после получения COM-объекта книги, свойство ReadOnly уже корректно отражало фактические права пользователя на сервере SharePoint.

  2. В MS Excel после 2010 года (включая 2010, 2013, 2016, 2019, Office 365): Поведение изменилось. При создании COM-объекта файла, особенно если он расположен на SharePoint, значение свойства ReadOnly по умолчанию постоянно установлено в True, вне зависимости от того, есть у пользователя права на редактирование или нет. Чтобы Excel проверил и подтвердил права на редактирование, требуется явное действие.

Представляем метод Книга.LockServerFile()

Для версий Excel 2010 и новее, для проверки прав и перевода файла в режим редактирования при работе с SharePoint, необходимо использовать метод Книга.LockServerFile().

Метод LockServerFile() предназначен специально для взаимодействия с серверами, поддерживающими протоколы совместной работы, такими как SharePoint. Его основное назначение:

После успешного вызова метода Книга.LockServerFile() и при наличии достаточных прав у пользователя, свойство Книга.ReadOnly объекта Workbook должно быть обновлено до значения Ложь. Это означает, что файл теперь находится в режиме редактирования, и мы можем вносить изменения и сохранять их.

Пример кода с использованием LockServerFile()

Рассмотрим, как интегрировать этот метод в наш код 1С для программного редактирования файла Excel на SharePoint:


Перем Excel, Книга; // Объявляем переменные на уровне модуля или процедуры для корректного освобождения

Попытка
    ПутьКФайлу = "\\portal\Shared Documents\ExcelFile.xlsx"; // Используем SMB-путь, если он настроен для портала
    // Также можно использовать HTTP-путь: "http://portal/Shared Documents/ExcelFile.xlsx"

    Excel = Новый COMОбъект("Excel.Application"); // Создаем приложение Excel
    Excel.Visible = Истина; // Или Ложь, если не нужен видимый интерфейс
    Excel.DisplayAlerts = Ложь; // Отключаем всплывающие окна

    // Открываем книгу. Для новых версий Excel она, скорее всего, откроется как ReadOnly.
    // Третий параметр False указывает на желание открыть для записи, но SharePoint может это игнорировать по умолчанию.
    Книга = Excel.Workbooks.Open(ПутьКФайлу,,False); 

    Сообщить("Файл открыт. Текущее состояние ReadOnly: " + Книга.ReadOnly);

    // Этот блок кода критически важен для Excel 2010 и новее при работе с SharePoint
    // Мы пытаемся вызвать LockServerFile()
    Попытка
        // Метод LockServerFile() пытается заблокировать файл на сервере для редактирования.
        // Если он успешен, Книга.ReadOnly изменится на Ложь.
        Книга.LockServerFile();
        Сообщить("Метод LockServerFile() успешно вызван.");

        Если Не Книга.ReadOnly Тогда
            Сообщить("Файл успешно переведен в режим редактирования.");
            // Теперь мы можем безопасно вносить изменения
            Книга.Sheets(1).Cells(1, 1).Value = "Данные из 1С (" + ТекущаяДата() + ")";
            Книга.Sheets(1).Cells(2, 1).Value = "Строка 2";
            Книга.Save(); // Сохраняем изменения
            Сообщить("Изменения сохранены в файл на SharePoint.");
        Иначе
            Сообщить("Не удалось перевести файл в режим редактирования после вызова LockServerFile(). Проверьте права доступа пользователя на SharePoint.");
        КонецЕсли;

    Исключение
        // Здесь мы обрабатываем ситуации, когда LockServerFile() не сработал или вызвал ошибку.
        // Это может произойти, если метод не поддерживается (например, очень старая версия Excel),
        // или если сервер SharePoint отклонил запрос на блокировку.
        Сообщить("Ошибка при вызове Книга.LockServerFile(): " + ОписаниеОшибки());
        Сообщить("Возможно, вы используете версию Excel до 2010 года, где LockServerFile() не требуется или не поддерживается,");
        Сообщить("или существуют проблемы с доступом/блокировкой на SharePoint.");
        
        // Для старых версий Excel (до 2010), если LockServerFile() не нужен/недоступен,
        // свойство ReadOnly должно было бы быть корректным сразу после Open().
        Если Книга.ReadOnly Тогда
            Сообщить("Файл все еще в режиме 'только для чтения'. Проверьте права пользователя на SharePoint или версию Excel.");
        Иначе
            Сообщить("Файл открыт для редактирования (для Excel до 2010?). Изменения будут сохранены.");
            // Здесь можно выполнять изменения
            Книга.Sheets(1).Cells(1, 1).Value = "Данные из 1С (старый Excel)";
            Книга.Save();
            Сообщить("Изменения сохранены.");
        КонецЕсли;
    КонецПопытки;

Исключение
    Сообщить("Произошла общая ошибка при работе с Excel: " + ОписаниеОшибки());
КонецПопытки;

// Важно: всегда освобождайте COM-объекты в конце, независимо от того, были ли ошибки.
// Используем отдельные блоки Попытка для освобождения, чтобы избежать прерывания очистки
// в случае ошибки при закрытии одной из книг или приложения.
Попытка
    Если Книга <> Неопределено Тогда
        Книга.Close(False); // Закрываем книгу. False - не сохранять изменения, если они не были сохранены ранее
        ReleaseCOMObject(Книга);
    КонецЕсли;
Исключение
    Сообщить("Ошибка при закрытии книги или освобождении COM-объекта Книга: " + ОписаниеОшибки());
КонецПопытки;

Попытка
    Если Excel <> Неопределено Тогда
        Excel.Quit(); // Закрываем приложение Excel
        ReleaseCOMObject(Excel);
    КонецЕсли;
Исключение
    Сообщить("Ошибка при закрытии приложения Excel или освобождении COM-объекта Excel: " + ОписаниеОшибки());
КонецПопытки;

Важный нюанс: как было упомянуто, метод LockServerFile() не нужен, если вы работаете с файлами в MS Excel версии до 2010 года. В таких случаях свойство ReadOnly должно корректно отражать права доступа сразу после открытия книги.

Альтернативные подходы и лучшие практики для работы с файлами SharePoint

Помимо использования LockServerFile(), существуют и другие стратегии для работы с файлами Excel на SharePoint, которые могут быть полезны в зависимости от конкретных требований и настроек среды.

1. Копирование файла на локальный диск, редактирование и загрузка обратно

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

  1. Скачивание файла: Скопируйте файл с SharePoint на временный локальный диск. Это можно сделать, используя файловые операции 1С (если SharePoint доступен как сетевой ресурс по SMB-протоколу, например, \\portal\...) или используя HTTP-запросы для загрузки файла по WebDAV-протоколу SharePoint (например, http://portal/...).

  2. Редактирование локальной копии: Откройте локальную копию файла Excel через COM-объект. Эта копия не будет иметь ограничений "Только для чтения", связанных с SharePoint, и вы сможете вносить все необходимые изменения.

  3. Сохранение и закрытие: Сохраните изменения в локальном файле и закройте COM-объекты Excel.

  4. Загрузка обратно: Загрузите измененную локальную копию обратно на SharePoint, заменив исходный файл. Это также может быть выполнено с помощью файловых операций (если SMB-доступ для записи) или HTTP PUT-запросом.

Давайте посмотрим на пример такого подхода:


Перем Excel, Книга;

Попытка
    ПутьКФайлуНаSharePointSMB = "\\portal\Shared Documents\ExcelFile.xlsx"; // SMB-путь для SharePoint
    // Если SMB недоступен для копирования, придется использовать HTTPЗапрос для скачивания/загрузки.
    // Пример HTTP-пути: ПутьКФайлуНаSharePointHTTP = "http://portal/Shared Documents/ExcelFile.xlsx";

    ПутьЛокальный = ПолучитьКаталогВременныхФайлов() + "ExcelFile_Local_" + Строка(Новый УникальныйИдентификатор()) + ".xlsx";

    // Шаг 1: Скачиваем файл с SharePoint на локальный диск
    Попытка
        КопироватьФайл(ПутьКФайлуНаSharePointSMB, ПутьЛокальный);
        Сообщить("Файл успешно скопирован на локальный диск: " + ПутьЛокальный);
    Исключение
        Сообщить("Ошибка при копировании файла с SharePoint на локальный диск: " + ОписаниеОшибки());
        Возврат;
    КонецПопытки;

    Excel = Новый COMОбъект("Excel.Application");
    Excel.Visible = Истина;
    Excel.DisplayAlerts = Ложь;

    // Шаг 2: Открываем и редактируем локальную копию
    Книга = Excel.Workbooks.Open(ПутьЛокальный);
    Сообщить("Локальный файл открыт. ReadOnly: " + Книга.ReadOnly); // Должно быть Ложь

    // Производим необходимые изменения
    Книга.Sheets(1).Cells(1, 1).Value = "Данные из 1С, отредактированные локально (" + Формат(ТекущаяДата(), "ДФ=дд.ММ.гггг ЧЧ:мм:сс") + ")";
    Книга.Sheets(1).Cells(2, 1).Value = "Вторая строка данных";

    // Шаг 3: Сохраняем изменения в локальном файле
    Книга.Save();
    Сообщить("Изменения сохранены в локальный файл.");

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

// Обязательно освобождаем COM-объекты после локального редактирования
Попытка
    Если Книга <> Неопределено Тогда
        Книга.Close(False); 
        ReleaseCOMObject(Книга);
    КонецЕсли;
    Если Excel <> Неопределено Тогда
        Excel.Quit();
        ReleaseCOMObject(Excel);
    КонецЕсли;
Исключение
    Сообщить("Ошибка при освобождении COM-объектов Excel: " + ОписаниеОшибки());
КонецПопытки;

// Шаг 4: Загружаем измененный файл обратно на SharePoint
Попытка
    КопироватьФайл(ПутьЛокальный, ПутьКФайлуНаSharePointSMB); // Перезаписываем файл на SharePoint
    Сообщить("Измененный файл успешно записан обратно на SharePoint.");
Исключение
    Сообщить("Ошибка при записи файла на SharePoint: " + ОписаниеОшибки());
КонецПопытки;

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

Важно: для полноценного взаимодействия с SharePoint по HTTP (если SMB-доступ не настроен или нежелателен), потребуется использовать объект HTTPСоединение и HTTPЗапрос для скачивания (GET-метод) и загрузки (PUT-метод) файлов. Эти операции более сложны и требуют понимания авторизации и специфики WebDAV-протокола SharePoint.

2. Использование методов CheckOut() и CheckIn() для SharePoint

Для файлов, хранящихся в библиотеках документов SharePoint, где включена функция "Извлечение" (Check Out), рекомендуется использовать методы CheckOut() и CheckIn() COM-объекта книги. Это явно сообщает SharePoint о намерении пользователя редактировать файл и контролирует версии:

  1. CheckOut(): Перед редактированием файла вызовите метод Книга.CheckOut(). Это заблокирует файл для эксклюзивного редактирования вами и создаст новую версию для работы.

  2. Редактирование: Внесите необходимые изменения в файл.

  3. CheckIn(): После завершения редактирования вызовите метод Книга.CheckIn(). Это сохранит изменения, обновит версию файла на SharePoint и сделает его доступным для других пользователей. Можно добавить комментарий к версии.

  4. UndoCheckOut(): Если по каким-то причинам изменения не должны быть сохранены, или произошла ошибка, можно отменить извлечение с помощью Книга.UndoCheckOut(). Это откатит все изменения, сделанные после CheckOut(), и вернет файл в предыдущее состояние.

Давайте рассмотрим концептуальный пример:


Перем Excel, Книга;

Попытка
    ПутьКФайлу = "\\portal\Shared Documents\ExcelFile.xlsx";
    Excel = Новый COMОбъект("Excel.Application");
    Excel.Visible = Истина;
    Excel.DisplayAlerts = Ложь;
    Книга = Excel.Workbooks.Open(ПутьКФайлу,,False);

    Сообщить("Файл открыт. Текущее состояние ReadOnly: " + Книга.ReadOnly);

    // Проверяем, поддерживает ли книга CheckOut (доступно ли для библиотеки SharePoint)
    Если Книга.CanCheckOut Тогда
        Попытка
            Книга.CheckOut(); // Извлекаем файл
            Сообщить("Файл успешно извлечен (CheckOut) из SharePoint.");

            // Теперь файл гарантированно доступен для редактирования
            Книга.Sheets(1).Cells(1, 1).Value = "Данные из 1С (через CheckOut) " + Формат(ТекущаяДата(), "ДФ=дд.ММ.гггг ЧЧ:мм:сс");
            Книга.Save(); // Сохраняем изменения

            // Возвращаем файл обратно, True означает, что сохраняем изменения
            Книга.CheckIn(True, "Изменения внесены из 1С по заданию."); 
            Сообщить("Файл успешно возвращен (CheckIn) в SharePoint.");

        Исключение
            Сообщить("Ошибка при работе с CheckOut/CheckIn: " + ОписаниеОшибки());
            // Если произошла ошибка до CheckIn, отменяем извлечение
            Попытка
                Книга.UndoCheckOut();
                Сообщить("Извлечение отменено (UndoCheckOut).");
            Исключение
                // Игнорируем ошибки, если файл и так не был извлечен или не удалось отменить
            КонецИсключения;
        КонецПопытки;
    Иначе
        Сообщить("Функция 'Извлечение/Возвращение' (CheckOut/CheckIn) не включена для данной библиотеки SharePoint или не применима к файлу.");
        // В этом случае можно попробовать метод LockServerFile() как альтернативу,
        // или использовать подход с копированием локально.
        Сообщить("Попробуем использовать LockServerFile() как альтернативу.");
        // ... Далее код с LockServerFile(), как описано выше ...
        Попытка
            Книга.LockServerFile();
            Если Не Книга.ReadOnly Тогда
                Сообщить("Файл переведен в режим редактирования через LockServerFile().");
                Книга.Sheets(1).Cells(1, 1).Value = "Данные из 1С (через LockServerFile) " + Формат(ТекущаяДата(), "ДФ=дд.ММ.гггг ЧЧ:мм:сс");
                Книга.Save();
            Иначе
                Сообщить("Не удалось перевести файл в режим редактирования через LockServerFile().");
            КонецЕсли;
        Исключение
            Сообщить("Ошибка при использовании LockServerFile() в альтернативном сценарии: " + ОписаниеОшибки());
        КонецИсключения;
    КонецЕсли;

Исключение
    Сообщить("Произошла общая ошибка при работе с Excel и SharePoint: " + ОписаниеОшибки());
КонецПопытки;

Попытка
    Если Книга <> Неопределено Тогда Книга.Close(False); ReleaseCOMObject(Книга); КонецЕсли;
    Если Excel <> Неопределено Тогда Excel.Quit(); ReleaseCOMObject(Excel); КонецЕсли;
Исключение
    Сообщить("Ошибка при освобождении COM-объектов: " + ОписаниеОшибки());
КонецПопытки;

3. Протокол WebDAV и кэш документов Office

Понимание того, как SharePoint использует протокол WebDAV для взаимодействия с клиентскими приложениями, может помочь в диагностике проблем. Иногда проблемы с режимом "Только для чтения" связаны с особенностями настройки WebDAV на сервере SharePoint или на клиентской машине. Также, как было упомянуто, Microsoft Office активно использует кэш документов Office на локальном диске пользователя. Это означает, что даже если вы программно изменили файл, эти изменения могут сначала сохраниться в локальный кэш, а затем асинхронно синхронизироваться с сервером SharePoint. Если синхронизация по какой-то причине не происходит, может возникнуть ощущение, что изменения не были сохранены.

Общие рекомендации и важные моменты при работе с COM-объектами Excel и SharePoint

Для обеспечения стабильной и безотказной работы с COM-объектами Excel и файлами на SharePoint, рекомендуем придерживаться следующих лучших практик:

  1. Обработка ошибок: Всегда используйте блоки Попытка...Исключение...КонецПопытки для обертывания операций с COM-объектами. Это позволит корректно реагировать на непредвиденные ситуации (например, отсутствие файла, проблемы с доступом, ошибки в Excel) и предотвратить аварийное завершение скрипта 1С. Важно не просто перехватывать ошибки, но и информировать пользователя или записывать информацию в журнал.

  2. Освобождение COM-объектов: Это критически важный шаг. После завершения работы с COM-объектами Excel (книги, приложение Excel), необходимо корректно освобождать их ресурсы. Неосвобожденные объекты могут приводить к утечкам памяти, зависанию процессов Excel в фоновом режиме, что, в свою очередь, может блокировать доступ к файлам для других пользователей или приложений. В 1С для этого используется функция ReleaseCOMObject().

    
    // Пример корректного освобождения COM-объектов
    Попытка
        Если Книга <> Неопределено Тогда
            // Книга.Close(False); // Закрываем книгу. False - не сохранять изменения, если они не были сохранены ранее
                                 // Если Save() был вызван, можно закрывать без сохранения.
            ReleaseCOMObject(Книга);
        КонецЕсли;
    Исключение
        Сообщить("Ошибка при освобождении COM-объекта Книга: " + ОписаниеОшибки());
    КонецПопытки;
    
    Попытка
        Если Excel <> Неопределено Тогда
            Excel.Quit(); // Закрываем приложение Excel
            ReleaseCOMObject(Excel);
        КонецЕсли;
    Исключение
        Сообщить("Ошибка при освобождении COM-объекта Excel: " + ОписаниеОшибки());
    КонецПопытки;
    

    Используйте отдельные блоки Попытка для каждого ReleaseCOMObject, чтобы даже если один из объектов не смог быть освобожден, другие объекты все равно были очищены.

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

  4. Учет версий Excel и SharePoint: Помните, что поведение и доступные методы могут отличаться в зависимости от конкретных версий Microsoft Excel и SharePoint (локальный SharePoint Server или SharePoint Online). При возникновении проблем всегда уточняйте версии используемого ПО.

Таким образом, для успешной программной работы с файлами Excel на SharePoint из 1С, особенно с современными версиями Excel, ключевым является понимание специфики взаимодействия этих систем. Метод Книга.LockServerFile() в большинстве случаев окажется тем самым "волшебным ключом", который позволит перевести файл из режима "Только для чтения" в режим редактирования.

← На главную