I need to create a COM class in .NET8 that needs to be accessible to Excel.
After watching this video, I implemented the following test bed class:
namespace COMTestBedCS
{
[Guid("26a0aa6d-5aba-458f-92b4-b9a30ae0c65c")]
[GeneratedComInterface]
public partial interface ITestBed
{
int GetXPTO();
void SetXPTO(int value);
}
[Guid("3e178f98-522e-4e95-8a9c-6d80dc48b7d5")]
[GeneratedComClass]
public partial class TestBed : ITestBed
{
private int _XPTO = 1024;
public int GetXPTO() => _XPTO;
public void SetXPTO(int value)=>_XPTO = value;
}
}
The project compiles correctly, without errors. However, when I try to reference this test bed in Excel, I get the following error: Can't add a reference to the specified file.
If I try to use regsvr32
, I get the following error:
What am I doing wrong?
For completion sake, here’s the project file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
</Project>
Update
I was able to compile the code correctly and register it using regsvr32
. However, I’m still unable to reference it in Excel.
First, I can’t find it on the reference list. If I try to browse for the dll
(either the assembly or the comhost), it fails with the message: Can't add a reference to the specified file.
All that’s left now it to add it as a Reference in the Excel VBA.
New Code
Project
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RootNamespace>COMTestBedCS</RootNamespace>
<TargetFramework>net8.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<EnableComHosting>true</EnableComHosting>
<RegisterForComInterop>True</RegisterForComInterop>
<Platforms>x86</Platforms>
<RegisterAssemblyMSBuildArchitecture>x86</RegisterAssemblyMSBuildArchitecture>
</PropertyGroup>
</Project>
Code
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
namespace COMTestBedCS
{
[Guid("26a0aa6d-5aba-458f-92b4-b9a30ae0c65c")]
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ITestBed
{
int GetXPTO();
void SetXPTO(int value);
}
[Guid("3e178f98-522e-4e95-8a9c-6d80dc48b7d5")]
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
internal class TestBed : ITestBed
{
private int _XPTO = 1024;
public int GetXPTO() => _XPTO;
public void SetXPTO(int value)=>_XPTO = value;
}
}
OBS.: To compile successfully, I had to, for some reason, build the project twice. The first time Visual Studio is unable to successfully build, with the following error:
MSB3217
Cannot register assembly "<assembly file>" Could not load file or
assembly 'System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies.
The system cannot find the file specified.`
Then I have to rebuild it again without cleaning the project.
Only then the project compile successfully.
Update 2
If anyone wants to help, I put this test bed project on GitHub here.
2
Answers
<EnableComHosting>true</EnableComHosting>
property into the<PropertyGroup>
in the csproj. This will telldotnet
to generate*.comhost.dll
.TestBed
classinternal
instead ofpublic
. This will solve the build problem (I don’t know why, but from a general point of view, the implementation (theTestBed
class) should not be accessible outside the assembly in any way other than the generated factory).First, you must follow what’s detailed here Expose .NET Core components to COM, Generate the COM host:
But doing this will raise "The "GenerateClsidMap" task failed unexpectedly." error, as explained here:
SYSLIB diagnostics for COM interop source generation
GeneratedComInterfaceAttribute
is a new to .NET 8 feature, that you can’t use here in this scenario (exposing and hosting your own interfaces), so you’ll have to replace your code by something like this to revert back to "built-in" COM interop:Once the project is build, you can call
regsvr32 <myfile>.comhost.dll
(which has been generated by .NET Core) with sufficient rights.PS: You cannot use the
RegisterForComInterop
.csproj directive anymore as it’s reserved for .NET Framework (it internally uses the same code asRegasm
which you cannot use either).