I'm involved in creating a COM interface from a C# 4.0 library. This took a lot of hair-pulling and banging-head-against-the-wall moments. This skillset appears to be quickly disappearing; sad, but quite understandable. I wanted to store how this is done, because I found many little slivers across the Intertubes, but nowhere did I find the slivers put into a coherent picture.
I'm going to use a simple class that I'm calling ComDog. Here is the definition:
using System;
using System.Runtime.InteropServices;
namespace ComDog
{
[ComVisible(false)]
public delegatevoid DogEventHandler();
[ComVisible(true)]
[Guid("2406DD50-A3CE-43A6-9F20-112B621CB784")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
public interfaceIDogEvents
{
[DispId(1)]
void Bark();
[DispId(2)]
void Howl();
[DispId(3)]
void Eat();
}
[ComVisible(true)]
[Guid("8C6DAD17-0612-4166-AD35-3A55DDEAF62E")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComSourceInterfaces(typeof(IDogEvents))]
public class Dog : MarshalByRefObject
{
public event DogEventHandler Bark;
public event DogEventHandler Howl;
public event DogEventHandler Eat;
public void MakeDogBark()
{
if (Bark != null)
{
Bark();
}
}
public void MakeDogHowl()
{
if (Howl != null)
{
Howl();
}
}
public void MakeDogEat()
{
if (Eat != null)
{
Eat();
}
}
}
Now let's get this compiled and registered. To get this registered with COM, well need to issue this command, in an elevated command prompt:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm comdog.dll /tlb:ComDog.tlb
Now on to Delphi 7...
Copy both the ComDog.dll and ComDog.tlb to the same folder as your Delphi project. I'm doing this, because I don't want to mess with the GAC.
In the Delphi IDE, select Project --> Import Type Library. It will look like this:

This in turn, should show the Import Type Library dialog, that looks like this:

If you registered the assembly (dll in .NET parlance), you should see an entry for ComDog, like the selected one in the dialog above. Click on the "Create Unit" button. This will add a "ComDog_TLB.pas" file to your Delphi project.

One important section that I want to direct your attention to:
// *********************************************************************//
// OLE Server Proxy class declaration
// Server Object : TDog
// Help String :
// Default Interface: _Dog
// Def. Intf. DISP? : No
// Event Interface: IDogEvents
// TypeFlags : (2) CanCreate
// *********************************************************************//
{$IFDEF LIVE_SERVER_AT_DESIGN_TIME}
TDogProperties= class;
{$ENDIF}
TDog = class(TOleServer)
private
FOnBark: TNotifyEvent;
FOnHowl: TNotifyEvent;
FOnEat: TNotifyEvent;
FIntf: _Dog;
The events are of type TNotifyEvent, because they do not have parameters. This comes from the IDogEvents. Delphi will ALWAYS use the definition in your event interface, instead of the events listed in the main class. Make absolutely sure that the signature in the event interface match the signature of the events in your main C# class.
Here is what the definition of the events will look like in your Delphi main form/unit:
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ActiveX, ComObj, ComDog_TLB, StdCtrls, OleServer;
type
TForm1 = class(TForm)
btnBark: TButton;
btnHowl: TButton;
btnEat: TButton;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure btnBarkClick(Sender: TObject);
procedure btnHowlClick(Sender: TObject);
procedure btnEatClick(Sender: TObject);
private
{ Private declarations }
protected
procedure Barked(Sender: TObject);
procedure Howled(Sender: TObject);
procedure Ate(Sender: TObject);
public
{ Public declarations }
end;
var
Form1: TForm1;
TestDog: TDog;
The proctected section above defines the events. This you will have to type manually. Make sure that your _TLB file is listed in the uses section above.
Now to actually have the events handled, you will have to create a procedure that matches the signature of event. Like so:
procedure TForm1.Barked(Sender: TObject);
begin
Memo1.Lines.Add('Dog Barked');
end;
procedure TForm1.Howled(Sender: TObject);
begin
Memo1.Lines.Add('Dog Howled');
end;
procedure TForm1.Ate(Sender: TObject);
begin
Memo1.Lines.Add('Dog ate something');
end;
This is how you wire up C# COM events up to a Delphi COM client app.
The next question is how to deal with events that have parameters. It's basically the same thing. You'll just have to make sure that the signatures for event definitions and event handlers in Delphi, match what's in the _TLB file.
I did a lot of hair-pulling in order to get this working. I wanted to post this in my blog, for the next time I'm doing this. Please feel free to comment here, if you need more help.