Предоставление доступа к компонентам .NET Core для COM
В этой статье описывается, как предоставить класс com из .NET Core (или .NET 5+). В этом учебнике описаны следующие процедуры.
- Предоставление класса для модели COM из .NET Core.
- Создайте сервер COM в процессе сборки библиотеки .NET Core.
- Автоматически создайте параллельный манифест сервера для модели COM без поддержки реестра.
Необходимые компоненты
- Установите пакет SDK для .NET Core 3.0 или более новой версии.
Создание библиотеки
Сначала нужно создать библиотеку.
Создайте новую папку и в этой папке выполните следующую команду.
dotnet new classlib
Открыть
Class1.cs
.Добавьте
using System.Runtime.InteropServices;
в начало файла.Создайте интерфейс с именем
IServer
. Например:using System; using System.Runtime.InteropServices; [ComVisible(true)] [Guid(ContractGuids.ServerInterface)] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IServer { /// <summary> /// Compute the value of the constant Pi. /// </summary> double ComputePi(); }
Добавьте в интерфейс атрибут
[Guid("<IID>")]
с идентификатором GUID реализуемого интерфейса COM. Например,[Guid("fe103d6e-e71b-414c-80bf-982f18f6c1c7")]
. Обратите внимание, что этот идентификатор GUID должен быть уникальным, так как он является единственным идентификатором данного интерфейса для модели COM. В Visual Studio можно создать GUID, перейдя в раздел "Сервис > создания GUID", чтобы открыть средство создания GUID.Добавьте в интерфейс атрибут
[InterfaceType]
и укажите, какие базовые COM-интерфейсы должен реализовывать ваш интерфейс.Создайте класс
Server
, реализующийIServer
.Добавьте в класс атрибут
[Guid("<CLSID>")]
с идентификатором GUID реализуемого класса COM. Например,[Guid("9f35b6f5-2c05-4e7f-93aa-ee087f6e7ab6")]
. Так же как и в случае с идентификатором GUID интерфейса, этот идентификатор GUID должен быть уникальным, так как он является единственным идентификатором данного класса для модели COM.Добавьте атрибут
[ComVisible(true)]
как в интерфейс, так и в класс.
Внимание
В отличие от .NET Framework, .NET Core требует указывать идентификатор CLSID любого класса, который должен активироваться через модель COM.
Создание узла COM
- Откройте файл проекта
.csproj
и добавьте элемент<EnableComHosting>true</EnableComHosting>
внутри тега<PropertyGroup></PropertyGroup>
. - Выполните сборку проекта.
В результате будут получены файлы ProjectName.dll
, ProjectName.deps.json
, ProjectName.runtimeconfig.json
и ProjectName.comhost.dll
.
Регистрация узла COM для модели COM
Откройте командную строку с повышенными привилегиями и запустите regsvr32 ProjectName.comhost.dll
. Это приведет к регистрации всех предоставленных объектов .NET в модели COM.
Если вы планируете внедрить библиотеку типов (TLB), рекомендуется также определить функции с помощью ComRegisterFunctionAttribute
и ComUnregisterFunctionAttribute
. Эти функции можно использовать для регистрации и отмены регистрации TLB для COM-сервера. Полный пример см. в OutOfProcCOM
примере.
Реализация модели COM без поддержки реестра
- Откройте файл проекта
.csproj
и добавьте элемент<EnableRegFreeCom>true</EnableRegFreeCom>
внутри тега<PropertyGroup></PropertyGroup>
. - Выполните сборку проекта.
В результате будет также получен файл ProjectName.X.manifest
. Это параллельный манифест для использования с моделью COM без поддержки реестра.
Внедрение библиотек типов на узле COM
В отличие от .NET Framework, в .NET Core и .NET 5 или более поздней версии создание библиотеки типов COM (TLB) из сборки .NET не поддерживается. Нужно вручную написать файл IDL или заголовок C/C++ для собственных объявлений COM-интерфейсов. Если вы решили написать файл IDL, его можно скомпилировать с помощью компилятора MIDL пакета SDK Visual C++, чтобы создать TLB-файл.
В .NET 6 и более поздних версиях пакет SDK для .NET поддерживает внедрение уже скомпилированных TLB-файлов на узле COM в рамках сборки проекта.
Чтобы внедрить библиотеку типов в приложение, выполните следующие действия.
- Откройте файл проекта
.csproj
и добавьте элемент<ComHostTypeLibrary Include="path/to/typelib.tlb" Id="<id>" />
внутри тега<ItemGroup></ItemGroup>
. - Замените
<id>
на положительное целое значение. Чтобы внедрение на узле COM было возможным, значение должно быть уникальным для указанных TLB-файлов.- Атрибут
Id
является необязательным, если в проект добавляется только один объектComHostTypeLibrary
.
- Атрибут
Например, следующий блок кода добавляет библиотеку типов Server.tlb
с индексом 1
на узел COM:
<ItemGroup>
<ComHostTypeLibrary Include="Server.tlb" Id="1" />
</ItemGroup>
Загрузка по умолчанию AssemblyLoadContext
Во время активации сборка, содержащая компонент модели COM, загружается отдельную AssemblyLoadContext на основе пути к сборке. Если имеется одна сборка, предоставляющая несколько серверов модели COM, компонент AssemblyLoadContext
используется повторно, поскольку все серверы из этой сборки находятся в одном контексте загрузки. Если есть несколько сборок, предоставляющих серверы модели COM, для каждой сборки создается новый AssemblyLoadContext
, а каждый сервер находится в контексте загрузки, соответствующем его сборке.
В .NET 8 и более поздних версиях сборка может указать, что она должна быть загружена по умолчанию AssemblyLoadContext
. Чтобы включить загрузку в контексте по умолчанию, добавьте в проект следующий элемент RuntimeHostConfigurationOption :
<ItemGroup>
<RuntimeHostConfigurationOption Include="System.Runtime.InteropServices.COM.LoadComponentInDefaultContext" Value="true" />
</ItemGroup>
Пример
В репозитории dotnet/samples на сайте GitHub есть полнофункциональный пример сервера COM.
Дополнительные примечания
Внимание
В .NET Framework сборка "Любой ЦП" может использоваться как с 32-разрядными, так и с 64-разрядными клиентами. По умолчанию в .NET Core, .NET 5 и более поздних версиях сборки "Любой ЦП" сопровождаются 64-разрядным *.comhost.dll. По этой причине они могут использоваться только в 64-разрядных клиентах. Это настроено по умолчанию, поскольку это то, что предоставляет пакет SDK. Такое поведение аналогично публикации "автономного" компонента: по умолчанию он использует то, что предоставляет пакет SDK. Свойство NETCoreSdkRuntimeIdentifier
MSBuild определяет битность *.comhost.dll. Управляемая часть на самом деле не зависит от ожидаемой разрядности, однако разрядность сопутствующего ресурса по умолчанию совпадает с разрядностью целевого пакета SDK.
Автономные развертывания COM-компонентов не поддерживаются. Поддерживаются только зависящие от платформы развертывания COM-компонентов.
Предоставление com-компонентов из проектов C++/CLI через свойство EnableComHosting не поддерживается.
Кроме того, загрузка как .NET Framework, так и .NET Core в один и тот же процесс имеет ограничения диагностического характера. Основное ограничение — отладка управляемых компонентов, так как невозможно одновременно выполнить отладку .NET Framework и .NET Core. Кроме того, два экземпляра среды выполнения не используют управляемые сборки совместно. Это означает, что невозможно совместно использовать фактические типы .NET в двух средах выполнения, вместо этого все взаимодействия должны быть ограничены предоставленными контрактами COM-интерфейса.