Having a very strange problem here. I'm attempting to make a .NET 8 library which will be called from Excel VBA via COM interop.
I've been following these two pieces of guidance:
Expose .NET Core components to COM
How to correctly create COM classes with .NET8?
Per that guidance, I've used the DSCOM tool to generate my .tlb file, which Excel can reference.
I've managed to make one working test class (with requisite interface), but I've been struggling to make a second one. My second test class was supposed to be more complicated, but through trial and error I made the second class simplier and simpler until I now have an exact duplicate of the first, working class, but with a different name.
Two classes and two interfaces, exactly the same members, differing only by name (and GUID). One set works, the other does not:
namespace MyTest.COM
{
[Guid("9d02f386-c90e-4353-964a-d3bdbad2c9f3")]
public class MyTestCOMDebug : IMyTestCOMDebug
{
public int Add(int x, int y) => x + y;
public string ToUpper(string s) => s.ToUpper();
}
[Guid("e6c5eb34-8412-4f17-a8e7-ef5e091841c5")]
public interface IMyTestCOMDebug
{
int Add(int x, int y);
string ToUpper(string s);
}
[Guid("f56b05d8-21aa-4ce8-8dd4-271eb102fea4")]
public class MyTestCOMDebug2 : IMyTestCOMDebug2
{
public int Add(int x, int y) => x + y;
public string ToUpper(string s) => s.ToUpper();
}
[Guid("23b13668-d7a3-4cfa-8a75-4a9063b2edb7")]
public interface IMyTestCOMDebug2
{
int Add(int x, int y);
string ToUpper(string s);
}
}
So I have MyTestCOMDebug : IMyTestCOMDebug and MyTestCOMDebug2 : IMyTestCOMDebug2. Same members, in the same file of the same project.
This is the project file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<EnableComHosting>true</EnableComHosting>
<EnableRegFreeCom>true</EnableRegFreeCom>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Runtime.InteropServices" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="dSPACE.Runtime.InteropServices.BuildTasks" Version="1.15.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<PropertyGroup>
<DsComTypeLibraryEmbedAfterBuild>true</DsComTypeLibraryEmbedAfterBuild>
<DsComOverideLibraryName>MyTest</DsComOverideLibraryName>
</PropertyGroup>
</Project>
I also have an AssemblyInfo.cs file with the following assembly-level attributes:
[assembly: ComVisible(true)]
[assembly: Guid("99134f79-a83c-4354-94f0-cfa52ea1ec0e")]
[assembly: ClassInterface(ClassInterfaceType.None)]
The following VBA code shows the test which is throwing the error:
Sub Test1()
Dim dbg As MyTest.IMyTestCOMDebug
Set dbg = CreateObject("MyTest.COM.MyTestCOMDebug")
Dim b As Integer
b = dbg.Add(2, 2)
MsgBox b
End Sub
Sub Test2()
Dim dbg As MyTest.IMyTestCOMDebug2
Set dbg = CreateObject("MyTest.COM.MyTestCOMDebug2")
Dim b As Integer
b = dbg.Add(2, 2)
MsgBox b
End Sub
Test1 runs without error and correctly outputs 4.
Test2 gives the following error:
Run-time error '429':
ActiveX component can't create object
This error occurs on the line:
Set dbg = CreateObject("MyTest.COM.MyTestCOMDebug2")
Now, why in the world does the first version of the class work, while the second one does not?
As you can see from the project file, I'm using registry-free COM, so there's no worry about having to unregister and re-register the library. I've made double sure that the file I'm testing with is the newly-built version. I've rebooted the computer. I'm testing with a completely new Excel file.
What am I missing here?
[ComDefaultInterface(typeof(IMyTestCOMDebug))]above the class declaration for MyTestCOMDebug and[ComDefaultInterface(typeof(IMyTestCOMDebug2))]above the class declaration for MyTestCOMDebug2. You may also consider adding[ComVisible(true)]above all of the class declarations and also above the interface definitions as shown in the Expose .NET Core components to COM that you mentioned in your post.ComDefaultInterfaceto both classes did not change the error. I already haveComVisible(true)set for the entire assembly (I've updated my question to show this now). Similarly, I've setClassInterface(ClassInterfaceType.None)for the entire assembly. I am intentionally leavingComInterfaceTypewith the default value.EnableRegFreeComdoes is it gets the toolchain to generate a .manifest file with the registration information. Key is what you do next with that file. You're supposed to pass it to the client programmer so they can embed it in their own app and use your library without having to register it. You probably see the problem now, this can't work for an Office app. You'll have to forget about registry-free COM. It probably worked for the first attempt because it relied on registry keys that were written before you tried to make EnableRegFreeCom work.