Предоставление доступа к компонентам .NET Core для COM

В этой статье описывается, как предоставить класс com из .NET Core (или .NET 5+). В этом учебнике описаны следующие процедуры.

  • Предоставление класса для модели COM из .NET Core.
  • Создайте сервер COM в процессе сборки библиотеки .NET Core.
  • Автоматически создайте параллельный манифест сервера для модели COM без поддержки реестра.

Необходимые компоненты

Создание библиотеки

Сначала нужно создать библиотеку.

  1. Создайте новую папку и в этой папке выполните следующую команду.

    dotnet new classlib
    
  2. Открыть Class1.cs.

  3. Добавьте using System.Runtime.InteropServices; в начало файла.

  4. Создайте интерфейс с именем 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();
    }
    
  5. Добавьте в интерфейс атрибут [Guid("<IID>")] с идентификатором GUID реализуемого интерфейса COM. Например, [Guid("fe103d6e-e71b-414c-80bf-982f18f6c1c7")]. Обратите внимание, что этот идентификатор GUID должен быть уникальным, так как он является единственным идентификатором данного интерфейса для модели COM. В Visual Studio можно создать GUID, перейдя в раздел "Сервис > создания GUID", чтобы открыть средство создания GUID.

  6. Добавьте в интерфейс атрибут [InterfaceType] и укажите, какие базовые COM-интерфейсы должен реализовывать ваш интерфейс.

  7. Создайте класс Server, реализующий IServer.

  8. Добавьте в класс атрибут [Guid("<CLSID>")] с идентификатором GUID реализуемого класса COM. Например, [Guid("9f35b6f5-2c05-4e7f-93aa-ee087f6e7ab6")]. Так же как и в случае с идентификатором GUID интерфейса, этот идентификатор GUID должен быть уникальным, так как он является единственным идентификатором данного класса для модели COM.

  9. Добавьте атрибут [ComVisible(true)] как в интерфейс, так и в класс.

Внимание

В отличие от .NET Framework, .NET Core требует указывать идентификатор CLSID любого класса, который должен активироваться через модель COM.

Создание узла COM

  1. Откройте файл проекта .csproj и добавьте элемент <EnableComHosting>true</EnableComHosting> внутри тега <PropertyGroup></PropertyGroup>.
  2. Выполните сборку проекта.

В результате будут получены файлы ProjectName.dll, ProjectName.deps.json, ProjectName.runtimeconfig.json и ProjectName.comhost.dll.

Регистрация узла COM для модели COM

Откройте командную строку с повышенными привилегиями и запустите regsvr32 ProjectName.comhost.dll. Это приведет к регистрации всех предоставленных объектов .NET в модели COM.

Реализация модели COM без поддержки реестра

  1. Откройте файл проекта .csproj и добавьте элемент <EnableRegFreeCom>true</EnableRegFreeCom> внутри тега <PropertyGroup></PropertyGroup>.
  2. Выполните сборку проекта.

В результате будет также получен файл 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 в рамках сборки проекта.

Чтобы внедрить библиотеку типов в приложение, выполните следующие действия.

  1. Откройте файл проекта .csproj и добавьте элемент <ComHostTypeLibrary Include="path/to/typelib.tlb" Id="<id>" /> внутри тега <ItemGroup></ItemGroup>.
  2. Замените <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-компонентов.

Кроме того, загрузка как .NET Framework, так и .NET Core в один и тот же процесс имеет ограничения диагностического характера. Основное ограничение — отладка управляемых компонентов, так как невозможно одновременно выполнить отладку .NET Framework и .NET Core. Кроме того, два экземпляра среды выполнения не используют управляемые сборки совместно. Это означает, что невозможно совместно использовать фактические типы .NET в двух средах выполнения, вместо этого все взаимодействия должны быть ограничены предоставленными контрактами COM-интерфейса.