將 .NET Core 元件公開給 COM

本文將逐步引導您瞭解如何從 .NET Core (或 .NET 5+) 將類別公開給 COM。 本教學課程會示範如何:

  • 從 .NET Core 向 COM 公開類別。
  • 在建置您的 .NET Core 程式庫時,一併產生 COM 伺服器。
  • 自動為 Registry-Free 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. 使用您要實作之 COM 介面的介面 GUID,將 [Guid("<IID>")] 屬性新增到介面。 例如: [Guid("fe103d6e-e71b-414c-80bf-982f18f6c1c7")] 。 請注意,因為對 COM 而言,此 GUID 是此介面的唯一識別碼,所以其必須是唯一的。 在 Visual Studio 中,您可以前往 [工具] > [建立 GUID] 開啟建立 GUID 工具,以產生 GUID。

  6. [InterfaceType] 屬性新增到介面,並指定您介面應實作的基底 COM 介面。

  7. 建立名為 Server 且實作 IServer 的類別。

  8. 使用您要實作之 COM 類別的識別碼 GUID,將 [Guid("<CLSID>")] 屬性新增到類別。 例如: [Guid("9f35b6f5-2c05-4e7f-93aa-ee087f6e7ab6")] 。 一如介面 GUID,因為對 COM 而言,此 GUID 是此介面唯一的識別碼,所以其必須是唯一的。

  9. [ComVisible(true)] 屬性新增到介面和類別。

重要

不同於 .NET Framework,.NET Core 會要求您為您希望可以透過 COM 啟動的所有類別指定 CLSID。

產生 COM 主機

  1. 開啟 .csproj 專案檔,然後在 <PropertyGroup></PropertyGroup> 標籤內新增 <EnableComHosting>true</EnableComHosting>
  2. 組建專案。

產生的輸出包含 ProjectName.dllProjectName.deps.jsonProjectName.runtimeconfig.jsonProjectName.comhost.dll 檔案。

為 COM 註冊 COM 主機

開啟提升權限的命令提示字元,然後執行 regsvr32 ProjectName.comhost.dll。 這會向 COM 註冊您所有的公開 .NET 物件。

啟用 RegFree COM

  1. 開啟 .csproj 專案檔,然後在 <PropertyGroup></PropertyGroup> 標籤內新增 <EnableRegFreeCom>true</EnableRegFreeCom>
  2. 組建專案。

產生的輸出現在還包含 ProjectName.X.manifest 檔案。 此檔案為並存資訊清單,可與 Registry-Free COM 搭配使用。

在 COM 主機中內嵌型別程式庫

不同於 .NET Framework,.NET Core 或 .NET 5+ 不支援從 .NET 組件產生 COM 型別程式庫 (TLB)。 指引是對於 COM 介面的原生宣告手動撰寫 IDL 檔案或 C/C++ 標頭。 如果您決定撰寫 IDL 檔案,您可以使用 Visual C++ SDK 的 MIDL 編譯器進行編譯,以產生 TLB。

在 .NET 6 和更新版本中,.NET SDK 支援將已編譯的 TLB 內嵌至 COM 主機,作為專案建置的一部分。

若要將型別程式庫內嵌至您的應用程式,請遵循下列步驟:

  1. 開啟 .csproj 專案檔,並且在 <ItemGroup></ItemGroup> 標記內新增 <ComHostTypeLibrary Include="path/to/typelib.tlb" Id="<id>" />
  2. <id> 取代為正整數值。 在您指定要內嵌在 COM 主機中的 TLB 之間,此值必須是唯一的。
    • 如果您只將一個 ComHostTypeLibrary 新增至專案,則 Id 屬性是選用的。

例如,下列程式碼區塊會將位在索引 1Server.tlb 型別程式庫新增至 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>

範例

GitHub 上的 dotnet/samples 存放庫提供功能完整的 COM 伺服器範例

其他注意事項

重要

在 .NET Framework 中,32 位和 64 位用戶端都可以取用「任何 CPU」元件。 根據預設,在 .NET Core、.NET 5 和更新版本中,「任何 CPU」元件會隨附 64 位 *.comhost.dll。 因此,這些只能由 64 位元用戶端取用。 這是預設的行為,因為這是 SDK 所代表的內容。 這種行為與發佈「獨立式」功能的方式相同:根據預設,這會使用 SDK 所提供的功能。 NETCoreSdkRuntimeIdentifier MSBuild 屬性會決定 *.comhost.dll 的位元。 受控元件實際上與預期無關,但伴隨的原生資產預設為目標 SDK。

不支援 COM 元件的獨立式部署。 僅支援 COM 元件的基礎結構相依部署

此外,將 .NET Framework 和 .NET Core 載入到相同的流程確實有診斷限制。 主要限制是受控元件的偵錯,因為無法同時偵錯 .NET Framework 和 .NET Core。 此外,這兩個執行階段執行個體不會共用受控組件。 這表示無法跨兩個執行階段共用實際的 .NET 類型,而所有互動都必須限制為公開的 COM 介面合約。