Monday, August 1, 2011

How To Write a C# 2010 DLL and Call It Within VB6 - CSharp Interoperability

Interoperability in C# is a real PITA. I know because I just spent the entire day chasing down a simple example. Unfortunately the C# documentation out there is so sparse and out of date (in this area the C# language seems to have changed quite a bit pre 2010) on the subject that doing a simple task like linking a C# dll from VB6 seems next to impossible. Maybe the topic is so mind numbingly simple that only pure C# neophytes struggle with something so mundane. But there is hope at the end of this rainbow. This short tutorial will give you the code necessary to write a simple C# 2010 DLL, and link that DLL via COM in VB6.

C# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;


namespace testMath
{
    public interface Math
    {
        int Multiply(int x, int y);
        int Add(int x, int y);
    }


    [ClassInterface(ClassInterfaceType.None)]
    public class Calc : Math
    {
        public int Multiply(int x, int y)
        {
            return(x * y);
        }


        public int Add(int x, int y)
        {
            return (x + y);
        }
    }
}
The public interface is what is shown in VB6 when you look at the referenced class's methods and properties. If the interface is excluded, the class shows up as not having any way to access the methods (interface-less).

The only real kicker is the [ClassInterface(ClassInterfaceType.None)] line that eliminates extraneous class interfaces, including the desired Multiply and Add functions from showing up in the interface. You can verify this by making the removing "public" from in front of the interface declaration.

However, because a public interface is declared with Multiply and Add, those interface elements show up in VB6 as if they were the actual functions, and because the class that inherits the ": Math" interface also contains the Multiply and Add functions, VB6 is none the wiser.

On the AssemblyInfo.cs page make sure you see the following line:
[assembly: ComVisible(true)]

If it is set to false, make the change. This can also be done from within the Visual Studio environment under the Project/Properties menu. Choose to "Register for COM interop" on the Build tab, and on the Application tab under Assembly Information, make sure to check that "Make assembly COM-Visible" is checked.

Note: the C# DLL was saved as testClass.dll.


VB6 code:

Option Explicit
Private o As testClass.Calc
Private Sub Form_Load()
    Set o = New testClass.Calc
    Debug.Print "testClass.Calc"
    Debug.Print o.Add(5, 10)
    Debug.Print o.Multiply(5, 5)
    Set o = Nothing
End Sub

Yes the VB6 end of the equation really is that simple. In the VB6 IDE, just add the reference to the .tlb that was created in C# under Project/References (menu) and you're good to go.

No comments: