Consuming .net Assemblies from VB6

-Basic COM interop

I spent a lot of time with my first interop project going through all the resources I could find on the subject. I found that many of the articles I managed to dig up did not cover the basics needed to get a simple ineterop project up and running.
Another lack in the existing library of interop articles is the bias towards writing articles describing the consumtion of COM libraries from .Net. My need has allways been the other way around: consuming .Net assemblies from VB6.
The best guide I found where a 15 seconds article by Patrick Steele: COM Interop Exposed. This article adressed most, if not all, of the issues i ran into with my first interop project. It also goes through the background needed for someone not previously exposed to the COM way of thinking to understand enough of what's going on behind the scenes.
My goal for this article is to make a basic step by step guide on getting the very simplest interop project up and running in your development enviroment.

A small disclaimer before I start: all these intsructions will refer to VS 2008 or newer togehter with Visual Basic 6.

An important fact about COM

COM components allways interacts through interfaces. If your method is not defined in an interface, it does not exist in COM.
This also means that static classes and methods can not exist in COM. As static methods can not be defined in an interface, and static classes can not implement interfaces.

What will need to be done

For my .Net class library to be available in VB6 I need to expose my methods and properties in a COM interface.
This COM interface is called a type library (.tlb files). Type libraries can be created with various tools, and in my guide I will let Visual studio create them for me. (See this article on tlbexp.exe for a 100% manual way creating type libaries)
The main part of getting interop to work is therefor to provide the automated type library tools with the information they need to create the COM interfaces (.tlb files). COM uses GUIDS to locate its interfaces and classes. Thus managing the GUIDS of your assembly is the main job of creating a COM enabled .Net assembly. If you mark your assembly to be COM visible, the compiler will generate some random GUIDS for your classes and Interfaces at compile time. This will get you into DLL versioning trouble! To take control, it is considered best practice to provide guids explicitly for each of the interfaces and classes you want to use through COM.
The other main thing is that if your class does not implement an interface, the type library generator will create an empty COM interface with no methods or properties. The type library generator reads only the first implemented interface, so you the interface defining your COM methods and properties must be the first.

Step 1: Create your project

Create a new Class library, save it, and make the following changes in the project properties:

  1. Open the Assembly information dialog, and check the box "Make assembly COM-visible". Also make sure the assembly has a GUID.
    Assemblyinfo.png
  2. In the Build properties of the project, check the box for "Register for COM interop".
    CAUTION: This setting indicates that Visual Studio should automatically create a type library, and register this type library in the registry when the project is built. This is only to save time during development, and you still have to make a plan for deployment!
    buildsettings.png
  3. Save the project

Step 2: Create your class

public class TextGetter
{
  public string GetSomeText()
  {
        return "I come from .Net"
  }
}

If you build the project now, the library will be available for reference in VB6, but no methods or properties will be exposed because no Interface is implemented

Step 3: Create and implement you interface

public interfcae ITextGetter
{
        string GetSomeText();
}

public class TextGetter : ITextGetter
{
  public string GetSomeText()
  {
        return "I come from .Net"
  }
}

Upon build there still will not be any methods visible in VB6. We have to tell the type library to use our interface, not the autogenerated one.

Step 4: Adding the Interop sugar

using System.Runtime.InteropServices;

namespace ClassLibrary1
{
    [Guid("68456B51-CB83-4220-81DC-F2B2256C06CE")]
    public interface ItextGetter
    {
                string GetSomeText();
    }
       
        [Guid("D0DF1E7A-A99D-4F2C-A5DF-29E0957F2F4E")]
        [ClassInterface(ClassInterfaceType.None)]
        public class TextGetter : ITextGetter
        {
                public string GetSomeText()
                {
                        return "I come from .Net"
                }
        }        
}

We have now taken control of the GUIDS, and using the [ClassInterface(ClassInterfaceType.None)] marker on the class tells the typelibrary generator not to autogenerate a COM interface but use the first one implemented by the class.
The namespace System.Runtime.InteropServices contains all methods used to control interop behaviour. In addition to Guid() and Classinterface() it contains methods for controlling COM visibility, ,marshalling of values and more

Thats it

Build the project, and add Classlibrary1 as a reference in VB6 (it is registered in the registry by Visual Studio, and available as any other library.) Use the object browser and observe that Classlibrary1 contains TetGetter with the GetSomeText Method.
Deployment of interop projects is another post in it self. For one approach read my earlier post on using RegFree deployment.

Summary of references for further reading

COM Interop Exposed
By Patrick Steele
http://www.15seconds.com/issue/040721.htm

Introduction to COM Interop (Visual Basic)
(MSDN)
http://msdn.microsoft.com/en-us/library/kew41ycz.aspx

Interop Marshaling
(MSDN)
http://msdn.microsoft.com/en-us/library/eaw10et3.aspx

Tlbexp.exe (Type Library Exporter)
(MSDN)
http://msdn.microsoft.com/en-us/library/hfzzah2c.aspx

Exposing .NET Framework Components to COM
(MSDN)
http://msdn.microsoft.com/en-us/library/zsfww439.aspx

Categories: