Как в 1С разрешить копирование данных из отчета, запретив при этом печать и сохранение

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

В практике разработки на платформе 1С (особенно в версиях 8.2 и 8.3 с использованием обычных форм) часто возникает задача тонкой настройки прав доступа. Одной из самых проблемных зон является право «Вывод». Платформа устроена таким образом, что это право регулирует сразу три действия: печать документа, сохранение его в файл (Excel, PDF и др.) и копирование данных в буфер обмена. Если мы отключаем это право, пользователь теряет возможность не только распечатать отчет, но и просто скопировать строку. Однако бизнесу часто требуется разрешить копирование (например, для переноса артикула в другую систему), жестко запретив при этом выгрузку всего отчета целиком. Разберем, как обойти это ограничение программными средствами.

Почему стандартное право «Вывод» нам не подходит

Проанализируем стандартное поведение платформы. Когда у пользователя в роли снята галочка «Вывод», для любого объекта типа ТабличныйДокумент блокируются методы Записать(), Напечатать(), а также системное сочетание клавиш Ctrl+C. Попытка программного вызова записи в файл приведет к ошибке нарушения прав доступа. Наша задача — создать альтернативный механизм копирования, который будет считывать данные из ячеек напрямую из оперативной памяти и передавать их в системный буфер Windows, минуя стандартный механизм «Вывода» 1С.

Шаг 1. Перехват выделенной области табличного документа

Первым делом нам необходимо понять, что именно пользователь выделил в отчете. В обычном приложении у элемента формы «Поле табличного документа» есть свойство ВыделенныеОбласти. Это коллекция, которая содержит одну или несколько областей, выбранных пользователем.

Рассмотрим алгоритм обхода этих областей. Нам нужно собрать значения всех ячеек в одну текстовую строку, сохраняя структуру таблицы (чтобы при вставке в Excel данные распределились по ячейкам, а не слиплись в одну кучу). Для этого мы будем использовать символ табуляции в качестве разделителя колонок и символ перевода строки для разделения строк таблицы.

Разберем пример кода для сбора данных:


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

Шаг 2. Работа с буфером обмена через COM-объекты

После того как мы получили текстовую строку, нам нужно «заставить» операционную систему принять ее в буфер обмена. Поскольку встроенных средств прямой работы с буфером в 1С 8.2/8.3 нет (кроме платформенных механизмов, которые у нас заблокированы), мы воспользуемся внешними объектами Windows.

Наиболее стабильным и современным способом является использование объекта htmlfile. Этот метод не требует открытия видимых окон браузера и работает быстрее, чем эмуляция нажатия клавиш через SendKeys.

Рассмотрим реализацию помещения текста в буфер:


Процедура ПоместитьТекстВБуферОбмена(Текст)
    Попытка
        ОбъектHTML = Новый COMОбъект("htmlfile");
        ОбъектHTML.ParentWindow.ClipboardData.SetData("Text", Текст);
    Исключение
        Сообщить("Не удалось получить доступ к буферу обмена: " + ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

Проанализируем, почему это работает. Объект htmlfile — это часть движка Internet Explorer, которая доступна в любой системе Windows. Метод SetData работает напрямую с API операционной системы. Для 1С это выглядит как обычное использование COM-объекта, и система прав 1С не отслеживает, что данные уходят именно в буфер обмена.

Шаг 3. Создание пользовательского интерфейса

Теперь нам нужно дать пользователю возможность вызвать этот код. Так как Ctrl+C заблокирован на уровне платформы, нам нужно создать свою кнопку или пункт меню. Посмотрим на два способа реализации.

Способ А: Командная панель

Добавим в командную панель формы кнопку «Копировать данные». В действии этой кнопки пропишем вызов наших процедур:


Процедура КоманднаяПанельКопировать(Кнопка)
    ТекстДляКопирования = ПолучитьТекстИзВыделенныхОбластей(ЭлементыФормы.ПолеТабличногоДокумента);
    Если ЗначениеЗаполнено(ТекстДляКопирования) Тогда
        ПоместитьТекстВБуферОбмена(ТекстДляКопирования);
    КонецЕсли;
КонецПроцедуры

Способ Б: Подмена контекстного меню

Это более изящный метод. В свойствах элемента ПолеТабличногоДокумента отключим свойство «Автоматическое контекстное меню». Затем создадим свое собственное контекстное меню, где будет только один пункт — «Копировать выделенное». Таким образом, пользователь даже не увидит кнопок «Печать» или «Сохранить как», которые обычно присутствуют в стандартном меню 1С.

Нюансы работы в терминальном режиме (RDP)

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

Альтернативный метод через WScript.Shell

Если по каким-то причинам объект htmlfile недоступен, можно использовать старый проверенный метод через WScript.Shell. Он менее надежен, так как имитирует нажатие клавиш и чувствителен к раскладке клавиатуры и фокусу окна, но его полезно знать как запасной вариант.


Процедура КопироватьЧерезSendKeys()
    WshShell = Новый COMОбъект("WScript.Shell");
    // Имитация Ctrl+C. 
    // Внимание: метод может не сработать при запрещенном праве "Вывод"
    WshShell.SendKeys("^c"); 
КонецПроцедуры

Важно понимать, что SendKeys просто посылает сигнал нажатия клавиш. Если право «Вывод» у пользователя отозвано, платформа 1С проигнорирует этот сигнал точно так же, как и физическое нажатие кнопок на клавиатуре. Поэтому метод с прямым перебором ячеек (Шаг 1) и использованием htmlfile (Шаг 2) является единственным гарантированным решением.

Заключение и рекомендации

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

  1. Безопасность: Мы не нарушаем общую логику прав доступа, а лишь точечно разрешаем извлечение текстовых данных. Метод ТабличныйДокумент.Записать() по-прежнему будет выдавать ошибку, что защищает от массовой выгрузки данных в файлы.
  2. Форматирование: Использование Символы.Таб позволяет сохранять табличную структуру при вставке в сторонние редакторы.
  3. Ограничения: Данный метод копирует только текст. Картинки, диаграммы или сложное оформление ячеек (цвета, рамки) через простой буфер текста передать не получится. Для передачи оформления потребовалось бы формирование HTML-кода и помещение его в буфер в формате CF_HTML, что значительно сложнее в реализации.

Таким образом, комбинируя программный обход ячеек и возможности COM-объектов Windows, мы получаем гибкий инструмент, позволяющий удовлетворить специфические требования безопасности без потери удобства работы пользователей.

← На главную