How to establish a COM event sink with return values in the .NET Framework by using Visual Basic .NET or Visual Basic 2005 (810228)



The information in this article applies to:

  • Microsoft .NET Framework 2.0
  • Microsoft .NET Framework 1.0
  • Microsoft Visual Basic 2005
  • Microsoft Visual Basic .NET (2003)
  • Microsoft Visual Basic .NET (2002)

For a Microsoft Visual C# .NET version of this article, see 811645.

This article refers to the following Microsoft .NET Framework Class Library namespace:
  • System.Runtime.InteropServices

SUMMARY

This step-by-step article describes how to declare and establish a COM event sink by using sink objects in Microsoft Visual Basic .NET or in Microsoft Visual Basic 2005. The sample that appears in this article creates one sink object that implements all the events that are exposed by the COM server. The COM server uses return values from multiple events for later computations.

This article also describes the problems that may occur when you use a delegate model where the COM server cannot use return values from multiple events.

back to the top

MORE INFORMATION

Note This article assumes that MySrv is a user-defined COM server that is registered and exists on the system. The COM server exposes two events, Initialize and CanShutdown. The COM server uses these events as follows:
  1. The COM server fires the Initialize event, and then stores the value in a variable.
  2. The COM server fires the CanShutDown event, and then stores the value in a variable.
"Event source" refers to the COM server and "event sink" refers to the Microsoft .NET client throughout this article. For more information, visit the following Microsoft Web site:Microsoft .NET client consumes COM events by using the following:
  • A classic COM connection point model.
  • A Microsoft .NET delegate event model.
back to the top

Classic COM Connection Point Model

You can connect to a COM server by using the COM connection point interfaces from managed code. All COM event classes provide the IConnectionPointContainer interface. When you have the IConnectionPointContainer interface, you must find the specific connection point of the event interface that you want to subscribe to.
To use the classic COM connection point model, follow these steps:
  1. In Microsoft Visual Studio .NET or in Microsoft Visual Studio 2005, click File, and then click New Project.
  2. For Project Type, click Visual Basic. For Template, click Console Application.
  3. Name your project SampleClient, and then click OK.
  4. In Solution Explorer, right-click Reference, and then click Add Reference to create a reference to MyAtlSrv.
  5. Click the COM tab, and then click the MySrv COM object.
  6. Click OK.
  7. In Solution Explorer, right-click SampleClient, and then click Add Class to create the class for handling events.
  8. Type MyEventsSink.vb in the text box, click the Class template, and then click Open.
  9. To establish a COM event sink, use the following sample code to modify the existing MyEventsSink class:
       
    Imports MySrvLib
    Public Class MyEventsSink 
        Implements _IMySrvEvents
    
        Public Function CanShutdown() as Boolean Implements _IMySrvEvents.CanShutdown
            Console.WriteLine("CanShutdown interface method")
            Return True
        End Sub
    
        Public Function Initialize() as Boolean Implements _IMySrvEvents.Initialize
            Console.WriteLine("Initialize interface method")
            Return True
        End Sub
    
    End Class
     
  10. In the Main method of Module1.vb, use the FindConnectionPoint method to obtain the IConnectionPoint interface. To subscribe to the event, use the Advise method by using the following code:
     
    Imports MySrvLib
    Imports System.Runtime.InteropServices
    Module Module1
        Sub Main() 
            Dim cookie As Integer
            Dim mySink As MyEventsSink = New MyEventsSink()
            Dim myServerClass As MySrvClass = New MySrvClass()
            Dim icpc As UCOMIConnectionPointContainer = CType(myServerClass, UCOMIConnectionPointContainer)
            Dim icp As UCOMIConnectionPoint
            Dim IID_IMyEvents As Guid = GetType(_IMySrvEvents).GUID
            
            icpc.FindConnectionPoint(IID_IMyEvents, icp)
            icp.Advise(mySink, cookie)
    
           'Call to server function causes events to be raised. 
            myServerClass.SetParameter()
            icp.Unadvise(cookie)
        End Sub
    End Module
back to the top

Microsoft .NET Delegate Event Model

In the delegate event model, each time that an event handler is registered, a COM sink object is created. To use the delegate model for implementing the sink for MySrv server, you can implement two delegates. In the following pseudo code, two event handlers are registered. Therefore, two COM sink objects are created:
Imports MySrvLib
Public WithEvents mySvrc As New MySrvClass()
 ...
Public Function re_Initialize() As Boolean Handles mySvrc.Initialize
     Console.WriteLine("Initialize delegate")
     Return True
End Function

Public Function re_CanShutdown() As Boolean Handles mySvrc.CanShutdown
     Console.WriteLine("CanShutdown delegate")
     Return True
End Function
Sub Main
    mySvrc.SetParameter()
End Sub
...
This client pseudo code implements the two delegates as two complete IMyEvents sinks:
  • The first delegate sink implements the Initialize event by calling the re_Initialize delegate. The first event sink also provides default implementation for the CanShutdown event, and then returns false as a default value.
  • The second delegate sink implements the CanShutdown event by calling the re_CanShutdown delegate. The second event sink also provides default implementation for the Initialize event, and then returns false as a default value.
back to the top

Problems in the .NET Delegate Event Model with Return Values

The following problems occur:
  • The COM server fires the Initialize event for the first event sink, and then returns true from the re_Initialize delegate. Also, the COM server fires the CanShutdown event for the first event sink, and then always returns a default value of false. However, the expected behavior of the CanShutdown event is to return a value of true.
  • The COM server fires the Initialize event for the second event sink, and then always returns a default value of false. Also, the COM server fires the CanShutdown event for the second sink, and then returns true. However, the expected behavior of the Initialize event is to return a value of true.
These problems occur when you use the return values from events because the event source cannot distinguish between the default return value and the actual return value.

The delegate event model with COM event interfaces also introduces overheads. For example, if you have nine methods in an event interface:
  1. To handle all nine methods in the interface, you create nine delegates.
  2. These delegates generate nine event sinks.
  3. If the COM server fires one event method, the .NET Framework formulates nine calls to the default generated methods.
However:
  1. To handle three of the nine methods in the event interface, you create three delegates.
  2. These delegates generate three event sinks.
  3. If the COM server fires one event method, the .NET Framework formulates three calls to the default generated methods.
This behavior may not be acceptable.

To work around this behavior, create a .NET COM client by using the classic COM connection point model, as described in the "More Information" section of this article.

back to the top

Modification Type:MinorLast Reviewed:10/3/2006
Keywords:kbvs2005applies kbvs2005swept kbActivexEvents kbEvent kbhowto KB810228 kbAudDeveloper