Портирование COM на Linux
Мне нравится технология COM. Но речь пойдет не о технологии, восхвалении или недостатках COM, а опыте переноса и реализации на Linux. Велосипед? Целесообразность? Давайте не будем на этом заострять внимание.
В общем понимании, объект класса, реализующий как минимум один COM-интерфейс. Реализация объекта в основном скрывается в динамически подключаемой библиотеке, называемой COM-сервер (2) , для использования публикуются и распространяются интерфейсы.
COM-интерфейс, абстрактный класс содержащий только чисто виртуальные функции. Выделяется особый интерфейс IUnknown, любой COM-объект обязан реализовывать данный интерфейс.
Каждый COM-интерфейс должен содержать некий свой идентификатор. В COM он определяется структурой GUID и вот тут столкнемся с первым недостатком COM. GUID непонятен и не читаем ну и все остальное описанное на Wiki. Нам он то же нужен, но в более читаемом и понятном виде (назовем его uiid).
#define define_uiid(name) \ inline static const std::string& guid() < const static std::string idn(dom_guid_pre_name #name); return idn; >namespace Dom < using uiid = std::string; using clsuid= std::string; struct IUnknown < virtual long AddRef() = 0; virtual long Release() = 0; virtual bool QueryInterface(const uiid&, void **ppv) = 0; define_uiid(Unknown) >; >
Помимо идентификатора интерфейса, выделяется и идентификатор класса (clsuid), необходимый для создания объекта. В нашем случае, т.к. это более менее читаемый идентификатор, который может определять суть, можно пока забыть о их публикации (возможно это не хорошо).
Резюме
COM-объект, содержит единственный идентификатор класса. Реализует как минимум один COM-интерфейс — IUnknown (любой COM-интерфейс имеет уникальный идентификатор интерфейса). Разные реализации COM-объекта могут иметь один и тот же идентификатор класса (пример: release и debug версия).
Динамически подключаемой библиотека (для Linux это Shared object — so) реализующая как минимум один COM-объект. Сервер должен экспортировать определенный набор функций:
extern "C" bool DllCreateInstance(const uiid& iid, void** ppv)
Создает объект класса по clsuid, увеличивает количество ссылок на so, каждый раз при успешном создании объекта. Вызов IUnknown::AddRef, так же должен увеличивать счетчик ссылок на so, а IUnknown::Release должен уменьшать.
extern "C" bool DllCanUnloadNow()
Если количество ссылок на SO равно 0, то можно выгружать библиотеку.
extern "C" bool DllRegisterServer(IUnknown* unknown)
Регистрирует в “реестре” все clsuid сервера. Вызывается единожды при инсталляции COM-сервера.
extern "C" bool DllUnRegisterServer(IUnknown* unknown)
Удаляет из “реестра” записи о зарегистрированных clsuid сервера. Вызывается единожды при деинсталляции COM-сервера.
Пример SimpleHello, объявляем интерфейс IHello:
struct IHello : public virtual Dom::IUnknown < virtual void Print() = 0; define_uiid(Hello) >;
/* COM-объект */ class SimpleHello : public Dom::Implement < public: SimpleHello() < printf("%s\n", __PRETTY_FUNCTION__); >~SimpleHello() < printf("%s\n", __PRETTY_FUNCTION__); >virtual void Print() < printf("Hello from %s\n",__PRETTY_FUNCTION__); >define_clsuid(SimpleHello) >; /* COM-сервер */ namespace Dom < DOM_SERVER_EXPORT_BEGIN EXPORT_CLASS(SimpleHello) DOM_SERVER_EXPORT_END DOM_SERVER_INSTALL(IUnknown* unknown) < Interfaceregistry; if (unknown->QueryInterface(IRegistryServer::guid(), registry)) < // Дополнительные действия при инсталляции сервера >return true; > DOM_SERVER_UNINSTALL(IUnknown* unknown) < Interfaceregistry; if (unknown->QueryInterface(IRegistryServer::guid(), registry)) < // Дополнительные действия прии деинсталляции сервера >return true; > >
Набор макросов скрывает реализации функций, предоставляя более структурированное объявление и логику.
Dom::Implement — скрывает реализацию методов интерфейса IUnknown, добавляет “сахарок”, при объявлении интерфейсов реализуемых объектом (С++11 и variadic templates):
template struct Implement : virtual public IUnknown, virtual public IFACES… < . >;
Интерфейс IRegistryServer — определяет набор методов работы с “реестром” COM-серверов.
Важность реестра можно недооценить, но он является наверное главным столпом COM. Microsoft пишет в системный реестр, создает сложную структуру описания интерфейсов и их атрибутов (idl), я пошел немного по другому пути.
В реализации реестр базируется на файловой системе.
Какие плюшки? Понятность, простота, возможность восстановления, особая плюшка при регистрации сервера можно задать некого рода namespace (директорию относительно базового реестра в которой будет регистрироваться объекты сервера), тем самым можно реализовать целостность и версионность приложений использующих технологию.
Из недостатков, возможные проблемы с безопасностью, подмена реализаций объектов.
Как использовать, пример приложения (4)
Для того чтобы заставить все работать потребуется еще небольшая “библиотечка” и небольшая “программка”.
“Библиотечка” — ни что иное как обертка реализующая и собирающая все в единое целое, работу с реестром, загрузку\выгрузку SO, создание объектов.
Она единственная должна быть указана при сборке приложения. Все остальное, “хочется верить”, она сделает сама.
“Программка” — regsrv — собственно это аналог программы Microsoft RegSrv32, выполняющей те же действия (+ возможность указания namespace, + возможность получения списка зарегистрированных clsuid и COM-серверов).
#include "../include/dom.h" #include "../../skel/ihello.h" int main() < Dom::Interfaceunkwn; Dom::Interface hello; if (Dom::CreateInstance(Dom::clsid("SimpleHello"), unkwn)) < unkwn->QueryInterface(IHello::guid(), hello); hello->Print(); > else < printf("[WARNING] Class `SimpleHello` not register.\nFirst execute command\n\tregsrv /libskel.so\n. and try again."); > return 0; >
Dom (Dynamic Object Model), моя реализация для Linux.
COM-технология и Linux
А в linux’е что-то типа windows’кой COM-технологии есть.
Re: COM-технология и Linux
А что тебе от нее собственно надо в Linux. Как ты ее в обще понимаешь. Ежу ясно, что никто тут (в Linux) писать компоненты для VB не будет 🙂 А в остальном, пиши свои интерфейсы, фабрики, чем ником тебе. Вообще собственно что нужно то, а то вопрос не совсем понятен
Re: COM-технология и Linux
Re: COM-технология и Linux
Не знаю как ком ком+ в Линуксе поддерживаются довольно неплохо и даже доки на русском есть. И книги на рынке. если мне неизменяет память то ето что-то близкое k RPC. Под рукой ничего более подробного нет.
Re: COM-технология и Linux
Понятно. Но все же, какие именно задачи он (COM) должен решать в Linux. Ведь в большинстве случаев не обязательно лезть в дебри сложной технологии, биться как говориться в лоб, когда можно найти другое решение, причем не худшее. Я понимаю, что в Linux важен сам принцип COM — отделение реализации от интерфейса. А вот с COM+ . Пока не смотрел что за чудо, нет времени и обхожусь без него вполне, но позже обязательно взгляну, поэтому тут мне сказать нечего
Re: COM-технология и Linux
Есть например Bonobo,
есть еще несколько попыток сделать подобное, каждая реализация используется своим целевым пользователе,
будь то разработчики KDE, GNOME или RH.
Re: COM-технология и Linux
Может, я не правильно вопрос поставил. Или, я неправильно понимаю суть COM-технологии. Короче говоря, меня интересует возможность закатать объект в разделяемую библиотеку.
Re: COM-технология и Linux
По-поводу «отделение реализации от интерфейса»,
рекомендую (в качестве саморекламы 😉 посмотреть
http://root.cern.ch/root/htmldoc/TGuiBuilder.html
Чем тебе не COM 😉
Шаг 2 — набираем «Ctrl-S» и спасаем «интерфейс» в файл qq.C
http://carrot.cern.ch/~onuchin/br2.png
Работет (без-воз-мездно, то есть за-даром) как под M$, так и под Linuxом
Особенности разработки конфигураций для ОС Linux и macOS
Область применения: управляемое приложение, обычное приложение.
1. В большинстве случаев, в конфигурации не требуется предпринимать каких-либо специальных мер для обеспечения работы конфигурации (клиентское приложение и сервер) на ОС Linux и macOS. В этой статье перечислены отдельные рекомендации для специфических случаев, описанных в приложении 7 документации по платформе 1С:Предприятие.
2. Для реализации всех ключевых функций прикладного решения следует использовать возможности платформы 1С:Предприятие по унификации работы на различных операционных системах.
2.1. Вместо Windows-технологии COM (объект COMОбъект ) следует использовать специализированные кроссплатформенные механизмы платформы:
- Для администрирования кластера серверов 1С:Предприятия, вместо работы с объектной моделью агента сервера через COM-объект v83.ComConnector , следует использовать сервер администрирования (ras) и утилиту администрирования (rac). При работе в macOS утилиты rac и ras недоступны.
- Для получения путей к рабочим каталогам, вместо COM-объектов ОС Windows, следует использовать методы глобального контекста РабочийКаталогДанныхПользователя , КаталогДокументов , КаталогВременныхФайлов .
В остальных случаях следует рассмотреть другие альтернативы технологии COM, работающие в ОС Linux и macOS, например, технологию создания внешних компонент Native API.
2.2. Внешние компоненты (клиентские и серверные), поставляемые в составе конфигурации, следует разрабатывать с использованием технологии Native API. Это позволяет создавать кроссплатформенные внешние компоненты для различных операционных систем, а также для веб-клиента, работающего в веб-браузерах, которые поддерживаются платформой 1С:Предприятие. Подробнее о разработке внешних компонент см. документацию по платформе.
2.3. Для механизмов, использующих объект Почта , следует рассмотреть альтернативные варианты:
- По переводу на объект ИнтернетПочта ;
- По разработке внешних компонент для ОС Linux и macOS, которые поддерживают работу с установленными почтовыми клиентами в ОС Linux и macOS.
2.4. Если в составе конфигурации поставляются картинки в форматах WMF и EMF (метафайлы Windows), их следует заменить на растровые, например PNG или JPG.
2.5. Также следует использовать возможности платформы 1С:Предприятие по унификации работы с файловой системой.
2.5.1. В ОС Linux имена файлов регистро-зависимые, поэтому во всех местах кода, который работает с конкретным файлом, его имя (путь) должен указываться в одном регистре.
2.5.2. Не следует указывать разделить пути файла и маску всех файлов вручную (например, «/», «*.*»), для этого необходимо использовать функции ПолучитьРазделительПути и ПолучитьМаскуВсеФайлы .
При использовании в конфигурации Библиотеки стандартных подсистем для работы с именами файлов также рекомендуется использовать функции общих модулей ОбщегоНазначения и ОбщегоНазначения Клиент .
3. Для отдельных второстепенных (сервисных) функций прикладного решения допустимо отключать их работу в ОС Linux и macOS. Например, для прикладного решения в области торгового учета второстепенными могут считаться возможности по синхронизации данных через прямое подключение с другими программами, по импорту почты из сторонних почтовых клиентов и т.п.
Для этого следует скрывать команды таких механизмов из командного интерфейса программы при работе в ОС Linux и macOS, либо (если технически скрыть невозможно) выводить сообщение вида
« доступна только при работе в ОС Windows».
&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
Информация = Новый СистемнаяИнформация;
Если Информация.ТипПлатформы <> ТипПлатформы.Windows_x86 И Информация.ТипПлатформы <> ТипПлатформы.Windows_x86_64 Тогда
ПоказатьПредупреждение(, НСтр(«ru = ‘Печать в Microsoft Word доступна только при работе в ОС Windows.'»));
Возврат;
КонецЕсли;
При использовании в конфигурации Библиотеки стандартных подсистем рекомендуется использовать функции ЭтоLinuxКлиент , ЭтоMacOSКлиент и ЭтоWindowsКлиент из общих модулей ОбщегоНазначения и ОбщегоНазначенияКлиент.