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



The information in this article applies to:

  • Microsoft .NET Framework
  • Microsoft Visual C# .NET (2002)
  • Microsoft Visual C# 2005, Express Edition

For a Microsoft Visual Basic .NET version of this article, see 810228.

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 C# .NET or Visual C# 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 variable.
"Event source" refers to 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 connect 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 connection point model, follow these steps:
  1. In Microsoft Visual Studio .NET or Microsoft Visual Studio 2005, click File and then click New Project.
  2. For Project Type, click Visual C#. 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 MySrv COM object.
  5. Click the COM tab, and then select 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.cs in the text box, click the Class template, and then click Open.
  9. To establish a COM event sink, use the following code to modify the existing MyEventsSink class:
       
        using System;
        using System.Runtime.InteropServices;
        using MySrvLib;
        class MyEventsSink  : _IMySrvEvents
        {
            public MyEventsSink (){}
            public bool CanShutDown()
            {
                Console.WriteLine("CanShutdown interface method");
                return true;
            }
    
            public bool Initialize()
            {
                Console.WriteLine("Initialize interface method");
                return true;
            }
    
        } 
  10. In the Main function of Class1.cs, use the FindConnectionPoint method to obtain the IConnectionPoint interface. To subscribe to the event, use the Advise method. To do this, use the following code:
     
    using System;
    using System.Runtime.InteropServices;
    using MySrvLib;
    
    namespace SampleClient
    {
        /// <summary>
        /// Summary description for Class1.
        /// </summary>
        class Class1
        {
            /// <summary>   
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main(string[] args)
            {
                try
                {  
                    int cookie;
                    MyEventsSink  mySink;
                    mySink = new MyEventsSink  ();
                    MySrvClass  myServerClass = new MySrvClass() ;
                    UCOMIConnectionPointContainer icpc = (UCOMIConnectionPointContainer)myServerClass;
                    UCOMIConnectionPoint icp;
                    Guid IID_IMyEvents = typeof(_IMySrvEvents).GUID;
                    
                    icpc.FindConnectionPoint(ref IID_IMyEvents,out icp);
                    icp.Advise(mySink,out cookie);
    
                   //Call to server function causes events to be raised.
                    myServerClass.SetParameter ();
                    
                    icp.Unadvise(cookie);
                }
                catch(Exception ex)
                {
                    Console.WriteLine (ex.Message );
                }
                
            }
        }
    }
    
back to the top

Microsoft .NET Delegate Event Model


In the delegate 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:
MySrvClass mySvrcClass;
mySvrcClass = new CTestClassClass ();

// Register first delegate
mySvrcClass.Initialize += new  _IMySrvEvents_InitializeEventHandler(this.re_Initialize);

// Register second delegate.
mySvrcClass.CanShutDown  += new  _IMySrvEvents_CanShutDownEventHandler (this.re_CanShutDown);            
...
private bool re_CanShutDown()
{
    Console.WriteLine("CanShutdown delegate")
    return true;
}
private bool re_Initialize()
{
   Console.WriteLine("Initialize delegate")
    return true;
}
...
The 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 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 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 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.

Delegate 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 workaround 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:MajorLast Reviewed:1/17/2006
Keywords:kbActivexEvents kbEvent kbhowto KB811645 kbAudDeveloper