Search code examples
c#wcfcom-interopregasm

Why would some classes in an assembly be exposed to to COM but not others?


I am struggling to produce a Class Library to be consumed by VBA. I have gotten one class in the Project to work, but the second does not seem to be being registered. If I use VBS to test, CreateObject("Libname.Class2") works, but CreateObject("Libname.Class1") gives an "ActiveX component can't create object" error. RegAsm isn't giving any useful feedback - it just says some types were exported but doesn't tell me why other types were not. I can also only find Class2 in OleView.

Most of the answers to questions relating to this sort of error refer to cases where the wrong version (x86/x64) of RegAsm was being used, but given that the one class is successfully registering I can't imagine that this is the case (I'm registering with both versions anyway). There were also some answers that suggested making sure there was something included in the default constructors so that they would not be optimised out, but that didn't seem to help either.

The two have the exact same attributes (apart from ProgId), and have relatively similar interfaces:

[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[ComVisible(true)]
public interface _Class1
{
    _Class2 GetClass2();

    string testertong { get; }
}

[ClassInterface(ClassInterfaceType.None)]
[ProgId("Libname.Class1")]
[ComVisible(true)]
class Class1 : _Class1
{
    private ...;

    public Class1 ()
    {
        /* Constructor stuff - commenting it out doesn't help */
    }

    public _Class2 GetClass2()
    {
        /* Generate and return an instance of Class2.  Tried return null too */
    }

    public string testertong
    {
        get
        {
            return "I love yams";
        }
    }
}

and

[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[ComVisible(true)]
public interface _Class2
{
    ArrayList GetLog(int entries);

    string testytest { get; }
}

[ClassInterface(ClassInterfaceType.None)]
[ProgId("Libname.Class2")]
[ComVisible(true)]
public class Class2 : _Class2
{
    internal IThing client;

    public Class2()
    {
        /* Currently empty but works fine */
    }

    public ArrayList GetSubmissionLog(int entries)
    {
        return new ArrayList(client.GetSubmissionLog(entries));
    }

    public string testytest
    {
        get { return "wololo"; }
    }
}

Class2 was actually the first of the two that I created and compiled. Class1 is effectively going to be a Factory object to be doing some WCF setup. I don't know if adding a class to a previously registered assembly would cause problems (and if so how I would fix it)?

The following VBS works as expected:

Set y = CreateObject("Libname.Class2")
Msgbox y.testytest

Any assistance is much appreciated


Solution

  • Class1 is implicitly internal since you don't specify a visibility level.

    Change it to

    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("Libname.Class1")]
    [ComVisible(true)]
    public class Class1 : _Class1
    {
    

    This is documented under ComVisibleAttribute:

    Only public types can be made visible. The attribute cannot be used to make an otherwise internal or protected type visible to COM or to make members of a nonvisible type visible.