Search code examples
c#comintellisense

How do I create a COM object with child objects without displaying the base methods, Equals(), GetHashCode(), GetType(), ToString() in Intellisense?


I would like to have my classes exposed without displaying the base methods Equals(), GetHashCode(), GetType(), ToString(). I also want Intellisense to work properly. Here is my sample code:

using System;
using System.IO;
using System.Runtime.InteropServices;

namespace InteropTest
{
    [ClassInterface(ClassInterfaceType.AutoDual),
        ComVisible(true)]
    [ProgId("InteropTest.Wrapper")]
    public class Wrapper
    {
        public string Text1 = "hello";
        public string Text2 = "world";
        public Class1 Class1 = new Class1();
        public Class2 Class2 = new Class2();

    }

    [ClassInterface(ClassInterfaceType.AutoDual),
        ComVisible(true)]
    public class Class1
    {
        public string Method1a(string myText)
        {
            return myText;
        }

        public string Method1b(string myText)
        {
            return myText;
        }
    }

    [ClassInterface(ClassInterfaceType.AutoDual),
        ComVisible(true)]
    public class Class2
    {
        public string Method2a(string myText)
        {
            return myText;
        }

        public string Method2b(string myText)
        {
            return myText;
        }
    }
}

When I use [ClassInterface(ClassInterfaceType.None), ComVisible(true)], I can see the 2 properties in the Wrapper class, but I cannot see, nor access, Class1 or Class2.

When I use this class, I expect to be able to create the object and use it as well as see the appropriate Intellisense for the inner class objects.

o = CreateObject("InteropTest.Wrapper")
o.Class1.Method1a("Some text")

I guess, my real question is, how do I setup my classes for COM and make both Class1 and Class2 visible without displaying the extra methods?

I also tried using the refactor tool to extract the interfaces, but I could not get those to work the way I want to work, either. I don't want to put in any funky work-arounds, either.


Solution

  • Using AutoDual on classes exposes every public method of the class automatically. To avoid that you can use AutoDual interfaces instead and implement it. Something like this should be equivalent:

    [InterfaceType(ComInterfaceType.InterfaceIsDual), ComVisible(true)]
    public interface IWrapper
    {
        string Text1 { get; set; }
        string Text2 { get; set; }
        IClass1 Class1 { get; set; }
        IClass2 Class2 { get; set; }
    }
    
    [ClassInterface(ClassInterfaceType.None), ComVisible(true)]
    [ProgId("InteropTest.Wrapper")]
    public class Wrapper : IWrapper
    {
        public string Text1 { get; set; } = "hello";
        public string Text2 { get; set; } = "world";
        public IClass1 Class1 { get; set; } = new Class1();
        public IClass2 Class2 { get; set; } = new Class2();
    }
    
    [InterfaceType(ComInterfaceType.InterfaceIsDual), ComVisible(true)]
    public interface IClass1
    {
        string Method1a(string myText);
        string Method1b(string myText);
    }
    
    [ClassInterface(ClassInterfaceType.None), ComVisible(true)]
    public class Class1 : IClass1
    {
        public string Method1a(string myText) => myText;
        public string Method1b(string myText) => myText;
    }
    
    [InterfaceType(ComInterfaceType.InterfaceIsDual), ComVisible(true)]
    public interface IClass2
    {
        string Method2a(string myText);
        string Method2b(string myText);
    }
    
    [ClassInterface(ClassInterfaceType.None), ComVisible(true)]
    public class Class2 : IClass2
    {
        public string Method2a(string myText) => myText;
        public string Method2b(string myText) => myText;
    }
    

    Note .NET fields have been replaced by .NET properties since you cannot define fields in interfaces, but at COM level it shouldn't change anything.