Использование внешних COM-компонент (.dll) или любых клиентских методов в регламентных заданиях серверной базы.

Для расширения возможностей платформы 1С существует огромное количество внешних компонент (дополнительные функции, взаимодействие с софтом и железом других производителей, ключи защиты).
К сожалению, большинство из них написано на технологии .COM и не могут использоваться на сервере.
Для использования в регламентных заданиях серверной базы их приходится переписывать на Native API.
Однако, иногда нет возможности переписать компоненту на новую технологию, но нужно вызвать ее в регламентном задании на сервере.

Например, не получится переписать компоненту, если вы не её автор и исходников просто нет. Либо если для ее работы недостаточно поддерживаемых технологией Native API простейших типов (число, строка, булево, дата).

При работе с файловой базой особых проблем нет.  Регламентное задание вызывается в фоновом процессе обычного пользователя. Поэтому ему доступны клиенские вызовы. В серверной базе при запуске регламентного задания клиентского контекста нет, соответственно вызов ПодключитьВнешнююКомпоненту() недоступен.

Подробнее о том, почему недоступен, можно почитать на ИТС.

В этом случае можно вызывать компоненту на клиенте. Для этого достаточно выполнить из регламентного задания на сервере запуск еще одного сеанса 1С в котором на клиенте выполнить нужные действия. Ну и не забыть потом завершить запущенный сеанс.

Допустим, у нас в регламентном задании выполняется формирование и сохранение отчета, использующего для склонения ФИО внешнюю COM-компоненту NameDeclension.dll. На файловой базе такое регламентное задание будет работать корректно, на серверной компоненту подключить не получится.

Для устранения проблемы добавим в модуль регламентных заданий процедуру, которая в серверном режиме запустит еще один сеанс и в нем выполнит из внешней обработки вызов формирования отчета на клиенте.

#Если Клиент Тогда

Процедура ВыполнитьФормированиеИСохранениеОтчета() Экспорт

Если ПодключитьВнешнююКомпоненту("ОбщийМакет.NAMEDECL","Скл",ТипВнешнейКомпоненты.COM) Тогда
Компонента = Новый ("AddIn.Скл.NameDeclension");
//Тут код формирования и сохранения отчета
Иначе
ЗаписьЖурналаРегистрации("РеглЗадания", УровеньЖурналаРегистрации.Ошибка,,,
"Не удалось подключить внешнюю компоненту на клиенте");
КонецЕсли;

КонецПроцедуры

#Иначе

Процедура ВыполнитьФормированиеИСохранениеОтчета() Экспорт

ВыполнитьОперациюНаКлиенте("РеглЗадания.ВыполнитьФормированиеИСохранениеОтчета()");

КонецПроцедуры

Процедура ВыполнитьОперациюНаКлиенте(ПараметрДляВыполнения) Экспорт

ИмяПользователя = "";
ПарольПользователя = "";
ПутьКВнешнейОбработке = "c:/temp/Автозапуск.epf";

Кавычка = """";

КаталогBIN = КаталогПрограммы();

ПутьККонфигурации = СтрокаСоединенияИнформационнойБазы();
ПутьККонфигурации = СтрЗаменить(ПутьККонфигурации, Кавычка, Кавычка + Кавычка);

СтрокаЗапуска = Кавычка + КаталогBIN + "1cv8.exe" + Кавычка + " ENTERPRISE"
+ " /IBConnectionString " + Кавычка + ПутьККонфигурации + Кавычка
+ " /N "                  + Кавычка + ИмяПользователя + Кавычка
+ " /P "                  + Кавычка + ПарольПользователя + Кавычка
+ " /Execute  "           + Кавычка + ПутьКВнешнейОбработке + Кавычка
+ " /C  "                 + Кавычка + ПараметрДляВыполнения + Кавычка;

ЗапуститьПриложение(СтрокаЗапуска);

КонецПроцедуры

#КонецЕсли

Код внешней обработки, которая просто вызовет в контексте клиента печать нужного отчета из модуля регламентных заданий и завершит сеанс после формирования отчета.

Попытка
Выполнить(ПараметрЗапуска);
Исключение
КонецПопытки;
ЗавершитьРаботуСистемы(Ложь);

Удобство решения в том, что при настройке регламентных заданий не важно, в каком режиме будет выполняться запуск задания. Если база файловая, то сразу запустится нужная процедура. Если база серверная и при запуске клиентский контекст отсутствует, то выполнится инициализация нового сеанса и в нем процедура корректно отработает в контексте клиента.

Код для обычного приложения. Теоретически полностью аналогично будет работать и в управляемом.

p.s. Также этот подход можно использовать для выполнения любых клиентских процедур в регламентных заданиях.

 


51 Comments

  1. AlX0id

    Гм.. А что насчет лицензий? Какой-то не очень дешевый способ обхода, если на каждого юзера по доп.лицензии надобно.. Да и старт-стоп клиента на сервере — тоже не самый безнакладный процесс..Эт прям вот оооочень сильно надо захотеть именно эту компоненту запустить..

    Reply
  2. ekaruk

    (1) AlX0id, В данном случае речь в основном о кратковременном регламентном запуске процедур. Например, выгрузка отчетов, синхронизация с АТС, выгрузка/загрузка данных на сайт, считка информации со стороннего железа/сервисов. С точки зрения лицензий проблем не вижу. Лицензия занимается исключительно на время выполнения операции — в большинстве случаев несколько минут. Запуск и завершение сеанса тоже никакой особой загрузки не создает.

    Конечно, это не идеальное решение. Скорее костыль, но вполне универсальный и стабильно работающий.

    Reply
  3. theshadowco

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

    Использование запуска клиентских сессий на сервере еще чревато тем, что есть вероятность получения модального окна и зависшей сессии.

    Reply
  4. ekaruk

    (3) theshadowco, Как ни переосмысливай, .COM — компоненты банально не работают на сервере. Альтернатив иногда нет. Проблемы с зависшими сеансами возможны. Но вообще от кода зависит. Если написан корректно, то никаких модальных окон там нет. У нас были периодически такие зависания, но именно из проблем с внешними системами. Решали выполнением при старте обработки автозавершения через обращение к кластеру всех сеансов текущего пользователя старше одного часа. Разумеется, пользователь отдельный именно для регламентных заданий.

    Reply
  5. comol

    А сделать DCOM ну или на край .NET обёртку не?

    Reply
  6. ekaruk

    (5) comol, В смысле обёртку, которая будет обращаться к .dll а сама подключаться к 1С как Native API ? Или что-то другое имелось в виду?

    Теоретически тоже возможно. Из минусов, появляется дополнительная прослойка и необходимость сериализации/десериализации данных, если для них простых типов Native API недостаточно.

    Но лично я не умею такие обёртки писать, необходимости пока не было.

    Reply
  7. Asmody

    Самый большой минус технологии СOM — одноплатформенность. Как только у вас появляется сервер на Linux, о технологии COM приходится забыть.

    Reply
  8. yukon

    (4)

    .COM — компоненты банально не работают на сервере

    Вот те на. Всю жизнь обмен через COM-соединение отлично работал на сервере, а тут оказывается что он «банально не работает». Это как?

    UPD.

    В серверной базе при запуске регламентного задания клиентского контекста нет, соответственно вызов ПодключитьВнешнююКомпоненту() недоступен.

    ПодключитьВнешнююКомпоненту (AttachAddIn)
    Доступность:
    Тонкий клиент, веб-клиент, сервер, толстый клиент, внешнее соединение. 

    Может я действительно чего-то не понимаю, но в чем собственно проблема?

    Reply
  9. ekaruk

    (8) yukon, Добро пожаловать в клиент-серверную архитектуру 🙂

    Не подключаются на сервере com-компоненты. Уже очень давно.

    Работают в файловой базе, так как доступен толстый клиент. Но не в серверной.

    http://its.1c.ru/db/v83doc#bookmark:dev:TI000001197

    32.3. Особенности работы на сервере

    При работе на сервере «1С:Предприятия» допустимо использовать только компоненты, разработанные по технологии Native API, которые могут быть как отдельными файлами, так и упакованными в специальные ZIP-архивы.

    В СП описано 2 варианта подключения. Первый только для Native API. Второй для любых.

    Но:

    Описание варианта метода:

    Компонент должен быть выполнен по технологии COM и зарегистрирован в реестре MS Windows.

    Эти компоненты совместимы с компонентами 1С:Предприятия 7.7.

    Внимание! Вариант метода не работает на сервере и во внешнем соединении.

    В документации на ИТС по ссылке выше подробнее.

    Reply
  10. ekaruk

    (8) yukon, Обмен через COM- соединение Вы имеете в виду подключение через comcntr.dll?

    Оно работает корректно.

    Это не внешняя компонента для 1С, это компонента для Виндовс.

    Она не просто загружается в 1С, а устанавливается в Виндовс через службы компонентов.

    Не могу объяснить, в чем разница, но технология другая.

    Возможно, кто-то другой по принципу ее работы подскажет.

    Reply
  11. yukon

    (10)

    Все понятно. Действительно, компоненты в «старом» формате на сервере недоступны. В общем-то они могут регистрироваться через regsvr32 (увы, необязательно), а далее через Новый COMОбъект.

    А вот с теми кто не может регистрироваться придется держать отдельного клиента, который через обработку ожидания будет выполнять действия. Ваш вариант решает, конечно, задачу, но уж сильно «костыльно».

    Reply
  12. ekaruk

    (11) yukon, Насколько я понимаю, внешние компоненты не могут использоваться на сервере независимо от того, зарегистрированы ли они через regsvr32. Т.е. это принципиальное ограничение. Они просто не подключаются в 1С.

    Возможно, чего-то не учитываю и есть нюансы.

    По comcntr.dll мне самой хотелось бы понять, как она работает. Но информации не нашла.

    Reply
  13. DarLord

    (4) в 1С зависшие сессии вообще беда, у нас при одновременной работе более 150 человек постоянно появляются зависшие сеансы и блокировки базы, бороться с этим очень сложно…

    Reply
  14. kiruha

    Я так понимаю автор имел ввиду — что не работают некоторые com.

    Может автор 32 битную запускает ? Или с визуализацией ?

    Вообще что это было ?

    У нас используется много разных com на сервере — и все прекрасно работает и при очень большой нагрузке

    Reply
  15. ekaruk

    (14) kiruha, Мы говорим о внешних компонентах, выполненных по технологии .COM

    Которые подключаются с использованием синтаксиса ПодключитьВнешнююКомпоненту().

    О том, почему они не работают, описано выше в комментариях и по ссылкам на ИТС.

    Reply
  16. lefthander

    Спасибо за идею. Попробую решить одну задачку. Смысл ее в том что бы по заданию подключиться по COM к бухгалтериям и получить данные в отчет, и отчет разослать по списку. В клиенте все нормально, а вот в регламентном задании — швах.

    Reply
  17. oleg_km

    Мне кажется, нет смысла делать ВК в технологии COM. Лучше тогда делать и использовать просто COM.

    Reply
  18. adapter

    Интересный пример, но немного не удачный. ВыполнитьПечатьОтчета — из принтера на сервере выведет? Мне бы отчет на моем принтере нужен, а на сервере вообще принтер не подключен. Это только в обычном приложении контекст клиента и сервера выполняется на юзерском компе, для совместимости с управляемым.

    И во многих случаях проблемы использования com-компонент вызваны особенностями разрядности Windows (х32, х64) а не контекстом выполнения.

    Reply
  19. ekaruk

    (18) adapter, Тут речь о регламентных операциях, которые используют именно инфраструктуру сервера. Немного поменяла название процедуры в коде, чтобы было понятнее.

    Разрядности Windows (х32, х64) это отдельная история. Но по ней уже вроде достаточно информации. Как именно оборачивать компоненту, чтобы она работала на Виндовс с другой разрядностью. Эту тему уже много раз поднимали.

    Reply
  20. premierex

    (10) Возможно, кто-то другой по принципу ее работы подскажет.

    А всё достаточно просто:

    COM объект — самостоятельная программа, предоставляющая для работы с ней свои интерфейсы, через которые программы, поддерживающие технологию COM (теперь уже принято её ActiveX называть) могут обращаться к его свойствам и методам..

    А вот внешняя COM компонента — это вспомогательная программа (плагин для 1С), которая взаимодействует с 1С, через только через интерфейсы, предоставляемые самой системой 1С:Предприятие. Ну и, соответственно наша внешняя COM компонента — плагин может быть запущена только в рабочем процессе 1С Предприятия.

    Reply
  21. kiruha

    А вариант с подключением через com к 1С — там (внешнее соединение) компоненты тоже не работают ?

    Reply
  22. Nebiros777

    Чтобы не запускать еще один сеанс в конфу добавляется «внутренняя» обработка с макетом, в котором двоичные данные из DLL. Потом все нормально подключается на сервере без проблем: Из внешней обработки подключение DLL невозможно, обязательно нужно вшивать в конфу, если хотите пользоваться «Native» компонентой.

    Reply
  23. ekaruk

    (22) Nebiros777, С Native компонентами проблем никаких нет. Они отлично подключаются на сервере и без встраивания макетов.

    Проблема только с .COM компонентами

    (21) kiruha, с .com подключение К 1С проблем нет. Выше уже обсудили почему.

    Reply
  24. kiruha

    А почему тогда нельзя просто

    Коннектор= Новый COMObject(«V82.COMConnector»);
    База= Коннектор.Connect(СтрокаПодключения);
    База.МойМодуль.МояПроцедураСВнешнейКомпонентойВнутри();
    
    Reply
  25. ekaruk

    (24) kiruha, Потому что МояПроцедураСВнешнейКомпонентойВнутри() не сможет использовать внешнюю компоненту на сервере.

    Абсолютно пофиг, вызывается она снаружи или изнутри.

    Reply
  26. kiruha

    Она вызывает ее во внешнем соединении а не на сервере.

    Есть dll которую можно скачать и проверить ?

    Reply
  27. ekaruk

    (26) kiruha, Та копонента, что у меня в примере.

    http://manual1c.ru/sklonenie-familii-imeni-i-otchestva-po-padezham-v-1s-8-2/

    Где-то уже есть ее Native аналог, но эта вроде как раз .COM

    Попробуйте подключить в регламентном задании на сервере (не в толстом клиенте)

    Reply
  28. kiruha

    Com сессия прекрасно вызвалась из под сервера, в отладчике показывается как внешнее соединение, но подключить внешнюю компоненту в этой сессии не удалось.

    По какой причине не понял

    Так что ваш метод пока единственный )

    Reply
  29. ekaruk

    (28) kiruha, В режиме внешнего соединения нет клиентского контекста. Соответственно и .com компоненты не подключаются.

    Reply
  30. bulpi

    Народ, что же вы все уперлись в вырывание гланд через задний проход??? Ну если все равно придется запустить клиентский сеанс, тогда зачем его запускать через жопу сервер? Запустите вместо регламентного задания клиентский сеанс, используя внешний планировщик (да хоть встроенный Windows)

    Reply
  31. jan27

    (0) лучше использовать

    ПрекратитьРаботуСистемы()
    Reply
  32. zaverax

    Подскажите плиз…раньше свои внешние компоненты (COM) использовал в 1c8.2

    там строка была Компонента = Новый («AddIn.SW»);

    сейчас в 1с8.3 (управляемая форма) надо писать как тут описано в примере

    Компонента = Новый («AddIn.Скл.NameDeclension»);

    Вот интересует NameDeclension — что это такое? откуда брать?

    Reply
  33. Serginio

    А зачем ВК на сервере? Смысл ВК в событиях, окнах и доступе к глобальному контекста 1С.

    Используй COM. А например используя Библиотеки Net ты можешь написать, что угодно http://infostart.ru/public/238584/

    Вот библиотека склонения http://yeaahcode.blogspot.ru/2015/01/lingvonet.html

    Reply
  34. Serginio

    На самом деле интерес представляет Com объект который внутри будет вызывать методы IlanguageExtender

    На подобии http://infostart.ru/public/345658/ только в обратную сторону.

    А твой подход я применял еще в 8.1 для сохранения в эксель итд

    Reply
  35. ekaruk

    (32) zaverax, Это стандартная компонента для склонения.

    «NameDeclension» это прописанное в ней имя.

    Вообще если пишите сами, то лучше переделать сразу правильно на Native.

    Будет стабильнее работать и удобнее.

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

    Reply
  36. zaverax

    (35)

    а есть пример написания COM и Native в Delphi?

    у меня в делфи вот так описано CreateAddIn(‘sw’, ObjectGUID, TDM1,’AddInFPList’);

    в 1с8 вызывал Компонента = Новый («AddIn.SW»);

    если теперь вызываю Компонента = Новый («AddIn.SW.TDM1»); — то ошибка Тип не определен…

    Reply
  37. Serginio

    ПодключитьВнешнююКомпоненту(<Местоположение>, <Имя>, <Тип>)

    Вот Имя и будет вторым после Addin

    Reply
  38. Serginio

    (0) Проблема еще в том, сами ВК 32 разрядные.

    Кстати в http://infostart.ru/public/238584/ есть пример обмена данными по TCP/IP

    Смысл в том, что экономишь на запуске 1С, компоненты итд.

    А так созданшь обработку, в которой запускаешь Tcp/IP клиента и обмениваешься данными.

    Аналогичный обмен здесь

    http://infostart.ru/public/434771/

    Reply
  39. zaverax

    (37) Serginio,

    меня интересует что должно быть написано третим…AddIn.SW.хххххх — вместо ххххххх

    что за класс?

    CreateAddIn(‘sw’, ObjectGUID, TDM1,’AddInFPList’)….TDM1 — это класс который создается…но если я его подставляю в 1С то ошибка Тип не определен…

    Reply
  40. ekaruk

    (36) zaverax, Тут не подскажу, к сожалению.

    С нюансами разработки и регистрации внешних компонент я знакома плохо.

    Reply
  41. Serginio

    То, что ты задаешь в RegisterExtensionAs

    http://habrahabr.ru/post/191014/

    Reply
  42. kiruha

    Никто не заметил комментария (31) ПрекратитьРаботуСистемы

    Описание:

    Завершает работу системы не зависимо от наличия модальных диалогов, открытых редактируемых форм документов и справочников и т.д. При этом не вызываются процедуры-обработчики событий завершения работы системы.

    Reply
  43. ekaruk

    (42) kiruha, (31) jan27,

    Да, пожалуй, ПрекратитьРаботуСистемы() надежнее.

    У меня ЗавершитьРаботуСистемы() тоже вполне хватало.

    Reply
  44. v.shkapin

    Беда в том, что такой запуск клиента из фонового задания не работает.

    У меня внешняя dll с com-объектами, через которую надо подключиться к сторонней базе (не 1С) и забрать некоторые данные.

    Хотел делать это в фоновом задании. Если это регламентное задание запустит на клиенте — проходит в лет. А через фоновое — доходит до строки ЗапуститьПриложение(СтрокаЗапуска);

    и все. Новый сеанс не создается, и фоновое подвисает в бесконечности. Убить получается только перезапуском службы 1С на сервере.

    Reply
  45. malets

    (44) У меня такая же проблема

    Reply
  46. Human

    Получается нет решения кроме переписывания библиотек?

    Reply
  47. RoleXX

    Интересная идея, надо попробовать.

    Reply
  48. user618219_damirakhtyamov

    Добрый день.

    Если тема еще актуальна,

    а вот так: Компонента = Новый COMОбъект(«AddIn.NameDeclension»); — не работает?

    Reply
  49. uno-c

    (48) Если на сервере зарегистрирована — то работает. Доп.обработка еще должна запускаться в небезопасном режиме, или в безопасном с дополнительными разрешениями. На днях ковырялся с COM — компонентой для 1С mysql.dll, в облаке нужно было регламентное сделать, которое ее использовало. Все получилось (8.3.12, УНФ 1.6.15), работает в фоне по расписанию.

    Reply
  50. uno-c

    (48) И похоже, у автора статьи именно так это и работает — компонента запускается на сервере, просто она там уже зарегистрирована. Основные методы по формированию табличного документа производятся в контексте сервера, значит на сервере вычисляется и склонение ФИО с использованием внешней com-компоненты. Вряд ли отчет написан так, что при формировании табличного документа сервер общается с клиентом с целью просклонять ФИО. Хотя конечно всякое можно придумать — получить на клиент табличный документ и на клиенте менять падеж в ячейках с ФИО.

    Reply
  51. uno-c

    Наконец, главное, что выяснил. Проблема была такая же: в серверной базе на облаке обработка работала в интерактиве через файл-открыть, нормально создавала объект COM-компоненты с помощью (т.е. админ предварительно зарегистрировал ее в реестре облачного сервера)

    &НаСервере
    …Сайт = Новый COMObject(«AddIn.MySQL»)

    и дальше сервер 1С отрабатывал методы этого класса. Но когда запускал ее в регламентно-фоновом режиме — я журналировал ошибку

    {ВнешняяОбработка.ОпенКартДляРегламентного.МодульОбъекта(6873)}:
    Ошибка при вызове конструктора (COMObject) Сайт = Новый COMObject(«AddIn.MySQL»);
    по причине: Установлен безопасный режим. Выполнение операции запрещено

    Дело оказалось в том, что профили безопасности 1С разрешали небезопасный режим для клиентского вызова сервера из внешней обработки, но запрещали его для фоновых заданий из справочника доп.обработок — принудительно ставили безопасный, несмотря на то, что обработка была зарегистрирована

    ПараметрыРегистрации.БезопасныйРежим = Ложь;

    Поскольку это было облако, с админами связываться долго, а результат непредсказуем, проблему решил следующим образом:

    Менеджер = РегистрыСведений.РежимыПодключенияВнешнихМодулей.СоздатьМенеджерЗаписи();
    Менеджер.ИдентификаторПрограммногоМодуля = Справочники.ДополнительныеОтчетыИОбработки.НайтиПоНаименованию(«Загрузка заказов ОпенКарт по расписанию»,Истина).УникальныйИдентификатор();
    Менеджер.ТипПрограммногоМодуля  = Справочники.ИдентификаторыОбъектовМетаданных.НайтиПоНаименованию(«Дополнительные отчеты и обработки (Справочник)», Истина);
    Менеджер.БезопасныйРежим = Ложь;
    Менеджер.Записать(Истина);
    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *