Как предотвратить зависание 1С:Документооборот при предварительном просмотре файлов Excel, вызывающих диалог выбора принтера?

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

При работе с системой 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 через COM-автоматизацию:

  1. Сохраненные настройки печати в файле: Файлы Excel могут содержать специфические настройки принтера, которые были активны у пользователя, сохранившего документ. Например, размер страницы (А3, А4, нестандартный "портянка"), ориентация, параметры дуплекса, лоток для бумаги. Если текущий принтер пользователя, открывающего файл, не поддерживает эти настройки или не найден, Excel может инициировать диалог выбора принтера.
  2. Недоступность или несовместимость принтера: Если принтер, указанный в файле, недоступен в сети или его драйверы устарели/повреждены на клиентской машине, это также приводит к проблемам.
  3. Нехватка системных ресурсов: Ошибки "недостаточно памяти" могут быть следствием не только настроек печати, но и общих ограничений ресурсов системы, особенно при работе с большими или сложными файлами, большим количеством одновременно запущенных приложений, а также при использовании 32-битной версии Excel.
  4. Скрытые элементы файла: Файлы Excel могут содержать скрытые листы, строки, столбцы, объекты, макросы или условное форматирование, которые, хотя и не видны, могут влиять на производительность и вызывать ошибки при программном открытии.

Эффективное решение: программная смена принтера по умолчанию

Основываясь на найденном в ходе обсуждения решении, мы предлагаем следующий алгоритм для предотвращения зависаний при предварительном просмотре файлов Excel. Суть заключается во временной смене принтера по умолчанию на "безопасный" (например, Microsoft OneNote Printer) перед открытием файла, а затем возвращении исходного принтера.

  1. Сохраняем текущий принтер по умолчанию: Используем WMI (Windows Management Instrumentation) для получения информации о текущем принтере.
  2. Устанавливаем Microsoft OneNote Printer как принтер по умолчанию: Это позволяет избежать конфликтов с реальными принтерами, настройки которых могут быть причиной проблемы.
  3. Открываем файл Excel через COM-объект: Важно использовать явное создание объекта Excel.Application, чтобы получить полный контроль над процессом.
  4. Выполняем необходимую операцию: В нашем случае — сохраняем файл в формате HTML.
  5. Закрываем Excel и освобождаем COM-объекты.
  6. Восстанавливаем исходный принтер по умолчанию.

Рассмотрим пример кода 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. Использование Инспектора Документов (Document Inspector) в Excel

Часто проблема кроется в метаданных файла, которые включают в себя информацию о принтере. Перед загрузкой файлов в 1С:Документооборот рекомендуем использовать встроенный в Excel "Инспектор документов" (Document Inspector). Он позволяет найти и удалить скрытые данные и персональную информацию, включая свойства документа (например, имя автора), комментарии, скрытые строки/столбцы, а также параметры, связанные с принтером.

  1. Откройте проблемный файл в Excel.
  2. Перейдите в меню "Файл" (File) -> "Сведения" (Info).
  3. В разделе "Поиск проблем" (Check for Issues) выберите "Инспектор документов" (Inspect Document).
  4. В диалоговом окне выберите, какие элементы следует проверить (например, "Свойства документа и личные данные", "Настройки печати").
  5. Нажмите "Проверить" (Inspect).
  6. После проверки нажмите "Удалить все" (Remove All) рядом с найденными элементами, которые могут быть причиной проблемы.

Важно: Проводите эту операцию на копии файла, так как некоторые данные могут быть безвозвратно удалены.

2. Оптимизация COM-автоматизации Excel

При программной работе с Excel через COM-объекты мы можем дополнительно повысить стабильность и производительность:

3. Проверка прав доступа DCOM

В серверном режиме или при работе с фоновыми заданиями 1С, учетная запись, под которой запущен сервер 1С (например, USR1CV8), должна обладать достаточными правами для запуска и взаимодействия с COM-объектом Microsoft Excel Application. Иногда требуется предоставление прав на папки C:\Windows\SysWOW64\config\systemprofile\Desktop и C:\Windows\System32\config\systemprofile\Desktop, так как некоторые COM-объекты используют их для временных файлов.

4. Обновление Office и платформы 1С

Устаревшие версии Microsoft Office или платформы 1С могут иметь известные ошибки совместимости или производительности при работе с COM-автоматизацией. Регулярное обновление до последних версий может решить многие проблемы.

5. Альтернативные методы чтения Excel-файлов

Для простых файлов, которые не требуют сложной обработки или выполнения макросов, мы можем рассмотреть использование более "нативных" для 1С механизмов:

Заключение

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

← На главную