June 1st, 2007

So what does ComClass actually do?

I came across a really cool article yesterday by James Ashley, which shows some of the cool things you can do with the Interop Forms Toolkit 2.0.   The three VB6 examples cover consuming a WebService (complete with a Dilbert icon showing up in the VB6 toolbox!), implementing multithreading using the BackgroundWorker component, and last but not least a cool WPF cube.   Best of all there’s tons of code samples and  no less than *15* screenshots!

 

Along with the samples there’s also some C# translations of the templates that ship with the Interop Toolkit.  While playing with these templates I was reminded of some of the subtle differences in how the VB and C# compilers handle COM Interop.  The biggest difference is in how they handle the ComClass attribute, which we’ll see by looking at some code:

 

    public event System.EventHandler ButtonClicked;

 

    private void button1_Click(object sender, System.EventArgs e)

    {

        if (null!=this.ButtonClicked)

            this.ButtonClicked.Invoke(this, e);

    }

 

    Public Event ButtonClicked As System.EventHandler

 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        RaiseEvent ButtonClicked(Me, e)

    End Sub

 

In both cases we’re exposing a public event, and invoking it when the button is clicked.  By using Reflector, let’s look at what gets generated under the covers:

 

C#

[ComClass("c6cbbae7-44b8-422e-840f-cbaba8e3238c", "bf3ef778-6ca7-4ec8-a045-87be56528803", "37b0d42a-6740-45ec-adc6-38fcbcdc48e4")]
public class InteropUserControl : UserControl

{

…

}

 

VB

<DesignerGenerated(), ComClass(“a2ee6169-9a0d-4930-b8bb-ee71307c43b3”, “75ff3d57-6448-40ac-a294-68252180cacd”, “2b04895c-43f8-44b3-b187-00556ef53a6a”), Guid(“a2ee6169-9a0d-4930-b8bb-ee71307c43b3”), ClassInterface(ClassInterfaceType.None), ComSourceInterfaces(“VBControl.InteropUserControl+__InteropUserControl”)> _

Public Class InteropUserControl

    Inherits UserControl

    Implements _InteropUserControl

 

…

 

<InterfaceType(ComInterfaceType.InterfaceIsIDispatch), Guid(“2b04895c-43f8-44b3-b187-00556ef53a6a”), ComVisible(True)> _

Public Interface __InteropUserControl

    <DispId(1)> _

    Sub Click()

    <DispId(2)> _

    Sub DblClick()

    <DispId(3)> _

    Sub ButtonClicked(ByVal sender As Object, ByVal e As EventArgs)

End Interface

 

<Guid(“75ff3d57-6448-40ac-a294-68252180cacd”), ComVisible(True)> _

Public Interface _InteropUserControl

    <DispId(1)> _

    Property Visible() As Boolean

    <DispId(2)> _

    Property Enabled() As Boolean

    <DispId(3)> _

    Property ForegroundColor() As Integer

    <DispId(4)> _

    Property BackgroundColor() As Integer

    <DispId(5)> _

    Property BackgroundImage() As Image

    <DispId(6)> _

    Sub Refresh()

End Interface

End Class

 

The VB compiler has generated two extra interfaces and applied the ComSourceInterfaces attribute to the control, which it knows to do when it sees the ComClass attribute.  ComSourceInterfaces is used to link the event sink interface to the class.  (<ComClass> actually does a lot more than just making events work automatically, but we’ll leave that until another day).

 

What this means is that the VB.NET-compiled event will be visible in VB6, whereas using the C# compiler we’d have to define this interface ourselves.  This also means that certain members the template adds like Visible, ForegroundColor, Refresh etc. are automatically exposed by the VB compiler; it’s still possible to do this in C#, it just takes some extra steps.

 

Both VB and C# offer a lot of powerful features you can use to extend VB6, but it’s important to be aware of the differences, especially when working with events.  For more information on the Interop Toolkit be sure to check out our webcast on Wednesday.  Also stay tuned to this blog for a series of Interop articles by Todd Apley, one of our QA leads.

 

Jonathan

Author

0 comments