The Artima Developer Community
Sponsored Link

.NET Buzz Forum
Multiple eventsinks on a (Delphi) automation object. How to turn a single cast delegate into a...

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Peter van Ooijen

Posts: 284
Nickname: petergekko
Registered: Sep, 2003

Peter van Ooijen is a .NET devloper/architect for Gekko Software
Multiple eventsinks on a (Delphi) automation object. How to turn a single cast delegate into a... Posted: Mar 23, 2006 3:32 AM
Reply to this message Reply

This post originated from an RSS feed registered with .NET Buzz by Peter van Ooijen.
Original Post: Multiple eventsinks on a (Delphi) automation object. How to turn a single cast delegate into a...
Feed Title: Peter's Gekko
Feed URL: /error.htm?aspxerrorpath=/blogs/peter.van.ooijen/rss.aspx
Feed Description: My weblog cotains tips tricks and opinions on ASP.NET, tablet PC's and tech in general.
Latest .NET Buzz Posts
Latest .NET Buzz Posts by Peter van Ooijen
Latest Posts From Peter's Gekko

Advertisement

When you have a COM automation server your code can invoke methods and properties on the automation object. With a connectable COM object code invocations can go both ways. The consumer invokes methods and the server fires events. To subscribe to these events the client passes an event sink to the server. An event sink is an object which implements an interface with a (type library defined) set of event handling methods. This event sinking mechanism is defined very flexible, a full implementation of the COM IconnectionPointContainer  interface works with a collection of multiple types of eventsinks and each sink-type collection can manage any number of sinks.

In the real world the implementation of eventsinks is less elaborate. Notorious is the support in Delphi. A Delphi automation object accepts just one sink of one type. Borland can put the blame on that on Microsoft as the VCL (Delphi class library) code of their implementation is a straight C++ to Object Pascal port of the code found in the MS press book "OLE controls inside out". (Read here for a deeper story) Anyway, the fact that the Delphi automation object supports only one sink will give you a hard time in .NET.

These demo snippets are based on the sample for my COM in Delphi series. It is an in-process form to browse the file system. The automation object fires an event when the user selects another directory. At first sight working with the object in .NET is no big deal.

private FileManager.FileZapper fm;

private void Form1_Load(object sender, EventArgs e)

{

    fm = new FileManager.FileZapperClass();

    fm.OnDirectoryChanged += new FileManager.IFileZapperEvents_OnDirectoryChangedEventHandler(DisplayOnLabel);

    fm.OnDirectoryChanged += new FileManager.IFileZapperEvents_OnDirectoryChangedEventHandler(AddToListBox);

}

 

void DisplayOnLabel(string dirName)

{

    label1.Text = dirName;

}

 

void AddToListBox(string dirName)

{

    listBox1.Items.Add(dirName);

}

In this snippet a new automation object fm is instantiated and two handlers subscribe to the OnDirectoryChanged  event. One to display the current directory on a label, the other to add the history of the directories visited in a listbox. This code will build and run but the moment an event is fired in the automation object an exception is thrown. Each of the methods subscribing to the event takes a separate event sink and the Delphi automation object supports only one. In case only one eventhandler is subscribing the code will run without any problems.

There are two way to work around this. One is to extend the the Delphi framework class. Read here for a full story how to get that done. The other way is to find a workaround in the consuming client which I will describe here.

An event which can sink events to multiple eventhandlers subscribing is a multi cast delegate, an event which can sink only events to one subscriber is a single cast delegate. Delphi events are all single cast, .NET events are all multicast. To turn the single cast delegate in the automation class into a multi cast I will build a new class which inherits from the COM class and redefines the event.

class MyComServer : FileManager.FileZapperClass

{

     // Hide the event in the base class as it will fail on multiple event handlers

    public new event IFileZapperEvents_OnDirectoryChangedEventHandler OnDirectoryChanged;

    public new event IFileZapperEvents_OnSelectionChangedEventHandler OnSelectionChanged;

 

    private void MyComServer_OnDirectoryChanged(string DirName)

    {

        // fire eventhandler subscribed to this new implemenatation of the event

        this.OnDirectoryChanged(DirName);

    }

 

    private void MyComServer_OnSelectionChanged()

    {

        // fire eventhandler subscribed to this new implemenatation of the event

        this.OnSelectionChanged();

    }

 

    public MyComServer()

        : base()

    {

        // This is the one and only eventsink connected the COM server

        base.OnDirectoryChanged += new IFileZapperEvents_OnDirectoryChangedEventHandler(MyComServer_OnDirectoryChanged);

        base.OnSelectionChanged += new IFileZapperEvents_OnSelectionChangedEventHandler(MyComServer_OnSelectionChanged);

    }

 

}

The class inherits straight form the COM class. Both the OnDirectoryChanged and the OnSelectionChanged event are reintroduced with the new keyword. (You could override the events but this will force you to re-implement all other members as well, something which will not pop up until you try to run the code). These new events are normal .NET multicast delegates (read here for a deeper discussion on the difference between the event and delegate keyword). The class has two private methods to fire the event to all subscribers. These will be fired by the automation object itself. After executing the constructor of the base (COM) class the constructor of the inherited class passes the private members as eventsinks to the event in the COM baseclass.

Now all events are routed through this one event and the automation object only has one sink to take care of. The downside is that the automation object also has to sink events when nobody is actually subscribed to the events. In case that's an unaffordable overhead you have to do some optimization. But I hope you get the idea.

The code in the winform now changes to

private MyComServer fm;

private void Form1_Load(object sender, EventArgs e)

{

    fm = new MyComServer();

    fm.OnDirectoryChanged+= new FileManager.IFileZapperEvents_OnDirectoryChangedEventHandler(DisplayOnLabel);

    fm.OnDirectoryChanged += new FileManager.IFileZapperEvents_OnDirectoryChangedEventHandler(AddToListBox);

    fm.OnSelectionChanged += new FileManager.IFileZapperEvents_OnSelectionChangedEventHandler(MoveSlider);

}

And here's the almost old-fashioned looking Delphi6 form operating in the process of a .NET 2.0 winform and firing events on multiple handlers.

To quote Delphi eventsink master Binh Ly: (check his very handy COM registration tool):  have fun !

Read: Multiple eventsinks on a (Delphi) automation object. How to turn a single cast delegate into a...

Topic: DDD 3 session voting has started! Previous Topic   Next Topic Topic: Download Microsoft Expression previews - March CTP

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use