Как программно выбрать принтер в 1С при работе через RDP, учитывая изменяющиеся имена?

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

При работе в 1С через удаленный рабочий стол (RDP) часто возникает проблема с автоматическим выбором принтера. Если мы пытаемся задать имя принтера для табличного документа, используя конструкцию ТабДок.ИмяПринтера = "Имя_Принтера", то сталкиваемся с тем, что при перенаправлении через RDP к имени принтера добавляется суффикс "(перенаправлено N)", где N — это уникальный идентификатор сеанса пользователя. Из-за этого изменяющегося суффикса стандартный способ задания имени принтера не всегда работает корректно. Например, если задать ТабДок.ИмяПринтера = "BIXOLON XT5-40 (перенаправлено 97)", печать будет осуществляться правильно, но при изменении номера сеанса (например, на 98) принтер уже не будет найден. В то же время, если задать просто ТабДок.ИмяПринтера = "BIXOLON XT5-40", то принтер не будет проставлен автоматически, так как полное имя отличается. В этой статье мы разберем различные подходы к решению данной проблемы, включая получение списка принтеров и поиск нужного по части имени, а также более надежные методы с использованием системных средств Windows.

Причины изменения имени принтера в RDP и его идентификация

Для начала, давайте выясним причину такого поведения. Когда принтер перенаправляется через RDP, операционная система добавляет к его имени специальные суффиксы, чтобы обеспечить уникальность каждого перенаправленного принтера в рамках различных пользовательских сеансов. Это стандартное поведение Windows, направленное на предотвращение конфликтов. Например, принтер "BIXOLON XT5-40" может быть виден как "BIXOLON XT5-40 (перенаправлено 97)" или "BIXOLON XT5-40 (перенаправлено 98)". Этот суффикс делает затруднительной надежную идентификацию принтера по его "короткому" имени.

Для решения этой проблемы нам необходимо получить список всех доступных принтеров в текущем сеансе и найти нужный нам принтер по известной нам части его имени. Затем мы можем использовать полное имя найденного принтера для свойства ТабДок.ИмяПринтера.

Метод 1: Поиск принтера по части имени с использованием WScript.Network

Один из самых простых способов получить список принтеров в 1С — это использование COM-объекта WScript.Network. Давайте посмотрим, как это можно реализовать.

Сначала мы создадим объект WScript.Network, который предоставляет доступ к функциям управления сетью, включая информацию о принтерах. Затем мы используем метод EnumPrinterConnections(), который возвращает коллекцию подключенных принтеров. Эта коллекция содержит пары значений: имя порта и имя принтера.

Рассмотрим пример кода:


СписокПринтеров = Новый СписокЗначений;
Попытка
    // Создаем COM-объект WScript.Network для работы с сетевыми подключениями
    Принтеры = Новый COMОбъект("WScript.Network");
    // Получаем коллекцию подключенных принтеров
    Prn = Принтеры.EnumPrinterConnections();
    
    // Перебираем коллекцию, чтобы получить имена принтеров
    // Коллекция Prn содержит пары: Prn.Item(i) - имя порта, Prn.Item(i+1) - имя принтера
    Для i = 0 По Prn.Count() - 1 Шаг 2 Цикл
        // Добавляем имя принтера в список
        СписокПринтеров.Добавить(Prn.Item(i+1)); 
    КонецЦикла;
Исключение
    Сообщить("Ошибка при получении списка принтеров через WScript.Network: " + ОписаниеОшибки());
КонецПопытки;

Если СписокПринтеров.Количество() > 0 Тогда
    Сообщить("Список доступных принтеров:");
    Для Каждого Принтер Из СписокПринтеров Цикл
        Сообщить(Принтер.Значение);
    КонецЦикла;
Иначе
    Сообщить("Не удалось получить список принтеров.");
КонецЕсли;

// Теперь найдем наш принтер по части имени
ИскомоеИмяПринтера = "BIXOLON XT5-40";
НайденныйПринтер = "";

Для Каждого ЭлементСписка Из СписокПринтеров Цикл
    Если СтрНайти(Врег(ЭлементСписка.Значение), Врег(ИскомоеИмяПринтера)) > 0 Тогда
        НайденныйПринтер = ЭлементСписка.Значение;
        Прервать;
    КонецЕсли;
КонецЦикла;

Если Не ПустаяСтрока(НайденныйПринтер) Тогда
    Сообщить("Принтер '" + ИскомоеИмяПринтера + "' найден: " + НайденныйПринтер);
    // Теперь мы можем использовать это полное имя для ТабДок.ИмяПринтера
    // ТабДок.ИмяПринтера = НайденныйПринтер;
Иначе
    Сообщить("Принтер '" + ИскомоеИмяПринтера + "' не найден среди доступных.");
КонецЕсли;

Важный момент: Как показала практика (сообщение 5), объект WScript.Network может не всегда видеть принтеры, проброшенные через RDP. Он чаще всего отображает только локальные принтеры (если код выполняется на клиентской машине или на сервере, но не в RDP сессии) или сетевые принтеры, подключенные напрямую. Если ваш принтер проброшен через RDP, особенно с использованием технологии Remote Desktop Easy Print, он может не появиться в списке, полученном этим методом.

Метод 2: Использование WMI (Windows Management Instrumentation) для получения списка принтеров

Для более надежного и полного получения списка принтеров, включая те, что перенаправлены через RDP, мы можем использовать WMI (Windows Management Instrumentation). WMI предоставляет мощный интерфейс для управления операционной системой и ее компонентами. Мы можем получить список принтеров с помощью класса Win32_Printer. Этот метод более универсален и часто позволяет видеть все принтеры, доступные в текущем сеансе, включая RDP-перенаправленные.

Разберем шаги получения списка принтеров через WMI:

  1. Создаем COM-объект winmgmts:\\.\root\CIMV2. Это основной объект WMI, который позволяет выполнять запросы к системе.
  2. Выполняем WQL-запрос (WMI Query Language) SELECT * FROM Win32_Printer. Этот запрос вернет коллекцию всех принтеров, зарегистрированных в системе.
  3. Перебираем полученную коллекцию принтеров, извлекая их имена и другие свойства.

Посмотрим на пример кода 1С:


СписокПринтеровWMI = Новый СписокЗначений;
Попытка
    // Создаем COM-объект для доступа к WMI
    WMI = Новый COMОбъект("winmgmts:\\.\root\CIMV2");
    
    // Выполняем WQL-запрос для получения всех принтеров
    // Класс Win32_Printer содержит информацию о принтерах
    ПринтерыКоллекция = WMI.ExecQuery("SELECT * FROM Win32_Printer");
    
    // Перебираем найденные принтеры
    Для Каждого ПринтерWMI Из ПринтерыКоллекция Цикл
        // ПринтерWMI.Name содержит полное имя принтера
        // ПринтерWMI.PortName содержит имя порта
        // ПринтерWMI.DriverName содержит имя драйвера
        // ПринтерWMI.Local указывает, является ли принтер локальным
        // ПринтерWMI.Network указывает, является ли принтер сетевым
        // ПринтерWMI.Shared указывает, является ли принтер общим
        
        СписокПринтеровWMI.Добавить(ПринтерWMI.Name);
    КонецЦикла;
Исключение
    Сообщить("Ошибка при получении списка принтеров через WMI: " + ОписаниеОшибки());
КонецПопытки;

Если СписокПринтеровWMI.Количество() > 0 Тогда
    Сообщить("Список доступных принтеров через WMI:");
    Для Каждого Принтер Из СписокПринтеровWMI Цикл
        Сообщить(Принтер.Значение);
    КонецЦикла;
Иначе
    Сообщить("Не удалось получить список принтеров через WMI.");
КонецЕсли;

// Теперь найдем наш принтер по части имени из списка WMI
ИскомоеИмяПринтера = "BIXOLON XT5-40";
НайденныйПринтерWMI = "";

Для Каждого ЭлементСписка Из СписокПринтеровWMI Цикл
    Если СтрНайти(Врег(ЭлементСписка.Значение), Врег(ИскомоеИмяПринтера)) > 0 Тогда
        НайденныйПринтерWMI = ЭлементСписка.Значение;
        Прервать;
    КонецЕсли;
КонецЦикла;

Если Не ПустаяСтрока(НайденныйПринтерWMI) Тогда
    Сообщить("Принтер '" + ИскомоеИмяПринтера + "' найден через WMI: " + НайденныйПринтерWMI);
    // Используем найденное полное имя для ТабДок.ИмяПринтера
    // ТабДок.ИмяПринтера = НайденныйПринтерWMI;
Иначе
    Сообщить("Принтер '" + ИскомоеИмяПринтера + "' не найден среди доступных через WMI.");
КонецЕсли;

Этот метод считается более предпочтительным для работы с принтерами в Windows, так как предоставляет более полную и надежную информацию.

Особенности работы с Universal Print Driver (Remote Desktop Easy Print)

В современных версиях Windows Server для печати из RDP-сессии активно используется универсальный драйвер Remote Desktop Easy Print. Этот драйвер позволяет печатать практически на любом принтере, подключенном к клиентской машине, без необходимости установки специфических драйверов на RDP-сервере. Это значительно упрощает администрирование. Принтеры, проброшенные через Easy Print, также будут иметь суффикс "(redirected N)", и именно их мы чаще всего ищем в RDP-сессии.

При использовании WMI, эти принтеры также будут присутствовать в коллекции Win32_Printer, и их можно будет идентифицировать по имени, которое содержит как исходное имя принтера, так и метку перенаправления. Мы также можем дополнительно проверять свойство DriverName, которое для принтеров Easy Print будет, как правило, содержать "Remote Desktop Easy Print" или подобное значение.

Дополнительные рекомендации и альтернативные подходы

Помимо программного поиска, мы можем рассмотреть несколько организационных и технических подходов для минимизации проблем с печатью через RDP.

  1. Настройки RDP-клиента и сервера: Прежде всего, убедитесь, что в настройках вашего RDP-файла или клиента удаленного рабочего стола включено перенаправление принтеров (обычно это опция "Принтеры" на вкладке "Локальные ресурсы"). На сервере также необходимо проверить групповые политики, которые могут регулировать перенаправление принтеров.
  2. Установка драйверов на сервере: В некоторых случаях, особенно если принтер не совсем корректно работает с Easy Print, может потребоваться установка идентичных драйверов принтера как на клиентском компьютере, так и на терминальном сервере. Это иногда помогает избежать проблем с совместимостью и более стабильно получать имена принтеров.
  3. Расшаривание принтера как сетевого: Если позволяет сетевая инфраструктура (например, серверы находятся в одной сети или имеют к ней доступ), вы можете расшарить принтер на клиентской машине и подключить его на терминальном сервере как обычный сетевой принтер. В этом случае имя принтера будет стабильным и не будет содержать "(перенаправлено N)", но это не всегда реализуемо, особенно если клиенты находятся в разных географических точках или в изолированных сетях. Если расшаривание по локальной сети невозможно, можно рассмотреть вариант с расшариванием принтера через интернет, используя VPN или другие технологии, но это уже более сложная инфраструктурная задача, требующая усилий системных администраторов.
  4. Сторонние решения: Существуют специализированные сторонние программные продукты (например, TSPrint), предназначенные для решения проблем печати в терминальных сессиях. Они часто работают по принципу перехвата печати на сервере, преобразования документа в PDF и отправки его на клиент для печати на локальном принтере по умолчанию, обходя стандартные механизмы перенаправления RDP-принтеров. Эти решения могут предоставить более стабильное имя принтера или вовсе отказаться от его явного указания, используя принтер по умолчанию.
  5. Использование PowerShell или WinAPI (для глубокой интеграции): В более сложных сценариях можно использовать PowerShell скрипты (например, Get-Printer | ? DriverName -eq "Remote Desktop Easy Print") или функции WinAPI (EnumPrinters) для получения подробной информации о принтерах. Однако их интеграция с 1С потребует либо выполнения внешних скриптов, либо использования объектов COM-объектов для вызова функций WinAPI, что является более сложной задачей для программиста 1С.

Заключение

Программный выбор принтера в 1С при работе через RDP требует внимательного подхода из-за динамического изменения имен принтеров. Мы рассмотрели несколько методов для получения списка доступных принтеров. Метод с использованием WScript.Network прост в реализации, но может не видеть все перенаправленные RDP-принтеры. Метод с использованием WMI (Windows Management Instrumentation) через класс Win32_Printer является более универсальным и надежным, предоставляя доступ к полному списку принтеров, включая те, что используют Remote Desktop Easy Print.

Рекомендуем использовать WMI для получения списка принтеров, а затем производить поиск по части имени. Это позволит нам найти нужный принтер, даже если его полное имя изменяется из-за суффикса "(перенаправлено N)". Помните, что комплексное решение проблемы может включать как программные доработки в 1С, так и правильную настройку инфраструктуры RDP и принтеров. При возникновении проблем всегда полезно проверять журналы событий Windows на сервере и клиенте для выявления ошибок, связанных с драйверами или службой печати.

← На главную