Controlling the order of Get/Set property methods for .NET interfaces registered for COM Interop.

Some background information 1st. In C# when specifying an interface you can arbitrarily set the order of the get / set methods like such:

       public interface TestInterface

       {

              string k{get;}

              int i {get; set;}

              bool z {set; get;}

       }

So when you use tlbexp.exe the interface definition within the resulting TLB will be the same as was specified in the C# code above.

Things are different in VB.NET. While this works find and dandy for a class definitions it is not so nice for an interface. VB doesn’t necessitate you specify the get/set properties (Instead you specify the ReadOnly and WriteOnly modifiers to either exclude the set or get methods respectively).

Consider the following VB code:

Public Class ComClass1

    Public Sub New()

        MyBase.New()

    End Sub

    Public Property s() As String

        Get

        End Get

        Set(ByVal Value As String)

        End Set

    End Property

    Public Property t() As String

        Set(ByVal Value As String)

        End Set

        Get

     End Get

    End Property

End Class

Public Interface test

    Property k() As String

    Property i() As Integer

    Property z() As Boolean

End Interface

Here’s the interface created by tlbexp.exe:

dispinterface _ComClass1 {

    properties:

    methods:

        [id(0x00000001), propget]

        BSTR s();

        [id(0x00000001), propput]

        void s([in] BSTR rhs);

        [id(0x00000002), propput]

        void t([in] BSTR rhs);

        [id(0x00000002), propget]

        BSTR t();

};

    interface test : IDispatch {

        [id(0x60020000), propget]

        HRESULT k([out, retval] BSTR* pRetVal);

        [id(0x60020000), propput]

        HRESULT k([in] BSTR pRetVal);

        [id(0x60020002), propput]

        HRESULT i([in] long pRetVal);

        [id(0x60020002), propget]

        HRESULT i([out, retval] long* pRetVal);

        [id(0x60020004), propget]

        HRESULT z([out, retval] VARIANT_BOOL* pRetVal);

        [id(0x60020004), propput]

        HRESULT z([in] VARIANT_BOOL pRetVal);

    };

As you can see the code within the class creates the TLB in the order we would expect but in the interface we get alternating results. I added another property to the code above and low and behold the pattern continues!? Or does it?

        [id(0x60020006), propget]

        HRESULT q([out, retval] VARIANT* pRetVal);

        [id(0x60020006), propputref]

        HRESULT q([in] VARIANT pRetVal);

Looks like the dev’s for this tool played some nice tricks on us! J  Actually it’s how the IL winds up being spit out by the compiler and not tlbexp.exe that’s at fault. If you look at the IL code using ILDASM.exe you’ll see that tlbexp.exe generates the TLB in the order of the methods as they are found within the IL code.

I have four recommendations on how to circumvent this:

1. the infamous “this is by design” and that’s just how it’s going to work J

2. Implement a base interface in C# (specifying the property order) and then have the VB interface inherit from this interface. This is very clumsy and if you are willing to do this I would just create the interface in C# and be done with it.

3. You can implement their interface in the order in which you would like the interface to be created and then use regasem.exe /tlb to generate the TLB for the object that implements the interface..

4. If you really, really wants to do this from vb and have the interfaces in the correct order you can manipulate the MSIL code for the compiled assembly that contains the interface and then recompile the updated IL code with ilasm.exe and the use tlbexp.exe to create the TLB.