Click here to Skip to main content
11,928,078 members (43,181 online)
Click here to Skip to main content
Add your own
alternative version


25 bookmarked

C# COM Late Binding Event

, 21 Apr 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
This article is a guide to building a .NET component, using it in a VB6 project at runtime using late binding, attaching its events and get a callback.


This article is a guide to building a .NET component and using it in a VB6 project. There are many samples about this issue, so why did I write a new one? In my humble opinion, in other articles, the missing part is to attach its event at runtime. So in this article, we will build a .NET component, mark it as a COM visible component, use it at runtime in VB6 and attach to its events.

.NET - COM Interoperability

There is a great article about this issue written by KRISHNA PRASAD.N. actually, called .NET - COM Interoperability Calling .NET components from COM Client, .NET Marshalling , Interop marshaler, COM marshaler etc., issues are well explained.

You should also check C# COM if you need to remember how to create a C# COM Interop DLL step by step by RakeshGunijan.

Early vs Late Binding

Early binding and late binding have their own advantages and disadvantages. I won't dig into details. I mostly prefer late binding especially if I am using someone's API because late binding has the advantage of removing some of the version dependencies. If you have to use or distribute monthly updating API or application, believe me, late binding is a better option.

What is functionpointer

A function pointer is a convention that enables you to pass the address of a user-defined function as an argument to another function you've declared for use within your application.

What are the Options

We will build a COM interop, use it from VB6 at runtime (without adding any reference to our project) and attach to its events. Here are the options.

Option 1 - Using a Callback Function

Passing the address of our event as a function pointer from VB6 to C# and invoke it from C#. (Thanks to Misha Shneerson for solving this issue at MSDN Forums.)

public void AttachToAnEventMethod1(int address)
    CallBackFunction cb = (CallBackFunction)Marshal.GetDelegateForFunctionPointer
	(new IntPtr(address), typeof(CallBackFunction));

Option 2 - Using Reflection

Pass the consumer object and callback function's name from VB6 to C# and invoke the function from C# via reflection.

object objApp_Late = this.consumer;
Type objClassType = this.consumer.GetType();
object ret = objApp_Late.GetType().InvokeMember
	(this.callbackEventName, BindingFlags.InvokeMethod, null, objApp_Late, null);

Building C# COM

public class CsApiCore : _CsApiCore
    private string sessionID = "";
    public string SessionID
        get { return sessionID; }
        set { sessionID = value; }

    public event NotifyDelegate NotifyEvent;

    public CsApiCore()
        this.SessionID = System.Guid.NewGuid().ToString().ToUpper();

    public int Add(int a, int b)
        return a + b;

    public int MultiplyAndNotify(int a, int b)
        for (int i = 0; i < 2; i++)
        return a * b;

    private void notifyClients()
        if (NotifyEvent != null)

        if (this.consumer != null)
            object objApp_Late = this.consumer;
            Type objClassType = this.consumer.GetType();
            object ret = objApp_Late.GetType().InvokeMember(this.callbackEventName, 
		BindingFlags.InvokeMethod, null, objApp_Late, null);
        if (this.cb != null)

    private object consumer = null;
    private string callbackEventName = "";

    public void AttachToAnEventMethod2(object consumerObject, string eventName)
        this.consumer = consumerObject;
        this.callbackEventName = eventName;

    public void DetachMethod2()
        this.callbackEventName = "";
        this.consumer = null;

    public void AttachToAnEventMethod1(int address)
        CallBackFunction cb = (CallBackFunction)
	Marshal.GetDelegateForFunctionPointer(new IntPtr(address), 
    public void DetachMethod1()
        this.cb = null;

    private Delegate cb = null;
    public void SetCallbackMethod1([MarshalAs(UnmanagedType.FunctionPtr)] 
	CallBackFunction callback)
        this.cb = callback;

We built a simple class for test purposes. Our aim is to attach to an event and when we execute MultiplyAndNotify method at runtime, get a feedback from VB6.

Using C# COM from VB6

We first need to connect to the C# COM using late binding.

Dim apiHandler  As Object
Dim obj As Object
Set obj = CreateObject("CSharpApi.CsApiCore")
If obj Is Nothing Then
    MsgBox ("Could not start Cs Api")
    Set apiHandler = obj
End If

We may test if everything works fine. We'll use CallByName function. The CallByName() function is used to manipulate objects by either executing a method or setting the value of a property.

Dim sRet As String
sRet = CallByName(apiHandler, "SessionID", VbGet)
Msgbox sRet

What we need to do is to use method 1, attach to a C# event, execute a method (MultiplyAndNotify), and get a callback from VB6.

Dim functinPointerAddress As Long
functinPointerAddress = getAddressOfFunction(AddressOf Vb6NotifyEventOnModule)
Dim o As Object
Set o = Me
ret = CallByName(apiHandler, "AttachToAnEventMethod1", VbMethod, functinPointerAddress)
ret = CallByName(apiHandler, "MultiplyAndNotify", VbMethod, 3, 5)
Dim oRet
oRet = CallByName(apiHandler, "DetachMethod1", VbMethod)
MsgBox ret

Using the Code

Download the source files. You will see a CsApiTestSln.sln solution file. Open and build solution. CsApiTest is a main API project in this solution. You may use CsApiConsumer C# project to debug the main API. In CsApiTest\bin\Debug subdirectory, you'll see a VB6 project called CsApiVb6Test.vbp. This is a VB6 client made for using the main API.


Limitation of AddressOf function is: You can only retrieve the address of a function or sub (public or private) contained within a Standard VB Module. There's no way around this. So if you use method1, your callback function or event must be contained within a Standard VB Module (bas file).

If you decide to use method 2, you have to pass an object and an event name and invoke it from C#. In this case, you may use a class module or a form (as you can see in the VB6 sample project).

Decide on a method according to your needs.



  • 21st April, 2010: Initial post


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Software Developer (Senior) MikroKom Yazilim A.S.
Turkey Turkey
c# , vb6 , mssql , oracle , mysql , asp , developer.

You may also be interested in...

Comments and Discussions

GeneralMy vote of 4 Pin
Amir Mohammad Nasrollahi15-Aug-13 0:41
professionalAmir Mohammad Nasrollahi15-Aug-13 0:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.151126.1 | Last Updated 21 Apr 2010
Article Copyright 2010 by yincekara
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid