A group blog from members of the VB team
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)
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)
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:
[ComClass("c6cbbae7-44b8-422e-840f-cbaba8e3238c", "bf3ef778-6ca7-4ec8-a045-87be56528803", "37b0d42a-6740-45ec-adc6-38fcbcdc48e4")]
public class InteropUserControl : UserControl
<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
<InterfaceType(ComInterfaceType.InterfaceIsIDispatch), Guid("2b04895c-43f8-44b3-b187-00556ef53a6a"), ComVisible(True)> _
Public Interface __InteropUserControl
Sub ButtonClicked(ByVal sender As Object, ByVal e As EventArgs)
<Guid("75ff3d57-6448-40ac-a294-68252180cacd"), ComVisible(True)> _
Public Interface _InteropUserControl
Property Visible() As Boolean
Property Enabled() As Boolean
Property ForegroundColor() As Integer
Property BackgroundColor() As Integer
Property BackgroundImage() As Image
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.
I am most indebted to you for explaining why events weren't working in the C# UserControl templates. The problem was actually brought to my attention by a reader of the referenced article. I started searching the web to find what the VB compiler was doing that the C# compiler wasn't (looking at the two versions of the code with the MS Disassembler indicated that they were very different), and it finally occurred to me to check the VB Team blog for any insights -- and sure enough, here it was.
As you said, the problem isn't too difficult to overcome once you realize what the VB compiler is doing behind the scenes. I've updated the C# interop templates to include the extra interfaces that the VB compiler writes for us automatically.
Again, thank you so much for your insight and help (as well as your kind words about the article itself).
I just wanted to swiftly share some useful links if you choose to extend a Visual Basic 6.0 application