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
topMORE 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:
- The COM server fires the Initialize event, and then stores the value in a variable.
- 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 topClassic 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:
- In Microsoft Visual Studio .NET or Microsoft Visual Studio 2005, click
File and then click New Project.
- For Project Type, click Visual
C#. For Template, click Console Application.
- Name your project SampleClient, and
then click OK.
- In Solution Explorer, right-click
Reference, and then click Add Reference to
create a reference to MySrv COM object.
- Click the COM tab, and then select the MySrv COM object.
- Click OK.
- In Solution explorer, right-click SampleClient
, and then click Add Class to create the class for
handling events.
- Type MyEventsSink.cs in the text
box, click the Class template, and then click
Open.
- 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;
}
}
- 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 topMicrosoft .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 topProblems 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:
- To handle all nine methods in the interface, you create
nine delegates.
- These delegates generate nine event sinks.
- If the COM server fires one event method, the .NET
framework formulates nine calls to the default generated methods.
However:
- To handle three of the nine methods in the event interface,
you create three delegates.
- These delegates generate three event sinks.
- 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