Что такое Reg-Free COM: механизм использования COM без регистрации

· Обновлено: · · COM, Reg-Free COM, Registration-Free COM, Разработка Windows, Устаревшие технологии

История изменений (1 обновлений, последнее 30 Aug 2026)

Журнал изменений этой статьи. Там, где версия до правки была заархивирована, она остаётся доступной для чтения по постоянной ссылке с DOI.

Русский текст переписан как полноценный технический перевод, а не калька с японского. Утверждения статьи не менялись.
Первая публикация
Цитирование статьи(DOI: 10.5281/zenodo.21619728)

Статья заархивирована на Zenodo. Ниже приведены DOI, который всегда ведёт к последней версии, и DOI, закреплённый за версией, которую вы читаете.

Го Комура (2026). Что такое Reg-Free COM: механизм использования COM без регистрации. KomuraSoft LLC. https://doi.org/10.5281/zenodo.21619728 https://comcomponent.com/ru/blog/2026/03/16/011-what-is-reg-free-com/

DOI (последняя версия)
10.5281/zenodo.21619728
DOI (эта версия)
10.5281/zenodo.21619729

В проектах с COM / ActiveX / OCX при каждом развёртывании и обновлении всплывает одна и та же грязь.

  • нужен regsvr32
  • почти всегда требуются права администратора
  • возникает конфликт с другой версией, которую поставило другое приложение
  • удаление приложения задевает и другие продукты
  • работает на машине разработчика, но не работает в чистом окружении

Эту трясину заметно уменьшает Reg-Free COM. Правда, вопреки названию, это не «волшебство, которое снимает все хлопоты с COM». Исчезает в первую очередь то, что тянет за собой глобальная регистрация. Сложности с разрядностью (bitness), зависимыми DLL, библиотеками типов и моделью потоков никуда не деваются.

Что исчезает и что остаётся в Reg-Free COMРисунок показывает, что Reg-Free COM в первую очередь уменьшает хлопоты глобальной регистрации, а разрядность, зависимые DLL, библиотеки типов и сложность модели потоков не исчезают.Reg-Free COMХлопот глобальной регистрации меньшеОстаются и свои сложностиbitness / зависимые DLL / библиотеки типов

Рис. 1: Это не волшебство: отдельно ждут, что исчезнет, и что останется.

В этой статье Reg-Free COM разбирается прежде всего в контексте использования COM DLL / OCX в Windows-десктоп-приложении с хранением локально у приложения.

Для кого эта статья и какие допущения

Текст рассчитан на разработчиков, которые распространяют Windows-десктоп-приложение с существующими COM DLL / OCX и хотят уйти от regsvr32 и прав администратора. Предполагается, что основы COM (CLSID, ProgID, CoCreateInstance, in-proc сервер) уже встречались. Если это ещё расплывчато, быстрее сначала прочитать «Что такое COM / ActiveX / OCX - объясняем различия и связь между ними».

В процедурной части используются mt.exe и sxstrace из Windows SDK, поэтому предполагается среда с Visual Studio или Windows SDK.

1. Сначала вывод (коротко)

Сначала грубая, но полезная формулировка.

  • Reg-Free COM — это способ хранить регистрационные сведения COM не в реестре, а в манифесте
  • Во время выполнения при разрешении CoCreateInstance или CLSIDFromProgID сначала смотрят контекст активации (activation context)
  • Благодаря этому COM DLL / OCX можно держать private для каждого приложения
  • Основные преимущества — удобное XCOPY-распространение, легче избегать конфликтов версий и меньше риск сломать удаление
  • Однако проблема 32-бит / 64-бит никуда не исчезает. Записью манифеста её не обойти
  • Кроме того, отдельно нужно продумывать зависимые DLL, библиотеки типов, ссылки на этапе проектирования и зависимость от нестандартной регистрации
  • На практике это хорошо подходит, когда рядом с приложением хотят положить COM-компоненты только для него

Иными словами, Reg-Free COM — это механизм, который возвращает активацию COM на уровень отдельного приложения.

Меняется место регистрационных сведенийРисунок показывает, что Reg-Free COM хранит регистрационные сведения COM в манифесте, а не в реестре, и поскольку при разрешении CoCreateInstance сначала смотрят контекст активации, COM-компоненты можно держать private для каждого приложения.Сведения хранят в манифестеПри разрешении сначала контекст активацииCOM можно держать private для приложенияПроще XCOPY и меньше конфликтов

Рис. 2: Суть в том, что вход разрешения смещается с реестра на манифест.

Карта знаний этой статьи

Reg-Free COM держит сведения о регистрации COM не в реестре, а в манифесте и при выполнении сначала смотрит контекст активации, чтобы разрешить DLL. Манифест приложения объявляет зависимую side-by-side assembly, манифест компонента держит сведения вроде CLSID и ProgID, которые раньше жили в реестре, — такое разделение ролей; встраивают через mt.exe, сбои разрешения отслеживают через sxstrace. Требование совпадения 32-bit и 64-bit при этом не снимается, а обращение с зависимыми DLL и библиотекой типов остаётся отдельным вопросом, поэтому схема подходит, чтобы сделать app-local существующие наработки рабочего стола вроде VB6, MFC и WinForms, но не подходит, когда нужно совместное использование COM на всю машину. В .NET 5+ / .NET 8 comhost создают через EnableComHosting, а включение EnableRegFreeCom позволяет вывести side-by-side манифест для Reg-Free COM.

Карта знаний Reg-Free COMСхема, которая показывает, что Reg-Free COM через контекст активации и механизм side-by-side assembly держит сведения о регистрации COM на уровне приложения; разделение ролей манифеста приложения и манифеста компонента; сборку через mt.exe и разбор сбоев через sxstrace; и связь с comhost в .NET 5+используетиспользуетиспользуеттребуетреализуеттребуетпреемникиспользуетнастраиваетсяпроверяетсянастраиваетсятребуетиспользуеттребуетнастраиваетсяреализуетиспользуетиспользуетиспользуетиспользуетиспользуетиспользуетрекомендуется длярекомендуется длярекомендуется дляне рекомендуетсяReg-Free COM (без регистрации)контекст активации (activation context)манифест приложения (Win32 side-by-side)манифест компонента (assembly manifest)side-by-side assemblyтребование совпадения разрядностиregsvr32библиотека типов (TLB)mt.exe (Manifest Tool)sxstraceпорядок поиска private assembly.NET (начиная с Core)COM host (*.comhost.dll)EnableComHostingEnableRegFreeComVisual Basic 6.0 (VB6)CLSID (Class ID)ProgID (Programmatic Identifier)COM (Component Object Model)ActiveXOCXMFC (Microsoft Foundation Classes)Windows Formsобщее использование COM на всю машину

На схеме сплошная линия обозначает отношение, которое выполняется всегда, а пунктирная — условное отношение (условия указаны в пояснении к каждому отношению на странице сведений). Полный список отношений (всего 26, с доказательствами и степенью уверенности) и определения основных понятий собраны на странице сведений карты знаний (на японском). Данные: JSON-LD / Turtle

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

И наоборот, в этой статье хочется особо подчеркнуть два момента.

  1. Reg-Free COM — это разговор об «активации»
  2. Распространение типовой информации и настройка ссылок на этапе проектирования могут оставаться отдельным вопросом

Если смешать эти темы, разговор становится куда мутнее.

Две темы, которые нельзя смешиватьРисунок показывает, что Reg-Free COM — разговор об активации, а распространение типовой информации и ссылки на этапе проектирования могут оставаться отдельным вопросом, поэтому смешение этих двух тем мутит разговор.Reg-Free COMРазговор об активацииТиповая информация и ссылки на этапе проектированияОстаётся отдельным вопросомЕсли смешать, разговор мутнеет

Рис. 3: Разговор о времени выполнения и разговор о времени проектирования с самого начала держат отдельно.

3. Сначала общая картина на одной схеме

До схемы заранее определим четыре термина, которые в статье встречаются снова и снова.

Термин Смысл
Контекст активации (activation context) Структура данных времени выполнения, которая держит «этот поток сейчас использует какую сборку какой версии». CoCreateInstance смотрит сюда раньше, чем в реестр
side-by-side assembly Механизм Windows, который позволяет сосуществовать на одной машине компонентам с одним именем, но разными версиями. Их идентифицирует манифест; assemblyIdentity здесь играет роль ярлыка
Манифест приложения XML на стороне EXE: «от каких side-by-side assembly я завишу»
Манифест компонента (assembly manifest) XML на стороне компонента: «какие файлы входит в эту сборку и какие COM-классы она публикует». Сюда приходят сведения, которые раньше жили в реестре

Контекст активации держат по потокам. COM передаёт контекст активации создающего потока на поток-хозяин и только потом вызывает LoadLibrary и DllGetClassObject, поэтому на вызывающей стороне отдельная подготовка не нужна.

После этого быстрее один раз посмотреть на общую картину.

MyApp.exeApplication ManifestdependentAssemblyComponent / Assembly Manifestfile / comClass / typelibVendorControl.dll / .ocxActivation ContextCLSIDFromProgID / CoCreateInstance

Рис. 4: От манифеста приложения идут к манифесту компонента и доходят до 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 — механизм, который снижает боль именно этой модели распространения.

Как глобальное совместное использование бьёт в обратную сторонуРисунок показывает, что регистрационные сведения COM в реестре удобны для совместного использования всей машиной, но на практике оборачиваются перезаписью другим продуктом, задеванием при удалении и расхождением среды разработки и боя, так что людей чаще беспокоит модель распространения, а не сам COM.Сведения делят на всю машинуУдобно: несколько приложений могут пользоватьсяНа практике совместное использование бьёт в обратную сторонуПерезапись / задевание / расхождение средЛюдей беспокоит модель распространения

Рис. 5: Источник тяжести — не сам COM, а допущение глобальной регистрации.

5. Как работает Reg-Free COM

5.1 Зависимости указывают в манифесте приложения

Сначала приложение в манифесте приложения указывает, от каких side-by-side assembly оно зависит.

Этот манифест можно оформить любым из двух способов:

  • положить рядом с EXE, например как MyApp.exe.manifest
  • встроить в EXE как ресурс

На практике часто выбирают так: внешний файл — если важно, чтобы распространение и замена были наглядными; встраивание — если в приоритете устойчивость и простота распространения.

Если существуют одновременно внешняя и встроенная версии, приоритет имеет манифест на файловой системе.

5.2 Сведения о COM описывают в манифесте компонента

Далее COM-сторона переносит сведения, которые раньше жили в реестре, в манифест компонента.

Сюда входит, например, такая информация:

  • comClass
  • clsid
  • progid
  • threadingModel
  • typelib
  • при необходимости — proxy / stub, классы окон и т. п.

То есть идея в том, чтобы вместо реестра описывать «облик» COM на XML.

Этот манифест также можно оформить любым из двух способов:

  • положить отдельным файлом рядом с DLL
  • встроить в DLL как ресурс

На практике встраивание в DLL как private assembly обычно даёт меньше сбоев. Отдельный файл нагляднее, но легче споткнуться о соответствие между именем файла и assemblyIdentity, о место размещения и о забытые копирования.

Как держат манифест компонентаРисунок показывает, что сведения вроде comClass, clsid и typelib, которые раньше жили в реестре, манифест компонента держит в XML, и можно положить их отдельным файлом рядом с DLL или встроить в DLL как ресурс; на практике встраивание обычно даёт меньше сбоев.Сведения из реестра держат в XMLПоложить отдельным файломВстроить в DLLЛегче споткнуться о забытое копированиеНа практике обычно меньше сбоев

Рис. 6: Содержание одно и то же, но выбор места влияет на частоту сбоев.

5.3 Во время выполнения сначала смотрят контекст активации

Здесь заключена суть Reg-Free COM.

Когда приложение вызывает CLSIDFromProgID или CoCreateInstance, среда выполнения COM смотрит активный контекст активации. Если там есть нужные сведения ProgID → CLSID и CLSID → DLL, разрешение выполняется без обращения к реестру.

И наоборот, если в манифесте не хватает нужных сведений, происходит откат к обычному разрешению по регистрации. Из-за этого поведения возникает ловушка: на машине разработчика приложение случайно работает. Кажется, что переход на Reg-Free состоялся, а на самом деле помогает локальная регистрация.

Это самая коварная ловушка Reg-Free COM.

Ловушка отката к разрешению по регистрацииРисунок показывает, что при разрешении CoCreateInstance сначала смотрят контекст активации, но если в манифесте не хватает сведений, происходит откат к обычному разрешению по регистрации, и на машине разработчика приложение может случайно работать за счёт локальной регистрации.ХватаетНе хватаетСначала смотрят контекст активацииВ манифесте хватает сведений?Разрешают без реестраОткат к разрешению по регистрацииЛовушка: на машине разработчика случайно работает

Рис. 7: Тихий откат — главная ловушка этого механизма.

6. В чём польза

На практике преимущества Reg-Free COM видны вполне отчётливо.

6.1 Удобное XCOPY-распространение

Все нужные файлы можно собрать в папке приложения, поэтому установщик и процедура регистрации становятся легче. Разумеется, если запись идёт в Program Files, вопрос прав остаётся отдельной темой, но по крайней мере административную работу, связанную с регистрацией COM, обычно удаётся сократить.

6.2 Легче сократить конфликты версий

Даже если на одной машине несколько версий COM-компонента, используемую версию проще развести по приложениям. Заметно легче избежать неприятности вроде «поведение внезапно изменилось из-за установки другого продукта».

6.3 Часто не требует крупных изменений в существующем коде

Reg-Free COM — механизм, который меняет способ разрешения, а не в корне переделывает то, как существующий код делает вызовы. Поэтому при удачном сценарии его можно внедрить, почти не трогая код на стороне CoCreateInstance.

6.4 Удаление и откат становятся проще

Поскольку всё замкнуто на уровне приложения, обновление и откат становятся заметно прямее. Утрируя, легче принять подход «просто заменить всю папку целиком».

Польза от замыкания на уровне приложенияРисунок показывает, что замыкание COM-компонентов на уровне приложения даёт удобное XCOPY-распространение, более лёгкое избегание конфликтов версий, внедрение почти без правок существующего кода и более простое удаление и откат.Замыкают на уровне приложенияУдобное XCOPY-распространениеМеньше конфликтов версийМожно заменить папку целикомКод вызовов почти не трогают

Рис. 8: Все преимущества растут из одного свойства: компонент замкнули.

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 настройки ссылок на этапе проектирования.

Время выполнения выигрывает, время проектирования остаётсяРисунок показывает, что Reg-Free COM помогает с активацией во время выполнения, но если инструменты проектирования и настройка ссылок в IDE предполагают реестр, это само по себе не меняется и нужен отдельный порядок эксплуатации.Активация во время выполненияReg-Free помогаетUI ссылок на этапе проектированияИногда предполагает реестрНужен отдельный порядок эксплуатации

Рис. 9: Даже если механизм запуска уже собран, механизм разработки собирают отдельно.

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 в первую очередь про то, чтобы приложение вообще запускалось. Как вести типизированную разработку — следующий, отдельный вопрос.

Порядок: сначала запуск, потом типыРисунок показывает, что в манифесте можно указать typelib, но настройка ссылок VBA, import в C++ и генерация ссылок .NET на этапе проектирования требуют отдельного проектирования; Reg-Free COM — сначала про запуск, типизированная разработка — следующий вопрос.Собирают Reg-Free COMСначала добиваются запускаЗатем — как разрабатывать с типамиСсылки VBA / import / генерация interop

Рис. 10: То, что typelib можно записать, и то, что типовая информация уже в эксплуатации, — разные вещи.

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. Ограничения на имя и идентификатор ресурса из раздела 10.4 точно так же действуют и на этот манифест компонента.

9.2 Публикация COM в .NET 5+ / .NET 8

В .NET 5+ / .NET 8 точкой входа для публикации COM становится *.comhost.dll. Если дополнительно указать EnableRegFreeCom=true, будет сгенерирован side-by-side манифест для Reg-Free COM.

Что типовая информация — отдельный вопрос, сказано в разделе 8.3, но в .NET Core / .NET 5+ это меняется ещё сильнее. Это уже не тот мир, где, как во времена .NET Framework, TLB естественным образом появляется из сборки, поэтому если нужно типизированное использование, генерацию, встраивание и регистрацию TLB нужно собирать отдельно. Конкретные шаги разобраны в «Как использовать DLL на .NET 8 из VBA с типизацией — публикация COM и TLB через dscom».

Reg-Free COM начиная с .NET 5Рисунок показывает, что начиная с .NET 5 EnableComHosting создаёт comhost.dll как точку входа для публикации COM, включение EnableRegFreeCom выводит side-by-side манифест для Reg-Free COM, а генерацию и регистрацию TLB собирают отдельно.Сборка с EnableComHostingТочкой входа становится comhost.dllВключают EnableRegFreeComВыводится манифест для Reg-FreeОбращение с TLB собирают отдельно

Рис. 11: В .NET 8 два свойства дают площадку, но типовая информация — отдельная работа.

10. Набросок минимальной конфигурации

Здесь показан минимальный набросок того, как MyApp.exe использует Vendor.CameraControl.dll через Reg-Free COM.

10.1 Набросок структуры файлов

MyApp.exe
MyApp.exe.manifest
Vendor.CameraControl.Asm.manifest
Vendor.CameraControl.dll
Vendor.Helper.dll

В примере выше предполагается, что манифест компонента лежит отдельным файлом. Его можно встроить в DLL, но тогда на имя сборки и идентификатор ресурса накладываются фиксированные ограничения. Шаги — в разделе 10.4.

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 и моделью потоков, которые реально предоставляет компонент.

Требование совпадения двух манифестовРисунок показывает, что dependentAssembly на стороне приложения и assemblyIdentity на стороне компонента должны совпадать по имени и версии, и если они расходятся, получается сбой запуска, причину которого по тексту ошибки не видно.СовпадаютРасходятсяdependentAssembly на стороне приложенияИмя и версия совпадают?assemblyIdentity на стороне компонентаРазрешение проходитСбой запуска без видимой причины

Рис. 12: Важнее деталей XML то, совпадают ли ярлыки с обеих сторон.

10.4 Куда класть манифест и как встраивать

Именно здесь на шагах чаще всего спотыкаются. От того, кладёте ли вы отдельный файл или встраиваете в двоичный файл, зависит, какое имя можно поставить.

side-by-side ищет private assembly относительно папки приложения в таком порядке.

  1. Папка WinSxS
  2. <appdir>\<assemblyname>.DLL
  3. <appdir>\<assemblyname>.manifest
  4. <appdir>\<assemblyname>\<assemblyname>.DLL
  5. <appdir>\<assemblyname>\<assemblyname>.manifest

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

Способ размещения Имя сборки Файл Идентификатор ресурса при встраивании
Отдельный файл Имя другое, чем у DLL. Пример: Vendor.CameraControl.Asm Vendor.CameraControl.Asm.manifest рядом с DLL Не встраивают
Встраивание в DLL Имя может совпадать с DLL. Пример: Vendor.CameraControl Только Vendor.CameraControl.dll 1

То есть если, как в примерах 10.2 и 10.3, используется имя Vendor.CameraControl.Asm, это приём отдельного файла. При переходе на встраивание name в assemblyIdentity меняют на Vendor.CameraControl и то же имя выравнивают на стороне dependentAssembly.

Как поиск останавливаетсяРисунок показывает, что side-by-side ищет private assembly от WinSxS к папке приложения и останавливается, как только находит DLL с тем же именем, что у сборки, поэтому при отдельном файле имя сборки нужно делать отличным от имени DLL.НашлиНе нашлиНачинают поиск private assemblyИщут DLL с тем же именем, что у сборкиПоиск на этом останавливаетсяИщут одноимённый файл manifestПри отдельном файле имена делают разными

Рис. 13: Ограничение на имена следует из того, что поиск останавливается на середине.

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

Для встраивания используют mt.exe (Manifest Tool) из Windows SDK. Запускайте из командной строки разработчика Visual Studio.

rem 1. Перед встраиванием сначала прогоняем проверку синтаксиса
mt.exe -manifest MyApp.exe.manifest -validate_manifest
mt.exe -manifest Vendor.CameraControl.manifest -validate_manifest

rem 2. Встраиваем манифест приложения в EXE
mt.exe -manifest MyApp.exe.manifest -outputresource:MyApp.exe;#1

rem 3. Встраиваем манифест компонента в DLL (идентификатор ресурса — 1)
mt.exe -manifest Vendor.CameraControl.manifest -outputresource:Vendor.CameraControl.dll;#1

rem 4. Проверяем, что встроилось: извлекаем и сравниваем
mt.exe -inputresource:Vendor.CameraControl.dll;#1 -out:extracted.manifest

Если извлечённый четвёртой командой extracted.manifest сравнить с исходным XML, можно отсечь случай «думали, что встроили, а внутри ничего нет».

Шаги встраивания через mt.exeРисунок показывает поток mt.exe: сначала прогоняют проверку синтаксиса validate_manifest, затем встраивают манифест приложения в EXE, манифест компонента в DLL с идентификатором ресурса 1 и в конце извлекают и сравнивают с исходным XML.Прогоняют проверку синтаксисаВстраивают сторону приложения в EXEВстраивают сторону компонента в DLL (ID 1)Извлекают и сравнивают с исходным XML

Рис. 14: Встраивание гоняют как одну процедуру, включая проверку.

У mt.exe есть два важных ограничения.

  • Файлы, на которые ссылается манифест, должны лежать в том же каталоге, что и манифест. Если написали <file name="Vendor.CameraControl.dll">, эту DLL кладут рядом с манифестом и только потом запускают. Если место сборки и место хранения манифеста разъехались, здесь процесс останавливается
  • Если в -outputresource опустить идентификатор ресурса, используется CREATEPROCESS_MANIFEST_RESOURCE (= 1). Чтобы случайный переход в 1 не путал, ;#1 лучше указывать явно — так читать проще

Если нужно только заменить уже встроенное, можно -updateresource:<файл>;#1. Это то же самое, что передать одинаковые аргументы в -inputresource и -outputresource.

10.5 Порядок проверки, включая чистое окружение

Для Reg-Free COM «заработало на машине разработчика» почти ничего не значит. Всегда остаётся возможность, что просто помогала локальная регистрация в реестре. Проверяют в таком порядке.

  1. Собрать и сложить комплект поставки в одну папку. EXE, манифесты, COM DLL, зависимые DLL, среда выполнения VC++, proxy / stub DLL
  2. Подготовить проверочную среду. Идеально — среда, где этот COM ни разу не регистрировали. С Windows Sandbox каждый раз можно начинать с чистого состояния
  3. Сначала убедиться, что в этой среде целевой COM не зарегистрирован. Командами ниже ошибка «ключ не найден» как раз и значит, что регистрации нет
  4. Скопировать папку и запустить как есть. Ни установщик, ни regsvr32 не запускают
  5. Дойти до создания COM-объекта. Одного запуска мало: компоненты с отложенным созданием так не проверяются. Нужно пройти экран или функцию, где реально вызывается CoCreateInstance
  6. Если не получилось — снять журнал по шагам из раздела 11.2

Команды для шага 3 такие.

reg query "HKCR\CLSID\{01234567-89AB-CDEF-0123-456789ABCDEF}" /reg:64
reg query "HKCR\CLSID\{01234567-89AB-CDEF-0123-456789ABCDEF}" /reg:32
reg query "HKCR\Vendor.CameraControl.1"

Представления реестра 32-бит и 64-бит — разные вещи, поэтому обязательно смотрят сторону, которая совпадает с разрядностью приложения. Надёжнее глянуть и /reg:64, и /reg:32.

Если хочется проверить на машине разработчика, сначала снимают регистрацию командой regsvr32 /u Vendor.CameraControl.dll. Но в среде, где тот же COM используют другие продукты, это даёт побочные эффекты, поэтому безопаснее готовить чистое окружение.

Поток проверки в чистом окруженииРисунок показывает поток: комплект поставки складывают в одну папку, готовят проверочную среду, где целевой COM никогда не регистрировали, сначала подтверждают отсутствие регистрации, копируют папку и запускают как есть, затем проходят функцию, где вызывается CoCreateInstance.Если сбойСкладывают комплект поставкиГотовят чистое проверочное окружениеСначала подтверждают, что не зарегистрированКопируют и запускают как естьДоходят до функции, где создаётся COMСнимают журнал и разбирают

Рис. 15: Проверка «не зарегистрирован» вычёркивает из проверки случайное везение.

11. Типичные ловушки

11.1 Работает на машине разработчика, но не работает на целевом компьютере

В первую очередь стоит заподозрить сценарий, при котором на самом деле помогала регистрация в реестре. Проверку Reg-Free COM по возможности безопаснее проводить в чистом окружении.

11.2 Приложение не запускается с ошибкой «side-by-side configuration is incorrect»

Эта группа ошибок возникает из-за рассогласования манифеста, нехватки зависимых DLL, отсутствия среды выполнения VC++, несовпадения архитектуры и тому подобного. Одного лишь текста ошибки на поверхности недостаточно, поэтому стандартный способ разобраться — журнал событий и sxstrace.

Журнал событий: в «Просмотре событий» открывают «Журналы Windows» > «Приложение» и ищут ошибки с источником SideBySide. Там видно, на разрешении какой сборки произошёл сбой.

sxstrace снимают, воспроизводя сбой. Командную строку надёжнее открыть от имени администратора.

rem 1. Начинаем трассировку. Это окно оставляем открытым
sxstrace trace -logfile:sxstrace.etl

rem 2. В другом окне запускаем приложение и воспроизводим сбой

rem 3. Останавливаем трассировку. В окне из шага 1 нажимаем Enter либо из другого окна выполняем следующее
sxstrace stoptrace

rem 4. Сырой .etl переводим в читаемый вид
sxstrace parse -logfile:sxstrace.etl -outfile:sxstrace.txt

Если не хотите видеть запрос на остановку, к шагу 1 добавляют -nostop. Если вывод слишком длинный, к шагу 4 можно добавить -filter:MyApp.exe и оставить только долю целевого приложения.

В преобразованном sxstrace.txt по порядку видно, какой манифест искали и где не совпало. Если в разделе 10.4 ошиблись с именами, здесь по «имени файла, который искали» это будет видно.

Как разбирать ошибку side-by-sideРисунок показывает поток при отказе запуска с «side-by-side configuration is incorrect»: в журнале событий смотрят ошибки источника SideBySide, запускают трассировку sxstrace, воспроизводят сбой, после остановки делают parse в читаемый вид и идут по местам поиска и расхождения.В журнале событий смотрят SideBySideЗапускают трассировку sxstraceЗапускают приложение и воспроизводят сбойОстанавливают и делают parseЧитают места поиска и расхождения

Рис. 16: Не застревают на тексте ошибки на поверхности, а идут по журналу и трассировке пути разрешения.

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 такой:

  1. Чётко принять, что это вопрос активации
  2. Разделять вопросы runtime и design-time
  3. Проверять в чистом окружении
  4. Сначала согласовать разрядность и зависимые DLL

Если смотреть на всё в таком порядке, риск проблем заметно снижается.

Базовый подход при внедренииРисунок показывает, что при внедрении Reg-Free COM меньше сбоев, если принять, что это разговор об активации, разделить вопросы времени выполнения и проектирования, проверять в чистом окружении и сначала согласовать разрядность и зависимые DLL.Принять, что это разговор об activationРазделить runtime и design-timeПроверять в чистом окруженииСначала согласовать bitness и зависимые DLL

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

13. Похожие статьи

14. Справочные материалы

Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.

Эти страницы показывают тему статьи в более широком контексте услуг и решений.

Статья напрямую связана со следующими услугами.

Частые вопросы

Вопросы, которые часто возникают при консультациях по теме статьи.

Что такое Reg-Free COM?
Это механизм, при котором сведения о регистрации COM хранятся не в реестре, а в манифесте. Сокращение от Registration-Free 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, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.

Публичные ссылки

Вернуться в блог