Что такое Reg-Free COM — механизм использования COM без регистрации
· Го Комура · COM, Reg-Free COM, Registration-Free COM, Разработка Windows, Устаревшие технологии
В проектах с COM / ActiveX / OCX при каждом развёртывании и обновлении всплывает одна и та же грязь.
- нужен
regsvr32 - почти всегда требуются права администратора
- возникает конфликт с другой версией, установленной другим приложением
- удаление приложения задевает и другие продукты
- работает на машине разработчика, но не работает в чистом окружении
Значительно уменьшить эту трясину помогает Reg-Free COM. Правда, вопреки названию, это не «волшебство, которое полностью избавляет от всех хлопот с COM». Оно избавляет в первую очередь от хлопот, связанных с глобальной регистрацией. Сложности с разрядностью (bitness), зависимыми DLL, типовыми библиотеками и моделью потоков никуда не исчезают.
В этой статье Reg-Free COM рассматривается прежде всего в контексте использования COM DLL / OCX в Windows-десктоп-приложениях с их хранением локально для приложения.
1. Сначала — вывод (коротко)
Начнём с грубой, но полезной формулировки.
- Reg-Free COM — это способ хранить регистрационную информацию COM не в реестре, а в манифесте
- Во время выполнения при разрешении
CoCreateInstanceилиCLSIDFromProgIDсначала проверяется контекст активации (activation context) - Благодаря этому COM DLL / OCX можно хранить private для каждого приложения
- Основные преимущества — это удобство XCOPY-распространения, более лёгкое предотвращение конфликтов версий и меньший риск поломки при удалении
- Однако проблема 32-бит / 64-бит никуда не исчезает. Здесь одним усердием её не преодолеть
- Кроме того, отдельно нужно продумывать зависимые DLL, типовые библиотеки, проектные ссылки и зависимость от нестандартной регистрации
- На практике это отлично подходит, когда нужно разместить рядом с приложением COM-компоненты, предназначенные только для него
Иными словами, Reg-Free COM — это механизм, который возвращает активацию COM на уровень отдельного приложения.
2. Что этот текст понимает под Reg-Free COM
Reg-Free COM — сокращение от Registration-Free COM. По-японски это иногда описывают как «COM без регистрации».
«Без регистрации» здесь означает, что для использования COM не требуется полностью полагаться на глобальную регистрацию в реестре — HKCR / CLSID / InprocServer32 и подобное.
Это не значит, что сам COM исчезает, и не значит, что GUID становится не нужен.
Основные предметы рассмотрения в этой статье — вот такие:
- нативные COM DLL
- COM-серверы на базе ATL
- ActiveX / OCX
- COM-взаимодействие на базе .NET Framework
- публикация через COM host в .NET 5+ / .NET 8
И наоборот, есть два момента, которые в этой статье хочется особо подчеркнуть.
- Reg-Free COM — это разговор об «активации»
- Распространение типовой информации и настройка проектных ссылок могут оставаться отдельным вопросом
Если смешать эти темы, разговор становится куда более мутным.
3. Сначала — общая картина на одной странице
Быстрее всего сначала взглянуть на общую картину на одной странице.
flowchart LR
APP["MyApp.exe"] --> AM["Application Manifest"]
AM --> DEP["dependentAssembly"]
DEP --> CM["Component / Assembly Manifest"]
CM --> META["file / comClass / typelib"]
META --> DLL["VendorControl.dll / .ocx"]
APP --> ACTX["Activation Context"]
ACTX --> COM["CLSIDFromProgID / CoCreateInstance"]
COM --> DLL
В обычном COM при вызове CoCreateInstance для определения того, какую DLL загрузить, происходит обход реестра.
В Reg-Free COM перед этим сначала проверяется текущий активный контекст активации, и разрешение выполняется по манифестной информации, записанной в нём.
Из-за этого приложениям A и B на одной машине становится проще работать, используя разные версии COM-компонентов одного семейства. Это немного возвращает культуру совместного использования COM в сторону локальности для конкретного приложения.
4. Почему обычное распространение COM обычно оказывается тяжёлым
Обычное распространение COM тяжело не столько из-за самого COM, сколько из-за допущения о глобальной регистрации.
Чтобы использовать класс COM, требуется примерно такая информация.
| Информация | Роль |
|---|---|
| CLSID | GUID, однозначно идентифицирующий класс |
| ProgID | Удобное для человека имя |
| InprocServer32 | Какую DLL загружать |
| ThreadingModel | Допущения вроде Apartment / Both |
| TypeLib | Информация о типах |
Когда всё это попадает в реестр, это удобно для машины в целом, потому что легко использовать совместно из нескольких приложений.
Однако на практике это совместное использование даёт обратный эффект.
- установка одного продукта перезаписывает COM-регистрацию другого продукта
- деинсталлятор «думает, что удаляет только своё», а на деле ломает общий COM
- регистрация, которая случайно присутствует на машине разработчика, отсутствует на боевой машине
- регистрации для 32-бит и 64-бит не согласуются друг с другом, и только симптомы жутковато расходятся
Иными словами, людей куда чаще беспокоит не сам COM, а модель распространения. Reg-Free COM — это механизм, который снижает боль именно этой модели распространения.
5. Как работает Reg-Free COM
5.1 Указываем зависимости в манифесте приложения
Сначала приложение указывает в манифесте приложения, от каких side-by-side сборок оно зависит.
Этот манифест можно оформить любым из двух способов:
- разместить рядом с EXE-файлом, например как
MyApp.exe.manifest - встроить в EXE как ресурс
На практике часто выбирают так: внешний файл — если важно, чтобы распространение и замена были наглядными, встраивание — если в приоритете надёжность и простота распространения.
Отметим, что если существуют одновременно и внешняя, и встроенная версия, приоритет имеет манифест на файловой системе.
5.2 Описываем информацию о COM в манифесте компонента
Далее COM-сторона переносит информацию, которая раньше находилась в реестре, в манифест компонента.
Сюда входит, например, такая информация:
comClassclsidprogidthreadingModeltypelib- при необходимости —
proxy/stub, классы окон и т. п.
То есть идея в том, чтобы описывать «облик» COM на XML вместо реестра.
Этот манифест также можно оформить любым из двух способов:
- разместить отдельным файлом рядом с DLL
- встроить в DLL как ресурс
На практике встраивание в DLL в качестве private assembly обычно приводит к меньшему числу проблем. Работа с отдельным файлом нагляднее, но легче споткнуться о соответствие между именем файла и assemblyIdentity, о место размещения и о забытые копирования.
5.3 Во время выполнения сначала проверяется контекст активации
Здесь заключена суть Reg-Free COM.
Когда приложение вызывает CLSIDFromProgID или CoCreateInstance, среда выполнения COM смотрит на активный контекст активации.
Если там есть нужная информация ProgID → CLSID и CLSID → DLL, разрешение выполняется без обращения к реестру.
И наоборот, если манифесту не хватает нужной информации, происходит откат к обычному разрешению на основе регистрации. Из-за такого поведения возникает ловушка: на машине разработчика приложение случайно работает. Кажется, что переход на Reg-Free состоялся, а на самом деле дело в том, что помогает локальная регистрация.
Это самая коварная ловушка Reg-Free COM.
6. В чём польза
На практике преимущества Reg-Free COM видны вполне отчётливо.
6.1 Удобное XCOPY-распространение
Все нужные файлы можно собрать вместе в папке приложения, что облегчает установщик и процедуру регистрации.
Разумеется, если запись идёт в Program Files, вопрос прав доступа остаётся отдельной темой, но по крайней мере административную работу, связанную с регистрацией COM, обычно удаётся сократить.
6.2 Легче сократить конфликты версий
Даже если на одной машине присутствует несколько версий COM-компонента, становится проще развести используемую версию по приложениям. Заметно легче избежать неприятности вроде «поведение внезапно изменилось из-за установки другого продукта».
6.3 Часто не требует крупных изменений в существующем коде
Reg-Free COM — это механизм, который меняет способ разрешения, а не в корне переделывает то, как существующий код делает вызовы.
Поэтому при удачном сценарии его можно внедрить, почти не трогая код на стороне CoCreateInstance.
6.4 Удаление и откат становятся проще
Поскольку всё замкнуто на уровне приложения, обновление и откат становятся заметно более прямолинейными. Утрируя, можно сказать, что легче принять подход «просто заменить всю папку целиком».
7. Где это подходит, а где — нет
7.1 Ситуации, где это подходит
В следующих случаях Reg-Free COM оказывается весьма сильным решением.
| Ситуация | Насколько подходит |
|---|---|
| Нужно поставлять COM DLL / OCX, предназначенные только для конкретного приложения | Очень хорошо |
| Нужно, чтобы на одном ПК сосуществовало несколько версий | Очень хорошо |
| Нужно избежать проблем с регистрацией компонентов от поставщика | Хорошо |
| Нужно использовать ActiveX / OCX приватно в существующем десктопном приложении | Хорошо |
| Нужно облегчить распространение, не меняя сильно существующие вызовы | Хорошо |
Как правило, это хорошо сочетается с бизнес-десктоп-приложениями, инструментами интеграции с оборудованием и существующими наработками на VB6 / MFC / WinForms.
7.2 Ситуации, где это не подходит или требует осторожности
С другой стороны, есть случаи, которые стоит рассматривать осторожнее.
| Ситуация | Комментарий |
|---|---|
| Нужно, чтобы COM был общим для всей машины | Польза Reg-Free невелика |
| Разрядность (bitness) не совпадает | Reg-Free это не решает |
| Сильная зависимость от нестандартной регистрационной информации или собственного установщика | Трудно выразить в манифесте |
| Не продумано распространение зависимых DLL или среды выполнения VC++ | В итоге споткнётесь в другом месте |
| Проектные инструменты или настройка ссылок в IDE предполагают наличие реестра | Нужен отдельный порядок эксплуатации |
Особенно важен последний пункт. Reg-Free COM помогает с активацией во время выполнения, но не меняет одним махом то, на что рассчитан UI настройки ссылок на этапе проектирования.
8. Распространённые заблуждения
8.1 «С Reg-Free COM проблема разрядности исчезает»
Не исчезает. 32-битный процесс может загружать только 32-битные in-proc COM DLL, а в 64-битный попадают только 64-битные DLL. В этом отношении Reg-Free ничего не меняет по сравнению с прежним подходом.
8.2 «С Reg-Free COM реестр вообще не используется»
Это тоже неверно. Если манифесту не хватает нужной информации, происходит откат к обычному разрешению на основе регистрации. Поэтому успешный запуск на машине разработчика ещё не означает, что конфигурация Reg-Free корректна.
8.3 «С Reg-Free COM вопрос типовых библиотек тоже решается автоматически»
Здесь верно лишь наполовину.
В манифесте действительно можно указать информацию typelib, но работа с типовой информацией — настройка ссылок в VBA, #import в C++, генерация проектных ссылок на стороне .NET — обычно требует отдельного продумывания.
Reg-Free COM в первую очередь про то, чтобы приложение вообще запускалось. Как вести типизированную разработку — это следующий, отдельный вопрос.
8.4 «С Reg-Free COM подойдёт любой ActiveX / OCX как есть»
Это тоже опасное заблуждение. Если компонент опирается на стандартную регистрационную информацию COM, продвигаться легко, но если он сильно зависит от собственных настроек реестра, дополнительной установки, обработки лицензий или набора других модулей, переход на Reg-Free резко усложняется.
8.5 «Reg-Free COM в .NET Framework и .NET 8 — примерно одно и то же»
Сходство есть, но набор инструментов заметно различается.
Контекст .NET Framework + RegAsm и контекст .NET 5+ / .NET 8 + comhost — это разные площадки, даже если речь об одном и том же COM.
9. Различия между нативным COM, .NET Framework, .NET 5+ и .NET 8
Здесь легко всё перепутать, поэтому разберём отдельно.
| Направление | Краткое описание |
|---|---|
| Нативные COM DLL / OCX | В основе — связка манифеста приложения и манифеста компонента |
| COM-взаимодействие на базе .NET Framework | Помимо манифеста приложения в стиле Win32, нужен ещё и манифест на стороне управляемого компонента |
| Публикация COM в .NET 5+ / .NET 8 | EnableComHosting создаёт COM host, а EnableRegFreeCom позволяет сгенерировать манифест для Reg-Free |
9.1 COM на базе .NET Framework
В COM на базе .NET Framework образуется двухуровневая структура: манифест приложения в стиле Win32 на стороне COM-приложения и манифест компонента на стороне управляемого компонента.
Это чуть сложнее, чем в случае нативного COM. Разговор снова слегка «увязает» в тот момент, когда «Reg-Free COM вроде понятен, но как только в дело вступает managed component, внезапно появляется ещё один манифест».
9.2 Публикация COM в .NET 5+ / .NET 8
В .NET 5+ / .NET 8 точкой входа для публикации COM становится *.comhost.dll.
Если дополнительно указать EnableRegFreeCom=true, будет сгенерирован side-by-side манифест для Reg-Free COM.
Но и здесь важно, что Reg-Free COM и стратегия работы с TLB — разные вопросы. .NET Core / .NET 5+ — это не тот мир, где TLB естественным образом появляется из сборки, как было во времена .NET Framework. Если требуется типизированное использование, безопаснее отдельно продумать генерацию, встраивание и регистрацию TLB.
10. Набросок минимальной конфигурации
Здесь приведён минимальный набросок того, как MyApp.exe использует Vendor.CameraControl.dll через Reg-Free COM.
10.1 Набросок структуры файлов
MyApp.exe
MyApp.exe.manifest
Vendor.CameraControl.dll
Vendor.Helper.dll
В примере выше предполагается, что манифест компонента встроен в саму DLL. Можно оформить его и отдельным файлом, но для начала со встраиванием проще навести порядок.
10.2 Набросок манифеста приложения
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
type="win32"
name="KomuraSoft.MyApp"
version="1.0.0.0"
processorArchitecture="amd64" />
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Vendor.CameraControl.Asm"
version="1.0.0.0"
processorArchitecture="amd64" />
</dependentAssembly>
</dependency>
</assembly>
10.3 Набросок манифеста компонента
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
type="win32"
name="Vendor.CameraControl.Asm"
version="1.0.0.0"
processorArchitecture="amd64" />
<file name="Vendor.CameraControl.dll">
<comClass
clsid="{01234567-89AB-CDEF-0123-456789ABCDEF}"
progid="Vendor.CameraControl.1"
threadingModel="Apartment"
tlbid="{89ABCDEF-0123-4567-89AB-CDEF01234567}" />
<typelib
tlbid="{89ABCDEF-0123-4567-89AB-CDEF01234567}"
version="1.0"
helpdir="" />
</file>
</assembly>
В этом примере по-настоящему важны не детали XML, а то, что dependentAssembly на стороне приложения и assemblyIdentity на стороне компонента совпадают.
Если здесь возникает рассогласование, мучиться приходится довольно тихо и незаметно.
Отметим, что GUID и имена выше — лишь пример для иллюстрации. На практике их нужно правильно указывать в соответствии с CLSID / TLBID / ProgID и моделью потоков, которые реально предоставляет компонент.
11. Типичные ловушки
11.1 Работает на машине разработчика, но не работает на целевом компьютере
В первую очередь стоит заподозрить сценарий, при котором на самом деле помогала регистрация в реестре. Проверку Reg-Free COM по возможности безопаснее проводить в чистом окружении.
11.2 Приложение не запускается с ошибкой «side-by-side configuration is incorrect»
Эта группа ошибок возникает из-за несогласованности манифеста, нехватки зависимых DLL, отсутствия среды выполнения VC++, несовпадения архитектуры и тому подобного.
Одного лишь текста ошибки на поверхности недостаточно, поэтому стандартный способ разобраться — журнал событий и sxstrace.
11.3 Рассогласование между манифестом компонента и манифестом приложения
- отличается
name - отличается
version - отличается
processorArchitecture - манифест, который вы думали, что скопировали, на самом деле устарел
На вид это совсем небольшие расхождения, но при запуске они сказываются очень сильно.
11.4 Забытые зависимые DLL
Если ограничиться только Vendor.CameraControl.dll и на этом успокоиться, легко упустить Vendor.Helper.dll, загружаемый следом, среду выполнения VC++ и proxy / stub DLL.
Reg-Free COM сокращает проблемы регистрации COM, но не устраняет заодно и проблемы разрешения нативных зависимостей.
11.5 Откладывание вопросов типовой библиотеки и настройки ссылок
Даже если активация во время выполнения проходит успешно, как только появляется потребность
- в раннем связывании из VBA,
- в
#importиз C++, - в создании проектного interop на стороне .NET,
требуется способ распространения типовой информации. Reg-Free COM не настраивает всё это автоматически, поэтому важно рассматривать runtime и design-time отдельно друг от друга.
12. Итоги
Если сформулировать Reg-Free COM одной фразой, это механизм, который переносит регистрационную информацию COM с уровня всей машины на уровень отдельного приложения.
Благодаря этому появляются такие преимущества:
- легче хранить COM DLL / OCX локально для приложения
- легче сокращать конфликты версий
- легче упрощать распространение и откат
В то же время по-прежнему важны:
- разрядность 32-бит / 64-бит
- зависимые DLL
- TLB / настройка ссылок
- зависимость от нестандартной регистрации
- проверка в чистом окружении
Поэтому базовый подход при внедрении Reg-Free COM такой:
- Чётко принять, что это вопрос активации
- Разделять вопросы runtime и design-time
- Проверять в чистом окружении
- Сначала согласовать разрядность и зависимые DLL
Если смотреть на всё в таком порядке, риск проблем заметно снижается.
13. Похожие статьи
- Что такое COM / ActiveX / OCX — различия и взаимосвязи
- Как сегодня поступать с ActiveX / OCX — таблица решений: оставить, обернуть или заменить
- Как использовать DLL на .NET 8 из VBA с типами — публикация COM + генерация TLB с помощью dscom
14. Источники
- Microsoft Learn - Создание Registration-Free COM объектов
- Microsoft Learn - Манифесты приложений
- Microsoft Learn - Assembly Manifests
- Microsoft Learn - Manifest File Schema
- Microsoft Learn - Взаимодействие с COM без регистрации (.NET Framework)
- Microsoft Learn - Публикация компонентов .NET Core для COM
- Microsoft Learn - sxstrace
Похожие статьи
Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.
Что такое COM / ActiveX / OCX - объясняем различия и связь между ними
Разбираем с практической точки зрения, что такое COM, что такое ActiveX и что такое OCX: их различия и связь, связь с OLE, где они примен...
Обратная совместимость интерфейсов DLL и COM — таблица решений: какие изменения ломают вызывающую сторону
Какие изменения DLL или COM-компонента на самом деле ломают вызывающую сторону? Разбираем три слоя совместимости — бинарную, исходную и п...
Работают ли бизнес-приложения на Windows на Arm — реальность x64-эмуляции (Prism) и нативных DLL/COM
Отвечаем разработчикам и ИТ-специалистам на вопрос «заработает ли наше бизнес-приложение на Windows на Arm». Разбираем принцип работы x64...
Если вам досталась система без исходного кода и без документации — практический план, как сопровождать её, не останавливая работу
Разбираем практический план начала эксплуатации и сопровождения бизнес-системы, у которой нет ни исходного кода, ни спецификаций. Охватыв...
Аутсорсинг и контрактная разработка Windows-приложения: что стоит прояснить перед заказом
Перед тем как заказать аутсорсинг или контрактную разработку Windows-приложения, разберём, что нужно прояснить: доработка существующего П...
Связанные темы
Эти страницы показывают тему статьи в более широком контексте услуг и решений.
Технические темы Windows
Раздел о разработке Windows, расследовании сбоев и использовании существующих активов.
Миграция ActiveX
Решения о сохранении, обёртке или замене компонентов COM / ActiveX / OCX.
Услуги по этой теме
Статья напрямую связана со следующими услугами.
Разработка приложений для Windows
Эта тема напрямую связана с реализацией Windows-десктоп-приложений: распространение COM DLL / OCX, настройка манифестов, разрядность (bitness) и зависимые DLL.
Технические консультации и ревью дизайна
Также подходит для того, чтобы разобраться, стоит ли переходить на Reg-Free COM или сохранить регистрационную модель эксплуатации, и как разделить работу с типовыми библиотеками и настройкой проектных ссылок.
Частые вопросы
Вопросы, которые часто возникают при консультациях по теме статьи.
- Что такое Reg-Free COM?
- Reg-Free COM (Registration-Free COM) — это механизм, при котором информация о регистрации COM хранится не в реестре, а в манифесте. Во время выполнения при разрешении CoCreateInstance или CLSIDFromProgID сначала проверяется контекст активации (activation context), и DLL разрешается по манифестной информации, записанной в нём. Благодаря этому COM DLL / OCX можно хранить private для каждого приложения, что даёт такие преимущества, как удобное XCOPY-распространение, более лёгкое предотвращение конфликтов версий и меньший риск поломки при удалении.
- Решает ли переход на Reg-Free COM проблему 32-бит / 64-бит?
- Нет. 32-битный процесс может загружать только 32-битные in-proc COM DLL, а 64-битный — только 64-битные DLL; в этом отношении Reg-Free COM ничего не меняет. Кроме того, отдельно нужно продумывать распространение зависимых DLL и среды выполнения VC++, работу с типовыми библиотеками, настройку проектных ссылок и зависимость от нестандартной регистрационной информации. Reg-Free COM в основном избавляет только от хлопот, связанных с глобальной регистрацией.
- Почему конфигурация Reg-Free COM работает на машине разработчика, но не работает на целевом компьютере?
- Прежде всего стоит заподозрить, что на самом деле дело было в помощи со стороны регистрации в реестре. Если манифесту не хватает нужной информации, среда выполнения COM откатывается к обычному разрешению на основе регистрации, поэтому на машине разработчика приложение может случайно работать благодаря локальной регистрации. Поэтому проверку Reg-Free COM безопаснее проводить в чистом окружении. Если приложение не запускается с ошибкой «side-by-side configuration is incorrect», причиной обычно являются несогласованность манифеста или нехватка зависимых DLL, и стандартный способ разобраться — журнал событий и sxstrace.
- Можно ли сделать Reg-Free COM для COM-компонента, созданного на .NET 8?
- Да. В .NET 5+/.NET 8 параметр EnableComHosting создаёт *.comhost.dll — точку входа для публикации COM, а добавление EnableRegFreeCom=true выводит side-by-side манифест для Reg-Free COM. Однако Reg-Free COM и стратегия работы с TLB — это отдельные вопросы. В .NET Core/.NET 5+ TLB не появляется из сборки естественным образом, как это было во времена .NET Framework, поэтому если требуется типизированное использование — например, раннее связывание из VBA, — генерацию, встраивание и регистрацию TLB безопаснее продумывать отдельно.
Об авторе
Страница с профилем автора статьи.
Го Комура
Представитель KomuraSoft LLC
Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.
Публичные ссылки