При формировании отчетов и печатных форм в 1С:Предприятии 7.7 разработчики часто сталкиваются с задачей сохранить документ в формате PDF или Excel так, чтобы таблица гарантированно умещалась на одной странице по ширине. Попытки решить эту задачу через прямое управление объектом PageSetup в Excel по OLE или через MSScriptControl.ScriptControl нередко приводят к ошибке Разрешение отклонено: 'ExcelPS.Zoom' (Error 70 Permission Denied).
Разберем причины возникновения этой ошибки и подробно рассмотрим эффективные способы решения задачи: от встроенной выгрузки без использования MS Excel до корректного управления макросами Excel.
Проанализируем природу ошибки. Свойство Zoom объекта PageSetup в Microsoft Excel имеет двойственное поведение: оно принимает либо логическое значение False (чтобы активировать параметры FitToPagesWide и FitToPagesTall), либо целое число от 10 до 400 (масштаб в процентах).
В платформе 1С 7.7 отсутствует нативный тип VT_BOOL. При передаче значений 0 или 1 платформа отправляет их как числовой тип (VT_I4). Передача 0 напрямую воспринимается Excel как масштаб 0%, что вызывает исключение. При попытке обойти это через передачу объекта в MSScriptControl возникает ошибка отказа в доступе из-за ограничений безопасности скриптового движка при работе с дочерними интерфейсами COM.
Наиболее стабильным и быстрым решением является отказ от промежуточной автоматизации Excel и использование специализированной бесплатной библиотеки SpreadSheet.dll (Йоксель). Компонента позволяет нативно работать с табличными документами 1С 7.7, управлять параметрами печати и напрямую экспортировать документ в PDF с автоматическим масштабированием.
Рассмотрим по шагам реализацию функции экспорта с подгонкой по ширине:
Функция ПодготовитьФайл(КаталогДляЗаписи)
Ошибка = 0;
Форма.Отправка.Заголовок("Идет формирование файла...");
Попытка
ЗагрузитьВнешнююКомпоненту("SpreadSheet.dll");
Исключение
Предупреждение("Не удалось загрузить компоненту SpreadSheet.dll.");
Ошибка = 1;
Возврат Ошибка;
КонецПопытки;
Йоксель = СоздатьОбъект("ТабличныйДокумент");
Йоксель.ЗагрузитьИзТаблицы(АктивныйКонтекст);
Параметры = Йоксель.ПараметрыПечати;
Параметры.ПолеСверху = 10;
Параметры.ПолеСнизу = 10;
Параметры.ПолеСлева = 10;
Параметры.ПолеСправа = 10;
Параметры.АвтоМасштаб = 1;
Параметры.Ориентация = 1;
Конвертер = СоздатьОбъект("Йоксель.ГрафическийКонвертер.PDF");
// 1 - альбомная ориентация, 0 - портретная
Если (СтрОриентация = 1) Тогда
Конвертер.ВысотаСтраницы = 210 * 56.7;
Конвертер.ШиринаСтраницы = 297 * 56.7;
Иначе
Конвертер.ВысотаСтраницы = 297 * 56.7;
Конвертер.ШиринаСтраницы = 210 * 56.7;
КонецЕсли;
Конвертер.КоличествоБитНаПиксел = 24;
Конвертер.Документ = Йоксель;
Конвертер.ПолеСлева = 450;
Конвертер.ПолеСверху = 300;
Конвертер.ПолеСправа = 0;
Конвертер.ПолеСнизу = 300;
Конвертер.ЗаписатьВФайл(КаталогДляЗаписи);
Йоксель.Очистить();
Возврат Ошибка;
КонецФункции
Установка свойства Параметры.АвтоМасштаб = 1 обеспечивает автоматическую подгонку таблицы под границы страницы при конвертации.
Если специфика бизнес-процесса требует сохранения именно файла Excel или использования встроенного в MS Office конвертера ExportAsFixedFormat, следует обойти прямое обращение к свойству Zoom через объектную модель. Для этого используем внутренний механизм макросов Excel 4.0.
Разберем пример кода на платформе 1С 7.7:
ExcelApp = СоздатьОбъект("Excel.Application");
ExcelApp.Visible = 0;
ExcelApp.DisplayAlerts = 0;
Книга = ExcelApp.Workbooks.Open(ПутьКФайлу);
Лист = Книга.ActiveSheet;
// 13-й параметр функции PAGE.SETUP принимает массив {Ширина, Высота}
// Значение 1 для ширины и 10 для высоты обеспечит сжатие по ширине листа
ExcelApp.ExecuteExcel4Macro("PAGE.SETUP(,,,,,,,,,,,,{1,10})");
// Экспорт в PDF средствами MS Excel
Лист.ExportAsFixedFormat(0, ПутьКPDF, 0);
Книга.Close(0);
ExcelApp.Quit();
Функция PAGE.SETUP макроязыка Excel 4.0 позволяет избежать проблем с маршалингом типов данных (VT_BOOL) и применяется мгновенно, без задержек на многократный опрос драйвера принтера.
Если для логики обработки требуется использовать скриптовый движок VBScript или JScript, необходимо передавать в скрипт корневой объект приложения Excel.Application, а не отдельный вложенный интерфейс PageSetup.
Посмотрим на пример правильной инициализации:
ScrptCtrl = СоздатьОбъект("MSScriptControl.ScriptControl");
ScrptCtrl.Language = "VBScript";
ScrptCtrl.AddObject("ExcelApp", ExcelApp);
// Выполняем установку параметров через корневой объект
ScrptCtrl.ExecuteStatement("ExcelApp.ActiveSheet.PageSetup.Zoom = False : ExcelApp.ActiveSheet.PageSetup.FitToPagesWide = 1 : ExcelApp.ActiveSheet.PageSetup.FitToPagesTall = 10");
При настройке параметров страницы через COM-соединение следует учитывать следующие технические особенности:
PageSetup жестко привязан к драйверу печати. Если в операционной системе не установлен принтер по умолчанию или остановлена служба Spooler (Диспетчер очереди печати), любые вызовы свойств страницы завершатся фатальной ошибкой.Orientation, LeftMargin, FitToPagesWide) инициирует отдельный синхронный запрос к драйверу принтера. Использование метода ExecuteExcel4Macro выполняет все изменения за один вызов, ускоряя обработку в десятки раз.SpreadSheet.dll и MSScriptControl.ScriptControl являются 32-битными модулями и полностью совместимы с архитектурой 1С:Предприятия 7.7.