При работе с системой 1С:Документооборот пользователи иногда сталкиваются с проблемой: при попытке предварительного просмотра или открытия файлов Excel система может намертво зависать. Выясним причину этого поведения и предложим несколько эффективных решений, включая программный обход и превентивные меры.
В начале обсуждения мы сталкиваемся с ситуацией, когда 1С:Документооборот (редакция 2.1) на платформе 8.3.10.2252 зависает при открытии задачи пользователя, если включен предварительный просмотр файла Excel. Изначально предполагалось, что проблема кроется в "проблемном" файле, который невозможно открыть. Однако дальнейшее расследование показало, что файл успешно открывается в Excel на некоторых компьютерах, что указывает на специфичность проблемы для определенного окружения или настроек.
Ключевой момент в понимании проблемы возникает, когда мы выясняем, что при открытии файла на компьютере пользователя, у которого происходит зависание, появляется диалоговое окно выбора принтера, а затем ошибки, связанные с печатью (например, "не хватает памяти", "не доступен принтер"). Это указывает на то, что проблема связана с настройками печати, встроенными непосредственно в файл Excel, и тем, как COM-объект Excel взаимодействует с этими настройками в текущей пользовательской среде.
Изначально использовался следующий фрагмент кода для предварительного просмотра файлов Excel путем их сохранения в HTML:
Если Файл.Расширение = ".xls" или Файл.Расширение = ".xlsx" Тогда
// Закомментированный код предполагает использование Excel.Application, но текущий использует ПолучитьComОбъект напрямую
//ФайлЭ = ПолучитьCOmОбъект("","Excel.Application");
//Лист = ФайлЭ.WorkBooks.Open(ПутьФайла);
//ВремФайл = ПолучитьИмяВременногоФайла(".html");
//Лист.saveAs(ВремФайл,44);
//ФайлЭ.Quit();
//ТекстВозврата = ВремФайл;
Книга = ПолучитьCOmОбъект(ПутьФайла);
ВремФайл = ПолучитьИмяВременногоФайла(".html");
Книга.saveAs(ВремФайл,44);
Книга.Close(0);
Книга = Неопределено;
ТекстВозврата = ВремФайл;
ИначеЕсли Файл.Расширение = ".doc" или Файл.Расширение = ".docx" или Файл.Расширение = ".rtf" Тогда
// ... (код для других форматов)
КонецЕсли;
Обратим внимание на строку Книга = ПолучитьCOmОбъект(ПутьФайла);. В данном случае 1С пытается напрямую открыть файл с помощью COM-объекта, который может не предоставлять полного контроля над приложением Excel (Excel.Application), его свойствами и событиями. Это не позволяет нам программно подавить диалоговые окна или изменить настройки перед открытием файла, что приводит к зависаниям при возникновении проблемы с принтером.
Разберем подробнее, почему возникают диалоги выбора принтера и ошибки при открытии файлов Excel через COM-автоматизацию:
Основываясь на найденном в ходе обсуждения решении, мы предлагаем следующий алгоритм для предотвращения зависаний при предварительном просмотре файлов Excel. Суть заключается во временной смене принтера по умолчанию на "безопасный" (например, Microsoft OneNote Printer) перед открытием файла, а затем возвращении исходного принтера.
Excel.Application, чтобы получить полный контроль над процессом.Рассмотрим пример кода 1С, реализующий этот алгоритм:
Функция ОткрытьExcelФайлДляПредпросмотра(ПутьКФайлу, РасширениеФайла) Экспорт
Перем ТекстВозврата;
ТекущийПринтер = "";
НовыйПринтерДляОткрытия = "Microsoft OneNote Driver"; // Или "Microsoft Print to PDF"
ПринтерИзменен = Ложь;
Попытка
// 1. Получаем текущий принтер по умолчанию
Попытка
Locator = Новый COMОбъект("WbemScripting.SWbemLocator");
ServicesSet = Locator.ConnectServer(".");
ObjectSet = ServicesSet.InstancesOf("Win32_Printer");
Для Каждого Item Из ObjectSet Цикл
Если Item.Default Тогда
ТекущийПринтер = Item.Caption;
Прервать;
КонецЕсли;
КонецЦикла;
Исключение
Сообщить("Не удалось определить текущий принтер по умолчанию: " + ОписаниеОшибки(), СтатусСообщения.Важное);
КонецПопытки;
// 2. Устанавливаем "безопасный" принтер (например, OneNote) как принтер по умолчанию
Если Не ПустаяСтрока(ТекущийПринтер) Тогда
Попытка
Для Каждого Item Из ObjectSet Цикл
Если Item.Caption = НовыйПринтерДляОткрытия Тогда
Item.SetDefaultPrinter();
ПринтерИзменен = Истина;
Прервать;
КонецЕсли;
КонецЦидо
Исключение
Сообщить("Не удалось установить принтер """ + НовыйПринтерДляОткрытия + """ по умолчанию: " + ОписаниеОшибки(), СтатусСообщения.Важное);
// Продолжаем без смены принтера, если не удалось
КонецПопытки;
КонецЕсли;
// 3. Работаем с Excel через COM-объект
Если РасширениеФайла = ".xls" Или РасширениеФайла = ".xlsx" Тогда
ExcelApp = Новый COMОбъект("Excel.Application");
ExcelApp.DisplayAlerts = 0; // Отключаем отображение предупреждений
ExcelApp.Visible = 0; // Делаем Excel невидимым
ExcelApp.ScreenUpdating = 0; // Отключаем обновление экрана для скорости
Книга = ExcelApp.Workbooks.Open(ПутьКФайлу);
// Установка режима просмотра в Обычный (xlNormalView)
// Хотя в обсуждении это не решило проблему с принтером, это хорошая практика
Попытка
Если Книга.Windows.Count > 0 Тогда
Книга.Windows(1).View = -4143; // xlNormalView
КонецЕсли;
Исключение
Сообщить("Не удалось установить режим просмотра: " + ОписаниеОшибки(), СтатусСообщения.Информация);
КонецПопытки;
ВремФайл = ПолучитьИмяВременногоФайла(".html");
Книга.SaveAs(ВремФайл, 44); // 44 - формат xlHtml
Книга.Close(0); // Закрываем книгу без сохранения изменений
ExcelApp.Quit(); // Закрываем приложение Excel
ExcelApp = Неопределено;
Книга = Неопределено;
ТекстВозврата = ВремФайл;
ИначеЕсли РасширениеФайла = ".doc" Или РасширениеФайла = ".docx" Или РасширениеФайла = ".rtf" Тогда
// ... (аналогичный код для Word, если требуется предпросмотр)
Сообщить("Обработка файлов Word пока не реализована.");
Возврат Неопределено;
Иначе
Сообщить("Формат файла не поддерживается для предпросмотра.");
Возврат Неопределено;
КонецЕсли;
Исключение
Сообщить("Ошибка при открытии файла Excel для предпросмотра: " + ОписаниеОшибки(), СтатусСообщения.Важное);
Если ЗначениеЗаполнено(ExcelApp) Тогда
Попытка
ExcelApp.Quit();
Исключение
// Игнорируем ошибку при закрытии
КонецПопытки;
ExcelApp = Неопределено;
КонецЕсли;
ТекстВозврата = Неопределено; // Возвращаем Неопределено, чтобы обозначить ошибку
КонецПопытки;
// 4. Восстанавливаем исходный принтер по умолчанию
Если ПринтерИзменен И Не ПустаяСтрока(ТекущийПринтер) Тогда
Попытка
ObjectSet = ServicesSet.InstancesOf("Win32_Printer");
Для Каждого Item Из ObjectSet Цикл
Если Item.Caption = ТекущийПринтер Тогда
Item.SetDefaultPrinter();
Прервать;
КонецЕсли;
КонецЦикла;
Исключение
Сообщить("Не удалось восстановить исходный принтер по умолчанию: " + ОписаниеОшибки(), СтатусСообщения.Важное);
КонецПопытки;
КонецЕсли;
Возврат ТекстВозврата;
КонецФункции
Этот код демонстрирует полный цикл работы: от сохранения текущих настроек до их восстановления. Использование блока Попытка...Исключение является критически важным для стабильной работы и корректного закрытия COM-объектов даже в случае возникновения ошибок.
Помимо прямого программного обхода, мы можем предпринять действия для предотвращения подобных проблем на этапе подготовки файлов или оптимизации среды:
Часто проблема кроется в метаданных файла, которые включают в себя информацию о принтере. Перед загрузкой файлов в 1С:Документооборот рекомендуем использовать встроенный в Excel "Инспектор документов" (Document Inspector). Он позволяет найти и удалить скрытые данные и персональную информацию, включая свойства документа (например, имя автора), комментарии, скрытые строки/столбцы, а также параметры, связанные с принтером.
Важно: Проводите эту операцию на копии файла, так как некоторые данные могут быть безвозвратно удалены.
При программной работе с Excel через COM-объекты мы можем дополнительно повысить стабильность и производительность:
ExcelApp.DisplayAlerts = 0 (отключить отображение предупреждений) и ExcelApp.Visible = 0 (сделать окно Excel невидимым). Это предотвращает появление интерактивных диалогов, которые могут блокировать выполнение кода.ExcelApp.ScreenUpdating = 0 для ускорения операций, так как Excel не будет перерисовывать экран при каждой операции.ExcelApp.EnableEvents = 0.Попытка...Исключение для корректного перехвата ошибок и освобождения COM-объектов.В серверном режиме или при работе с фоновыми заданиями 1С, учетная запись, под которой запущен сервер 1С (например, USR1CV8), должна обладать достаточными правами для запуска и взаимодействия с COM-объектом Microsoft Excel Application. Иногда требуется предоставление прав на папки C:\Windows\SysWOW64\config\systemprofile\Desktop и C:\Windows\System32\config\systemprofile\Desktop, так как некоторые COM-объекты используют их для временных файлов.
Устаревшие версии Microsoft Office или платформы 1С могут иметь известные ошибки совместимости или производительности при работе с COM-автоматизацией. Регулярное обновление до последних версий может решить многие проблемы.
Для простых файлов, которые не требуют сложной обработки или выполнения макросов, мы можем рассмотреть использование более "нативных" для 1С механизмов:
Проблема зависания 1С:Документооборот при предварительном просмотре файлов Excel, вызывающих диалог выбора принтера, является распространённой и связана с особенностями взаимодействия COM-объекта Excel с системными настройками печати. Применяя предложенный алгоритм временной смены принтера по умолчанию и используя превентивные меры по очистке файлов, мы сможем добиться стабильной работы системы и предотвратить подобные инциденты. Помните о важности обработки исключений и корректного освобождения COM-объектов для обеспечения надежности ваших решений.