COM-объекты и интерфейсы
COM — это технология, которая позволяет объектам взаимодействовать между процессами и границами компьютеров так же легко, как в рамках одного процесса. Com позволяет это сделать, указав, что единственный способ управления данными, связанными с объектом, — это интерфейс объекта. Если этот термин используется в этой документации, он ссылается на реализацию в коде бинарного интерфейса COM, связанного с объектом.
COM использует интерфейс слова в некотором смысле, отличающийся от того, который обычно используется в программировании на Visual C++. Интерфейс C++ ссылается на все функции, поддерживаемые классом и которые клиенты объекта могут вызывать для взаимодействия с ним. COM-интерфейс ссылается на предопределенную группу связанных функций, реализуемую классом COM, но конкретный интерфейс не обязательно представляет все функции, поддерживаемые классом.
Ссылка на объект, реализующий интерфейс, означает, что объект использует код, который реализует каждый метод интерфейса и предоставляет двоичные указатели COM на эти функции в библиотеку COM. Затем COM делает эти функции доступными для любого клиента, который запрашивает указатель на интерфейс, независимо от того, находится ли клиент внутри или за пределами процесса, реализующего эти функции.
Что такое COM объект, как происходит его разработка, какие особенности реализации COM Microsoft?

1) Еще одна безумная инкарнация попытки микрософта по встраиванию одной программы в другую. До этого были DDE, OLE, ActiveX и прочий зоопарк. Про это даже легенды слагают.
- Вконтакте


Армянское Радио, ну что такое. это эволюцией называется.
Java++ называлась их реинкарнация Java.
Концепция OLE была расширена до COM, который подразумевает не только то, что делал OLE, который да, изначально был предложен командой Офиса.
ActiveX — это больше маркетинговое название, с технической точки зрения обычно означает — компонент COM, который может встраиваться и активироваться в COM-контейнере путем реализации некоторых интерфейсов. COM+ и DCOM — это про межпроцессорное взаимодействие, в т.ч. по сети.
всё это успешно работает до сих пор.
разработка и использование COM-серверов на VB и Делфи не стоила ничего.
разработка и использование COM-серверов на .Net сейчас не стоит ничего.
задаётся декларативно.
бинарные протоколы и форматы, так понятно, что они эффективней по ресурсам, чем текстовые. а машины тогда какие были. я не говорю, что сейчас так надо делать, но они всё равно всегда будут быстрее, в т.ч. и сейчас.
COM — это соглашение про то, как надо делать. ООП в абстракции от различных ЯП. вносит минимальный оверхед при решении задач, которые требовалось решить.
это было отличное решение для своего времени и шаг в правильном направлении.
тогда была только еще одна реализация этого подхода — Corba.
точнее Visual J++, забыл уже.

По ресурсам на разработку, внедрение, развитие и поддержку, они категорически проигрывают текстовым. В вопросе речь идет как раз о разработке.
А если вы пытаетесь соединить, например, по сети, тупоконечнкую архитектуру с остроконечной, вам придется каждое, мать его, целочисленное значение перетряхивать.
А потом у вас еще будет x32/x64 битные архитектуры, это просто праздник.
Собственно, по этой причине нынче популярно бросаться XML/JSON, которые давлены GZIP, а не изобретать бинарный формат.
Работа с COM-объектами

проектировалась с целью дать возможность создавать компоненты на любом языке/платформе, обладающем поддержкой этой модели, и использовать их в любом языке/платформе (другом), так же обладающем поддержкой COM. Платформа .NET не исключение и позволяет легко использовать сторонние COM-объекты и экспортировать типы .NET в виде COM-объектов.
Суть организации взаимодействий с COM-объектами та же, что и при использовании механизма P/Invoke: вы объявляете управляемое представление COM-объекта, а среда выполнения CLR создает объект-обертку, реализующий маршалинг. Существует две разновидности оберток: обертка, вызываемая средой выполнения (Runtime Callable Wrapper, RCW), которая позволяет управляемому коду использовать COM-объекты:

и обертка, вызываемая COM-объектами (COM Callable Wrapper, CCW), дающая возможность COM-объектам вызывать управляемый код:

Сторонние COM-объекты часто поставляются вместе с основной сборкой взаимодействий (Primary Interop Assembly, PIA), содержащей определения, одобренные производителем, подписанной и устанавливаемой в глобальный кеш сборок (Global Assembly Cache, GAC). В противном случае можно воспользоваться инструментом tlbimp.exe, являющийся частью Windows SDK, который автоматически генерирует сборку взаимодействий, опираясь на информацию, содержащуюся в библиотеке типов.
При взаимодействиях с COM-объектами повторно используется инфраструктура маршалинга параметров механизма P/Invoke, но с иными умолчаниями (например, по умолчанию строки преобразуются в тип BSTR), поэтому все советы, что были даны в предыдущей статье относительно механизма P/Invoke, также применимы и здесь.
Модель COM имеет собственные проблемы производительности, обусловленные характерными особенностями COM, такими как многопоточная модель подразделений и несогласованность между природой COM, основанной на подсчете ссылок, и моделью сборки мусора в .NET.
Управление жизненным циклом
Получая ссылку на COM-объект в .NET, вы фактически получаете ссылку на объект-обертку RCW. Обертка RCW всегда хранит единственную ссылку на COM-объект и для каждого COM-объекта создается только один экземпляр объекта-обертки RCW. Обертка RCW поддерживает собственный счетчик ссылок, не связанный со счетчиком ссылок COM-объекта. Значение этого счетчика ссылок обычно равно 1, но может быть больше, при участии в маршалинге большего числа интерфейсов или когда к одному и тому же интерфейсу обращается несколько потоков выполнения.
Как правило, когда удаляется последняя управляемая ссылка на RCW, в следующем же цикле сборки мусора в поколении, где находится обертка RCW, вызывается финализатор RCW, который уменьшает счетчик ссылок в COM-объекте (который имеет значение 1) вызовом метода Release() интерфейса IUnknown этого COM-объекта. COM-объект тут же уничтожает себя и освобождает занимаемую им память.
Поскольку сборщик мусора в .NET запускается в непредсказуемые моменты времени и не знает о блоках неуправляемой памяти, выделенных при создании оберток RCW для COM-объектов, он не может ускорить сборку мусора, вследствие чего объем занимаемой памяти может оказаться очень большим.
При необходимости можно вызвать метод Marshal.ReleaseComObject(), чтобы явно освободить объект. Каждый вызов уменьшает счетчик ссылок в RCW и когда он достигнет нуля, автоматически уменьшается счетчик ссылок в соответствующем COM-объекте (точно так же, как при вызове фииализатора RCW). После вызова метода Marshal.ReleaseComObject() нельзя использовать обертку RCW.
Если после вызова счетчик ссылок RCW может оказаться больше нуля, метод Marshal.ReleaseComObject() следует вызывать в цикле, пока он не вернет нулевое значение. Лучше всего вызывать Marshal.ReleaseComObject() внутри блока finally, чтобы гарантировать освобождение COM-объекта, даже если где-то между созданием его экземпляра и освобождением возникнет исключение.
Маршалинг через границы подразделений
Модель COM реализует собственные механизмы синхронизации потоков выполнения для поддержки вызовов между разными потоками, которые могут использоваться даже при работе с объектами, изначально не предназначенными для использования в многопоточной среде. Эти механизмы могут снижать производительность при неправильном их применении. Хотя эта проблема не имеет прямого отношения к взаимодействиям с COM-объектами из .NET, тем не менее, ее стоит обсудить, потому что с ней часто сталкиваются на практике, вероятно потому, что разработчики, привыкшие к типичным приемам синхронизации в .NET могут не знать, что конкретно происходит под покровом COM-объектов.
Модель COM связывает объекты и потоки выполнения с подразделениями (apartments), служащими границами, через которые модель COM выполняет вызовы. Всего имеется несколько типов подразделений:
Однопоточные подразделения (Single-Threaded Apartment, STA)
В каждом подразделении имеется единственный поток выполнения, но может иметься любое количество объектов. В процессе может быть несколько подразделений STA.
Многопоточные подразделения (Multi-Threaded Apartment, МТА)
В каждом подразделении может иметься любое количество потоков выполнения и объектов, но в процессе может быть только одно подразделение МТА. Этот тип используется в .NET по умолчанию.
Потоконезависимые подразделения (Neutral-Threaded Apartment, NTA)
Содержат объекты, но не потоки. В процессе может быть только одно подразделение NTA.
Связывание потока выполнения с подразделением происходит при вызове CoInitialize или CoInitializeEx для инициализации COM-объекта в этом потоке. Функция CoInitialize связывает поток с новым подразделением STA, а функция CoInitializeEx позволяет указать тип подразделения, STA или МТА.
В .NET вам не придется вызывать эти функции непосредственно, вместо этого достаточно добавить атрибут STAThread или MTAThread к точке входа в поток (методу Main). При желании можно также вызвать метод Thread.SetApartmentState() или установить значение в свойстве Thread.ApartmentState перед запуском потока выполнения. Если не указано иное, .NET инициализирует потоки (включая главный поток приложения) как принадлежащие подразделению МТА.
Связывание COM-объектов с подразделениями выполняется, исходя из параметра ThreadingModel в реестре, который может иметь следующие значения:
Single — объект по умолчанию помещается в подразделение STA.
Apartment — объект должен быть помещен в любое подразделение STA, и только потоку из этого подразделения будет позволено вызывать объект непосредственно. Другие экземпляры могут помещаться в другие подразделения STA.
Free — объект помещается в подразделение МТА. Этот объект может вызываться непосредственно и одновременно из любого количества потоков в подразделении МТА. Объект должен обеспечивать поддержку использования в многопоточной среде.
Both — объект помещается в подразделение создавшей его программы (STA или МТА). По сути, после создания он становится STA- или МТА-подобным объектом.
Neutral — объект помещается в потоконезависимое подразделение и не требует маршалинга. Это — наиболее эффективный режим.
На рисунке ниже изображена схема взаимоотношений между подразделениями, потоками и объектами:

При попытке создать объект с моделью поддержки потоков, не совместимой с моделью потоков в текущем подразделении, вы получите указатель на интерфейс, который в действительности указывает на прокси-объект. Если потребуется передать интерфейс COM-объекта другому потоку, принадлежащему другому подразделению, указатель на интерфейс должен передаваться не напрямую, а через механизм маршалинга. Инфраструктура COM вернет соответствующий прокси-объект.
В процессе маршалинга вызов функции (включая параметры) преобразуется в сообщение, которое будет послано в очередь принимающего подразделения STA. Для объектов STA очередь реализуется как скрытое окно, оконная процедура которого принимает сообщения и передает COM-объекту с помощью заглушки (stub). При таком подходе COM-объекты в подразделении STA COM всегда вызываются в одном и том же потоке выполнения, благодаря чему обеспечивается безопасность при работе в многопоточном окружении.
Если вызывающее подразделение не совместимо с подразделением COM-объекта, происходит переключение потока и выполняется маршалинг параметра между потоками.
Чтобы избежать падения производительности из-за маршалинга между потоками, старайтесь обеспечить соответствие между подразделением COM-объекта и подразделением создающего его потока. Создавайте и используйте COM-объекты STA в потоках из подразделения STA, а COM объекты из подразделения МТА — в потоках МТА. COM-объекты, помеченные, как поддерживающие оба типа подразделений, могут свободно использоваться из любых потоков выполнения без лишних накладных расходов.
Вызов объектов STA из ASP.NET
По умолчанию среда ASP.NET выполняет страницы в потоках МТА. Если из этих страниц вызываются объекты, находящиеся в подразделениях STA, в дело вступает механизм маршалинга. Если основная масса используемых объектов принадлежит подразделениям STA, это приведет к деградации производительности. Эту проблему можно ликвидировать, пометив страницы атрибутом AspCompat, как показано ниже:
Обратите внимание, что конструкторы страниц все еще выполняются в потоке выполнения МТА, поэтому создание объектов STA следует выполнять в обработчиках событий Page_Load и Page_Init.
Импортирование библиотек типов и Code Access Security
Механизм Code Access Security выполняет те же проверки безопасности, что и P/Invoke. Вы можете добавлять ключ /unsafe при вызове утилиты tlbimp.exe, которая будет добавлять атрибут SuppressUnmanagedCodeSecurityAttribute к сгенерированным типам. Используйте эту возможность только в системах, пользующихся у вас безусловным доверием, так как она может порождать проблемы безопасности.
NoPIA
До выхода версии .NET Framework 4.0 приходилось вместе с приложением распространять сборки взаимодействий или основные сборки взаимодействий (Primary Interop Assemblies, PIA). Эти сборки обычно получались очень большими (даже в сравнении с кодом, использующим их) и как правило не входят в установочный комплект COM-компонентов; вместо этого их необходимо устанавливать отдельно, потому что сами они не требуются для работы самих COM-объектов. Другая причина, почему сборки PIA не включаются в установочные комплекты, состоит в том, что они устанавливаются в глобальный кеш сборок (GAC). Это вводит зависимость от .NET Framework в иначе полностью независимые приложения.
Начиная с версии .NET Framework 4.0, компиляторы C# и VB.NET могут проверить, какие COM-интерфейсы и методы используются в коде, и скопировать и встроить в вызывающую сборку только действительно необходимые определения, уменьшая размер кода и избавляя от необходимости распространять библиотеки PIA. В Microsoft эта особенность была названа NoPIA. Она действует как в отношении основных сборок взаимодействий, так и в отношении сборок взаимодействий в целом.
Сборки PIA обладают одной важной особенностью, которая называется эквивалентностью типов. Так как они имеют строгое именование и помещаются в глобальный кеш сборок, различные управляемые компоненты могут обмениваться обертками RCW и с точки зрения .NET они будут иметь эквивалентные типы. Напротив, сборки взаимодействий, сгенерированные с помощью tlbimp.exe, не обладают такой особенностью, так как каждый компонент в этом случае получит собственную, отдельную от других, сборку взаимодействий. С появлением поддержки особенности NoPIA отпала необходимость в строгом именовании сборок, и в Microsoft было предложено решение, позволяющее интерпретировать обертки RCW из других сборок, как принадлежащие тому же типу, если интерфейсы имеют одинаковый идентификатор GUID.
Чтобы включить поддержку NoPIA, выберите пункт Properties в контекстном меню Visual Studio после щелчка правой кнопкой мыши на сборке взаимодействий в разделе References, и установите параметр Embed Interop Types (Внедрять типы взаимодействий) в значение True:

Исключения
Большинство методов COM-интерфейсов сообщают об успехе или неудаче, возвращая значение типа HRESULT. Отрицательные значения HRESULT (с установленным старшим битом) сообщают об ошибке, а ноль (S_OK) или положительные значения — об успехе. Кроме того, COM-объект может возвращать дополнительную информацию об ошибке при вызове функции SetErrorInfo, передавая объект IErrorInfo, созданный вызовом CreateErrorInfo.
При вызове COM-метода через механизм взаимодействий с COM, заглушка маршалера преобразует значение HRESULT в управляемое исключение, согласно самому значению HRESULT и данным, содержащимся в объекте IErrorInfo. Поскольку возбуждение исключения является достаточно дорогостоящей операцией, функции COM-объекта, которые часто терпят неудачу, могут отрицательно сказываться на производительности. Вы можете подавить автоматическое преобразование исключений, пометив методы атрибутом PreserveSigAttribute. При этом вам придется изменить управляемую сигнатуру, как возвращающую значение типа int, в результате чего параметр retval станет параметром out.