Search code examples
c#delphicom.net-4.0

Exposing C# COM server events to Delphi client applications


My question is very similar to these two:

C# component events?

C# - writing a COM server - events not firing on client

However, what worked for them is not working for me. The type library file, does not have any hints of events definitions, so Delphi doesn't see it. The class works fine for other C# applications, as you would expect.

COM Server tools:

  • Visual Studio 2010
  • .NET 4.0

Delphi applications:

  • Delphi 2010
  • Delphi 7

Here's a simplified version of the code:

 /// <summary>
/// Call has arrived delegate.
/// </summary>
[ComVisible(false)]
public delegate void CallArrived(object sender, string callData);

/// <summary>
/// Interface to expose SimpleAgent events to COM
/// </summary>
[ComVisible(true)]
[GuidAttribute("1FFBFF09-3AF0-4F06-998D-7F4B6CB978DD")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IAgentEvents
{
    ///<summary>
    /// Handles incoming calls from the predictive manager.
    ///</summary>
    ///<param name="sender">The class that initiated this event</param>
    ///<param name="callData">The data associated with the incoming call.</param>
    [DispId(1)]
    void OnCallArrived(object sender, string callData);
}

/// <summary>
/// Represents the agent side of the system. This is usually related to UI interactions.
/// </summary>
[ComVisible(true)]
[GuidAttribute("EF00685F-1C14-4D05-9EFA-538B3137D86C")]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IAgentEvents))]
public class SimpleAgent
{
    /// <summary>
    /// Occurs when a call arrives.
    /// </summary>
    public event CallArrived OnCallArrived;

    public SimpleAgent() {}

    public string AgentName { get; set; }

    public string CurrentPhoneNumber { get; set; }

    public void FireOffCall()
    {
        if (OnCallArrived != null)
        {
            OnCallArrived(this, "555-123-4567");
        }
    }
}

The type library file has the definitions for the properties and methods, but no events are visible. I even opened the type library in Delphi's viewer to make sure. The Delphi app can see and use any property, methods, and functions just fine. It just doesn't see the events.

I would appreciate any pointers or articles to read.

Thanks!


Solution

  • I finally got this resolved after much trial and error. There were 2 things that I needed to change on the C# code.

    1) [ClassInterface(ClassInterfaceType.None)] needed to be changed to [ClassInterface(ClassInterfaceType.AutoDual)]

    2) The class that is the source of the events needs to inherit from MarshalByRefObject. This helps if there is any threading done in the source class.

    I only needed one thing on the Delphi side. I needed to make sure to have the "Generate Component Wrapper" checkbox checked. This is what will actually build the event scaffolding on Delphi's side.

    This is how you do it in Delphi 7:

    1. Select from the menu Project -> Import Type Library
    2. Make sure that "Generate Component Wrapper" is checked
    3. Select the COM class from the list
    4. Click on the "Add Unit" button

    The new unit will have the definitions of your COM events.

    Step-By-Step blog post on how to do this