Комментарии 38
Начало положено!
Он совместим с MS COM? Если нет, то есть D-Bus, как правильно сказали, если да, то рекомендую еще посмотреть в исходники wine и reactos.
D-bus не слишком жирно, для внутрипроцессного взаимодействия?
Вместо того, чтобы виртуальные функции дёргать...
При большем объёме соместимого кода с Windows, жить будет веселее, и ошибок в Windows будут находить больше некоторое ПО, которое живёт только на Windows из-за COM/DCOM, спокойно легче может быть портировано на Linux.
Например, можно будет редактировать в Microsoft Excel for Windows, не вставая со стула имея все возможности Linux
Для критиков "зачем это на Linux": COM — это универсальное ABI для кросс-языкового объектно-ориентированного взаимодействия. На текущий момент встроенные средства Linux и OSX такое ABI определяют только для обычных функций в стиле C.
Мы успешно применяем COM для взаимодействия кода на C# с объектно-ориентированным кодом на C++. За счёт встроенного рефкаунтинга время жизни объектов прозрачно регулируется, ABI даёт переносимость между платформами.
Шарповую обёртку генерим средствами SharpGenTools.
В частности посредством COM сделан новый бэкэнд под OSX для AvaloniaUI, других вменяемых способов сделать слой интеграции с ObjC просто нет. А тут clang-овский ARC обеспечивает интеграцию рефкаунтинга C++ и ObjC, а COM обеспечивает интеграцию C++ и C#.
Соорудил базовый заголовок с описанием IUnknown, реализацию ComPtr и ComObject и поехали. Дальше определяем набор интерфейсов и можно прозрачно их использовать из кода на C# как родные.
Так Xamarin.Mac же...
Ну вот у меня проблем с реализацией на связке clang/XCode не возникло
1. midl из комплекта VS умеет генерировать либо COM-интерфейс для студии (со студийными расширениями), либо не обернутый для остальных компиляторов. Во втором режиме не поддерживает часть функционала, midl выдаст ошибку при его наличии в idl файле. Решение: править idl руками
2. сгенерированный заголовочник не компилится в mingw из-за очередного использования нестандартных расширений msvc типа forward enum declaration (нетипизированного). Решение: править руками
3. т.к. в «универсальном» варианте полностью отсутствует всяческая обвязка, необходимо самому дописывать всю обработку ошибок COM. «Родной» вариант прокидывает их в виде исключений.
В итоге то, что делается прагмой #import в студии, вне студии выливается в несколько дней курения документации плюс несколько дней написания оберток.
- Используем SharpGenTools, на вход подаём сразу плюсовые заголовки, всё работает.
- Не используем midl, см. выше
- Все обёртки нагенерил SharpGenTools.
Пример рабочего проекта см. по ссылкам выше.
Базовая часть COM — это по сути обычные интерфейсы из C++. Просто в корне иерархии наследования оных должен быть IUnknown с реализацией счётчика ссылок и каста к другим интерфейсам. На этом собственно всё.
string scope = cmdline(«scope», "");
Ну, наверное, для примеров достаточно, а так — стоило бы убедиться, откуда и куда мы будем пытаться работать.
В итоге вы можете полностью отладить свой код, но работать он будет лишь с известными вам COM-серверами. Одна ошибка в чужом коде — и всё, ваш код трещит по швам.
Не стоит выкапывать эту стюардессу без нужды. Лучше сделать что-то аналогичное на умных указателях.
Одно исключение — это OPC (прежде всего OPC DA). Оно завязано на DCOM. Но при реализации — нарветесь на проблемы с «корпоративной» стабильностью.
С такой аргументацией нельзя использовать вообще никакие гномовские библиотеки. Они же все на GLib, а там g_object_ref и g_object_unref.
В COM- ничего этого нет. Типичная ситуцаия в COM. Есть объект А, у него интрефейс IA. Через этот интерфейс получаем интерфейсы IB и IC. Они могут относится к объекту А, а могут — ко вложенным объектам B и С. Это зависит от реализации. В результате, уничтожая ссылку на IA, мы можем получить неработоспобность B и С, потому что А им нужен, а он уничтожился (точнее при уничтожении А уничтожает B и С). А можем — не получить. И все это зависит от конкретной реализации, которая бывает какая угодно.
Описываемая вами ситуация произойти не может, т. к. QueryInterface увеличивает счётчик ссылок возвращаемого объекта.
Получаем IA, от него получаем IB, делаем release на IA, Память, занята объектом B, возвращается в кучу. Через 15 минут использования интерфейса IB (объекта B) он зависает.
Причем вы можете проверять своего клиента на десятке серверов. Все будет отлично работать, ибо у них интерфейсы IA и IB относятся к одному объекту А (или сделано делегирование вместо агрегатирования). А потом нарветесь на сервер с такой схемой — и кранты. Причем замены этому серверу нет, для данного устойства он один.
Это вот и есть чудный мир OPC и COM.
При удалении объекта А, он удаляет и объект B, причем не взирая на его счетчик ссылок.
Это прямое нарушение принципов работы с COM. Все COM-объекты должны быть в куче и все ссылки на COM-объект должны быть через умные указатели либо соответствующие механизмы клиентского языка. Описываемая вами явная ошибка программиста в коде компонента может случиться при использовании любой системы работы с учётом ссылок.
В другой системе использование ссылок может быть глубоко под капотом. Или возможен явный запрет агрегирования или присутствовать хороший чекер.
Агрегирование и делегирование подразумевают раздельный подсчёт ссылок. Удаление объекта с живыми ссылками — это всегда явный косяк того, кто писал реализацию и к COM как таковому отношения не имеет.
Вся фишка в том, что объемлющий объект должен иметь общий подсчет ссылок со вложенными. А не раздельный. Но, поскольку вложенные объекты могут быть независимыми (inProc COM изDLL ), это не всегда возможно.
Портирование COM на Linux