Всем добрый день. Хотел бы получить краткие и понятные для новичка ответы на следующие вопросы:

  1. Что такое COM объект?

  2. Как происходит разработка COM объекта?

  3. Какие особенности реализации COM Microsoft?

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

Мне попался на глаза такой вопрос, предлагаю свой развернутый ответ. Интересно получить оценку сообщества профессионалов. Надеюсь и новички смогут найти что то полезное.


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

Кстати в документации Майкрософта по DirectX, практически в заголовке мы также, как и 20+ лет назад, видим заявление о необходимости использования СОМ:

The Microsoft Component Object Model (COM) is an object-oriented programming model used by several technologies, including the bulk of the DirectX API surface. For that reason, you (as a DirectX developer) inevitably use COM when you program DirectX.

 Давайте я попробую рассказать, исходя из своего опыта, на всем известном примере что такое COM объекты и зачем вообще нужна концепция моделирования объектов в виде компонент, по аналогии с миром физических устройств. Идея проста, так же как разные смартфоны (например) собираются из набора микросхем, резисторов, конденсатором, так же можно и разные большие приложения собирать (казалось бы-хотелось бы) из локализованных компонент, изолированно созданных и сохраненных в разных файлах (ДЛЛ-ках) и поэтому совершенно не зависимых, а значит не способных нарушить как минимум компиляцию друг друга.

Для примера можно рассмотреть задачу создания универсального проигрывателя видео файлов (видеоплеер).

Проблема сложности реализации (не путать со сложностью вычислений в ран-тайме)

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

Для осознания масштаба той программы, которая будет претендовать на универсальность, при проигрывании видео, допустим у нас есть по 10 форматов каждого типа. Таким образом наш универсальный проигрыватель видео должен уметь обрабатывать 10 * 10 * 10 = 1000 вариантов конфигурации проигрываемого файла, представьте себе switch на тысячу кейсов! Это конечно очень грубая абстракция для оценки масштаба программы для проигрывания видео, но, как ни странно, она дает очень наглядную и совершенно адекватную оценку масштаба проблемы, которую надо решить. Очевидно что в одном случае сложность определяется произведением целых чисел больших единицы, а в другом суммой плюс некоторая константа сравнимая с единицей. Кстати, по поводу оценки 10 «десять» вариантов – для тех, кто не в курсе – это очень умеренная оценка количества, в реальности это число оценивается в несколько десятков и, типов кодеков на самом деле, гораздо больше, чем три.

Решение как обычно будет очевидным после того, как оно кем-то сформулировано. Вместо того что бы писать 1000 вариантов алгоритма на каждый из случаев жизни, надо:

  1. Написать отдельную компоненту (библиотеку‑DLL‑ку) для каждого декодера, распаковщика, рендерера, …, то есть в рассмотренном случае всего 30 ДЛЛ‑к вместо 1000 кейсов в свиче!

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

Для тех, кто любит считать сложность по формулам, исходная была:

O (произведение всех ni для всех m типов кодеков) где

ni – число кодеков одного типа i,

m – число типов кодеков.

Во втором случае сложность равна:

O(суммы Ni  для m типов + L) где

Ni – число кодеков одного типа i оформленных в виде компонент,

m – число типов кодеков и

L – сложность логики из пункта 2. Кажется, что N будет несколько выше, чем n так как нужно какое-то дополнительное оформление, на самом деле это оформление зачастую упрощает разработку так как заставляет сосредоточиться на действительно значимых аспектах реализации компоненты и обеспечивает существенный уровень унификации кода.

Есть отдельный огромный плюс компонентного подхода. У нас появляется возможность разрабатывать декодеры (например, для примера Mpeg4, MP4) совершенно изолированно друг от друга, в разных проектах, разными людьми, параллельно, … как угодно! Единственное условие соответствие разработанной компоненты определенным правилам оформления компонент.

И теперь можно остановиться на этих правилах оформления компонент поподробнее, их все равно надо понимать в каком-то виде для понимания всей технологии. Чтобы понять эти правила надо попробовать сформулировать логику по которой будет строиться и работать приложение видео плеера, основанное на использовании кодеков, каждый из которых может загружаться из отдельной ДЛЛ-ки.

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

Как это выглядит на каком-то подобии схемы

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

Как это ни странно в мире COM-объектов видео плеер НЕ декодирует, НЕ проигрывает видео сам, он строит связанный граф из компонент, которые будут проигрывать видео, а ПОТОМ транслирует пользовательские команды (такие как нажатие кнопок Стоп-Плей) в команды для этого графа. Уходя немного в сторону, можно отметить что граф тоже представлен некоторым объектом внутри видеоплеера и трансляция пользовательских команд к этому объекту тоже во многом регламентирована, не уверен что в рамках СОМ технологии.

Я уже отметил, что метод оценки сложности реализации функциональности, который я использовал очень грубый (хотя и адекватный по полученным результатам). Если мы даже немного погрузимся в детали того как выбирается нужный кодек для очередного этапа обработки данных, например декодирования, мы увидим что даже отдельный кодек зависит не только от типа данных в стриме который ему надо обрабатывать но и от того, например, каким образом эти данные ему скармливает предыдущий кодек (например МР4 декодер должен получить данные от файл-реадера который соответствующим образом парсит файл-екстрактит видео и аудио потоки). По поводу всего этого растущего с глубиной реализации многообразия можно отметить, что все это многообразие успешно управляется в рамках концепции COM объектов. COM технологии позволяют поддерживать управляемость кода, избегать древней, но все такой же актуальной проблемы известной под названием DLL HELL.

Я думаю, теперь вполне понятно, что смысл СОМ технологии или концепции состоит в том чтобы разбить решение одной очень объемной задачи, такой как разработка универсального видео плеера на множество подзадач которые можно решить независимо друг от друга. Нетрудно понять, что решение, которое делит огромную монолитную программу на множество независимых компонент и некоторое легковесное ядро для связывания этих компонент в законченное приложение требует поддержки со стороны операционной системы. Операционная система должна обеспечить поиск нужной компоненты для обработки выявленного формата данных, по сути ОС должна поддерживать базу данных исполняемых компонент и их описаний для того чтобы компоненты (обычно в виде ДЛЛ-к) можно было добавлять/регистрировать в этой базе данных, а потом находить и активировать-использовать эти компоненты по системе идентификации определенной в этой базе данных. Система идентификации компонент также является одной из глобальных инфраструктурных функций ОС, компоненты получают идентификаторы не зависимо от того добавлены они уже в базу данных компонент операционной системы или нет.

Фабрики классов и другие паттерны проектирования

Интересно отметить, что, например, применение паттерна проектирования с «фабриками классов» является неотъемлемой частью СОМ технологии. Чтобы иметь возможность создавать объекты классов, реализованных в ДЛЛ-ке по идентификатору (или по некоторой структуре с описанием функциональности требуемого объекта) каждая ДЛЛ-ка реализует один или несколько классов-фабрик для компонент, эти же классы-фабрики вызываются для получения информации о содержимом ДЛЛ-ки при регистрации в базе данных компонент.

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

Третий вопрос: Какие особенности реализации COM Microsoft?

Честно говоря, для меня вопрос выглядит не корректно. На сколько я знаю СОМ технология реализована только Мелко-Мягкими :). А анализ особенностей предполагает сравнение с какой-то другой реализацией, а другой реализации просто не существует, по крайней мере я таких не знаю.

Интересно в качестве ответа на 3-й вопрос попытаться сравнить КОМ технологию с какой-то в чем то сравнимой и/или чем-то похожей технологией. Возьмем для примера (неожиданно) технологию инстанциирования (создания, внедрения, …) объектов-бинов из Java Spring.

MS COM по сути тоже является технологией инстанциирования COM объектов

В какой-то степени Dependency Injection является интерпретацией идей создания объектов класса по его идентификатору, помноженной на идею создания некоторого универсального алгоритма для инстанциирования объектов на основе анализа кода.

Таким образом Dependency Injection для бинов из Java Spring мне представляется в каком то смысле развитием и переносом в новый контекст идей, изначально сформулированных в рамках СОМ технологии. При этом я совершенно не исключаю что СОМ технология также в свое время была развитием и переносом в новый контекст идей, изначально сформулированных где-то еще раньше. Я не историк, я разработчик, историческая точность для меня не стоит на первом месте.

Комментарии (44)


  1. sshikov
    29.05.2023 16:34
    +12

    COM объект – это C++ класс, созданный по правилам COM

    Вот с этой ошибки все и начинается. С нежелания и возможно неумения просто открыть и почитать родную документацию. Хотя бы главную страницу, где написано, что такое данная технология, и зачем она.


    COM — это Component Object Model, и если открыть первую же страницу в поиске по этому сочетанию, то там написано:


    a platform-independent, distributed, object-oriented system for creating binary software components that can interact.

    То есть, это модель компонентов софта, платформо независимая (не то чтобы у них это получилось, но попытки реализации под линукс вроде бы были), распределенная (DCOM), и тут нет ни слова про C++, потому что компоненты эти предполагалось сразу (и можно до сих пор) писать почти на чем угодно. То есть скажем на Perl хотите? Можно и на нем.


    И ровно из всего этого уже логично вытекает все остальное — что есть правила, которые общие для всех языков реализации, и которые можно реализовать на разных языках, поэтому есть отдельный язык описания API, поэтому есть реестр классов, чтобы скриптовые языки типа VB Script могли делать как-то так:


    Set objXL = CreateObject("Excel.Application")


    и работать с функциональностью Excel, который внутри состоит из множества COM компонентов.


    Ну и другие реализации конечно были. Больше всего пожалуй COM похожа на SOM от IBM, которая лежала в основе OS/2, и благополучно почила вместе с ней. А IDL например — вполне в духе CORBA.


    1. rukhi7 Автор
      29.05.2023 16:34
      -1

      Спасибо за замечание - исправил!

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


  1. B13nerd
    29.05.2023 16:34
    +1

    COM объект – это C++ класс

    Поперхнулся и дальше не читал. Ничего, что по мнению создателей "COM is independent of implementation language"?


    1. rukhi7 Автор
      29.05.2023 16:34
      -2

      Действительно я не сталкивался с разработкой СОМ объектов на чем нибудь кроме С++. Я писал DirectShow фильтры. Чесно говоря несколько лет прошло прежде чем я обратил внимание что там используется СОМ в каком то виде.

      Я прошу вас прочитать все таки дальше, я надеюсь что то интересное все таки получится найти.

      Извините что заставил поперхнуться :), но дальше читайте все таки с осторожностью, я надеюсь найдется причина поперхнуться не по поводу ошибки.


  1. aegoroff
    29.05.2023 16:34
    +5

    Ух ты! Давненько не слышал чтобы это кому-либо было нужно, разве что для поддержки легаси. А действительно на этом еще кто-то серьезно разрабатывает? мне казалось что разработка под виндоус уже почти уехала на C#, а что-то низкоуровневое можно и на Win32 API заделать.


    1. rukhi7 Автор
      29.05.2023 16:34
      -1

      Как известно, все новое это хорошо забытое старое. Это не разработка уехала, это разработчики улетели в облака.


      1. aegoroff
        29.05.2023 16:34
        +3

        Т.е. вы на полном серьезе предлагаете вернуться к этому ужасу регистрации COM объектов в реестре, полуавтоматическому управлению памятью, вместо удобного автоматического, предлагаемого .NET, ко всей этой возне с заголовочными файлами и файлами реализации, к более сложному синтаксису C++, по сравнению с C# ну и так далее. Очень напоминает луддитов, которые боролись с неизбежным :)


        1. rukhi7 Автор
          29.05.2023 16:34
          +2

          Вам не предлогаю, а тем кому надо работать с DirectX, например, без этого не обойтись.

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


          1. aegoroff
            29.05.2023 16:34

            Я вроде ни слова не сказал про облака - вы сами придумали это. Я лично имел ввиду классические Windows приложения. Вы их очень легко можете писать с использованием того же WinForms (весьма тонкая обертка над Win32 API) ну или WPF (немного более толстая), разницу в скорости, на более, менее нормальном железе вы не увидите, зато увидите разницу в скорости разработки. Это раз.

            Далее, если уж очень хочется низкоуровщины, - можно и без COM, используя Win32 API, ну а совсем если хотите bleeding edge - можно использовать тот же Rust (за который Microsoft в целом и Марк Руссинович в частности очень сильно топят), тем более что есть вполне сносный крейт для этого (https://crates.io/crates/windows). Вы получите и современный язык, без кучи тараканов, и отсутствие сборки мусора, за что вы сильно переживаете. Это два


            1. rukhi7 Автор
              29.05.2023 16:34
              +1

              про облака - это мне так показалось - это да.

              WPF вроде как обертка не над Win32 API, а над DirectX-м.

              По поводу: хочется низкоуровщины, это вроде как вы немного передергиваете, ее никогда не хочется, с ней приходится иметь дело. Если вы нашли способ работать не вспоминая про низкоуровневые проблемы, ну хорошо. Но ведь кто то эту низкоуровщину вам обеспечивает, а у вас это звучит так что это какая то грязная работа недостойная светлых разработчиков.

              Сборка мусора меня ни в каком виде не беспокоит, меня беспокоит что обсуждение сводится только к обсуждению ее наличия.

              И тараконов можно развести на любом языке, это не от языка зависит, а от того кто на нем пишет, я так думаю.


        1. KanuTaH
          29.05.2023 16:34
          +2

          удобного автоматического, предлагаемого .NET

          Это там, где момент уничтожения объекта в общем случае предсказать невозможно, а вместо полноценного RAII костыль в виде IDisposable? Спасибо, конечно, но... Мягко говоря, это не всем подходит.


          1. nronnie
            29.05.2023 16:34

            IDisposable.Dispose() это, по сути, и есть "уничтожение объекта". А GC это всего лишь уплотнение кучи. Можно сказать, что такого как "освобождение памяти" в .NET просто нет - куча просто уплотняется и все.


            1. KanuTaH
              29.05.2023 16:34
              +1

              Ага, только вот это именно что нисколько не удобный и отнюдь не автоматический костыль, сделанный с расчётом на то, что "конечный пользователь" класса, реализующего IDisposable, не забудет обернуть его в using.


            1. aegoroff
              29.05.2023 16:34

              А GC это всего лишь уплотнение кучи

              Это далеко не всегда так. Куча уплотняется лишь при сборке мусора второго поколения, при этом останавливаются все рабочие потоки. В нулевом и первом поколении никакого уплотнения нет. Далее, куча больших объектов (более 85000 байт) или LOH вообще не трогается (это слишком накладно двигать такие объекты), а учитывая что наверно 99% в ней это массивы и другие коллекции (мне сложно представить себе обычный объект такого размера), со временем, при длительно работающем процессе, который выделяет много подобных объектов, становящихся затем мусором - легко можно получить неслабую такую фрагментацию этой кучи и как следствие постоянный рост рабочего набора процесса. В общем, не так все радужно и с автоматическим мусоровозом.


          1. aegoroff
            29.05.2023 16:34

            Это там, где момент уничтожения объекта в общем случае предсказать невозможно

            А это и не нужно для чисто managed объектов

            а вместо полноценного RAII костыль в виде IDisposable

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

            Мягко говоря, это не всем подходит.

            Да, это совсем не нужно использовать для освобождения классических managed ресурсов, да и невозможно это с этим паттерном в принципе.

            Детальнее о работе с памятью стоит прочитать книгу К. Кокосы, она вроде так и называется, - управление памятью в .NET, и есть очень неплохой русский перевод.

            Прочтение откроет вам глаза на то как ДЕЙСТВИТЕЛЬНО все работает


            1. KanuTaH
              29.05.2023 16:34
              +1

              этот паттерн придуман не для этого

              Для чего "этого"? Этот паттерн придуман, чтобы имитировать в C# RAII из нормальных языков (так же как и try-with-resources в Java), но, как водится, не без колхоза, причем до появления using нужно было вообще писать try/finally блок для IDisposable вручную (собственно, using и есть синтаксических сахар для такого блока).

              Прочтение откроет вам глаза на то как ДЕЙСТВИТЕЛЬНО все работает

              Спасибо, я в курсе, как ДЕЙСТВИТЕЛЬНО все работает.


              1. aegoroff
                29.05.2023 16:34

                Откуда такая агрессия?

                ричем до появления using нужно было вообще писать try/finally блок для IDisposable вручную

                using был с самого начала https://www.ecma-international.org/wp-content/uploads/ECMA-334_1st_edition_december_2001.pdf страница 200 (в pdf файле страница 214). Потрудились бы для начала стандарт почитать, прежде чем писать такую ересь - перехожу на ваши методы разговора, уж простите


                1. KanuTaH
                  29.05.2023 16:34

                  Откуда такая агрессия?

                  Какая агрессия?

                  using был с самого начала

                  Да, действительно, using statement был доступен в C# с самой первой его версии, это у меня видимо история его появления как-то пересеклась в голове с историейtry-with-resourcesиз Java, который служит аналогичным целям является аналогичным костылем, но появился лишь в Java 7.


              1. nronnie
                29.05.2023 16:34

                причем до появления using нужно было вообще писать try/finally блок для IDisposable вручную

                Ого... Это когда такое было-то??? Оно там с самой первой версии - погуглите ECMA-334 от 2001 года. Эксперты дотнета, блин. Фейспалм.


                1. KanuTaH
                  29.05.2023 16:34

                  Костыль - он и есть костыль, неважно, когда он появился.


                  1. nronnie
                    29.05.2023 16:34

                    Хорошо, будь по вашему. Пускай будет костыль. :))


        1. verh010m
          29.05.2023 16:34
          +2

          .NET много где использует COM - оно никуда не делось. Нам дали толстоватую обертку над многими вещами и кое кто теперь думает, что COM отмер


          1. megasuperlexa
            29.05.2023 16:34

            "много где" - а можно перечислить хотя бы 3-5 "где"?


            1. rukhi7 Автор
              29.05.2023 16:34

              это даже я вам скажу: вроде как и Excel и Word никуда не делись, и DirectShow вроде никто не отменил, все это все также связано с СОМ спецификацией, все это доступно из .NET

              так же как какой нибудь 17, 22, 25 С++ стандарт не отменяет самый исходный С++ стандарт, так же и СОМ спецификацию никто не отменяет, она все также лежит в основе практически всех технологий на Windows.


              1. megasuperlexa
                29.05.2023 16:34

                офис и директшоу - это и было "много где"?

                ок


                1. Chaos_Optima
                  29.05.2023 16:34
                  +1

                  ок DirectX например


                1. rukhi7 Автор
                  29.05.2023 16:34

                  Причем DirectX аж с неизбежностью (inevitably):

                  COM is an object-oriented programming model used by several technologies, including the bulk of the DirectX API surface. For that reason, you (as a DirectX developer) inevitably use COM when you program DirectX.


  1. NeoCode
    29.05.2023 16:34

    Идея то была хорошая, а вот реализация уж больно запутанная. Наверное следствие того, что тогда все делалось на весьма низкоуровневом С++.


    1. nronnie
      29.05.2023 16:34
      -1

      В СОМ была, к сожалению, такая изначально порочная и, как показало дальнейшее развитие, тупиковая вещь, как управление памятью с помощью подсчета ссылок.


      1. rukhi7 Автор
        29.05.2023 16:34
        +2

        Интересно чего же в ней тупикового? То что она работает уже 25 лет и всегда будет работать? То что она позволяет собственную, абсолютно контролируемую, стратегию управления памятью реализовать?


        1. nronnie
          29.05.2023 16:34
          -1

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


          1. rukhi7 Автор
            29.05.2023 16:34
            +1

            А не надо в циклах объекты создавать, это очень плохо для производительности в том числе. Поэтому когда что-то вот так превращается в ад, это не ссылки виноваты, а какая-то прокладка между креслом и монитором. Не обязательно та прокладка которая это разбирает, пытается смягчить :))) .


            1. nronnie
              29.05.2023 16:34

              Так ведь не объекты в циклах, а циклические связи между объектами: A -> B -> C -> A


              1. rukhi7 Автор
                29.05.2023 16:34

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


                1. nronnie
                  29.05.2023 16:34

                  ОК :))


      1. aegoroff
        29.05.2023 16:34
        +3

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

        Хм, а как же Rust с его Rc (и потокобезопасным Arc)? Это ведь тоже умный указатель со счетчиком ссылок. Все таки не такая и тупиковая вещь, как может показаться


      1. Chaos_Optima
        29.05.2023 16:34

        С чего это тупиковая вещь? На С++ это чуть ли не обязаловка, управление памятью напрямую организуется обычно в исключительных целях, и считается плохим тоном в реалиях современной разработки на С++.


        1. nronnie
          29.05.2023 16:34
          -1

          В С++ просто альтернативы нет. Из-за его низкоуровневой природы указателей. А, вот, в JavaScript (точнее в его распространенных реализациях), как раз, от подсчета ссылок в свое время отказались и переделали все на GC.


          1. rukhi7 Автор
            29.05.2023 16:34

            применение сборщиков мусора это, конечно не та тема, которую я хотел бы видеть в рамках обсуждения этой статьи.

            Хотелось бы что то про сложность реализации, критерии ее расчета, сложность реализации кода в соответствии с СОМ спецификацией, ... про dependency injection наконец.

            Вот, сдается мне, это облачные технологии плохо влияют на способности программистов, все сводится к тому, как бы найти то, что сделает всю работу за нас.


          1. Chaos_Optima
            29.05.2023 16:34

            Потому что там и нет в этом особой нужды, JS язык не для производительности кода. И в С++ были альтернативы да и сейчас есть всякие версии сборщиков мусора, только они не приживаются, потому что сборка мусора отнимает производительность (ну или ручное управление памятью). А если например использовать только unique_ptr то вообще можно получить подобие rust.


    1. rukhi7 Автор
      29.05.2023 16:34

      Интересно а для какой идеи такого уровня вы видели не запутанную реализацию?

      Потом почему идея "была"? Если кто-то решил на какую то идею забить, это не значит что она для всех пропала.

      Как говорится:

      что один человек придумал, другой завсегда разобрать сможет!


  1. nronnie
    29.05.2023 16:34
    +3

    Статья припозднилась лет, этак, на 25, а в остальном все более-менее ок :))


  1. Tinkz
    29.05.2023 16:34
    +2

    Когда-то давно разрабатывал под COM на паскале (дельфи). До сих пор осталось несколько книжек. В одной, как сейчас помню, написано что-то вроде: "Вот-вот COM заработает на макос". Сейчас это, разве что, в экселе можно встретить.


  1. itHauntsMe
    29.05.2023 16:34

    Ещё читал про XPCOM от Mozilla, но ни разу не видел в использовании. Жаль, что технология не получила развития.