3
votes

I've imported a type library into Delphi XE2 that has many dispinterfaces. Most of them have had an autocreated coclass and corresponding delphi T interface automatically created.

However, some of the dispinterfaces that I need to work with have no classid; I've tried every example that I could find on the net to utilize the dispinterface(s) in question. Here's what the interface looks like:

DIID_ITableListener: TGUID = '{83D42EA5-2C18-46EB-823B-262D62DF8CF1}';
... 
ITableListener = dispinterface;
...
// *********************************************************************//
// DispIntf:  ITableListener
// Flags:     (4096) Dispatchable
// GUID:      {83D42EA5-2C18-46EB-823B-262D62DF8CF1}
// *********************************************************************//
ITableListener = dispinterface
  ['{83D42EA5-2C18-46EB-823B-262D62DF8CF1}']
  procedure Added(const rowID: WideString; const rowDataObj: IRow); dispid 1610743809;
  procedure Changed(const rowID: WideString; const rowDataObj: IRow); dispid 1610743810;
  procedure Deleted(const rowID: WideString; const rowDataObj: IRow); dispid 1610743811;
  procedure StatusChanged(status: TableStatus); dispid 1610743812;
end;

Here's an example from another interface in the type library wrapper that uses this dispinterface:

procedure subscribeUpdate(updateType: TableUpdateType; const listenerObj: ITableListener);

Here's a VB.NET example that is provided that explains how the dispinterface is supposed to be used:

' If you want to use methods of the ITableListener interface, you must create a 
' class that+ implements the interface. For example,

public class TableListener implements ITableListener { }

' In your application you must create an instance of the class that implements  
' the interface. For example,

TableListener tableListener = new TableListener();

With no ClassID how do I implement this in Delphi? How do I do an instantiation? I thought it would have something to do with implementing an IDispatch interface descendant, but again without a ClassID I couldn't find a way to make this work.

Help!

Thanks.

2
You're supposed to implement this interface, so you can use whatever ClassID you feel like. - Eric Brown
To elaborate on Eric's comment, ITableListener is an event sink interface, as evident by the fact that it is declared as a DIID. You are supposed to write a class in your own code that implements that interface (you do not need a ClassID for that) and then instantiate that class and pass it to another COM object via its subscribeUpdate() method. That allows the COM object to then use your ITableListener to send events to you when it needed to. - Remy Lebeau
Thanks Eric and Remy for the replies. I did create a class, but I couldn't figure out with the examples that I was able to find both in help and online how to do this and have it work. I did create a class as a descendant of TObject, I believe I also tried descending from TInterfacedObject as well. However the interface calls specifically require a parameter of type ITableListener. When I tried passing my class it would not accept it as it was of the wrong type. - DeCoder
Just an FYI, this is a .NET backend; I don't know how that affects the details but thought I should point it out. Does anyone have an example? I've tried many different things and dumped about 8 hours into this to no avail... Thanks. - DeCoder
So far nothing works, out of all of the examples that I have been able to find. The bottom line is, the parameter that is passed requires the dispinterface type; it will not take any other type. So again I ask, how do you implement/instantiate a dispinterface in delphi? Examples, please. - DeCoder

2 Answers

1
votes

So I went through the sample provided in the link, and substituted your interfaces for the interfaces in the link, and came up with this:

ITableListener = dispinterface
  ['{83D42EA5-2C18-46EB-823B-262D62DF8CF1}']
  procedure Added(const rowID: WideString; const rowDataObj: IRow); dispid 1610743809;
  procedure Changed(const rowID: WideString; const rowDataObj: IRow); dispid 1610743810;
  procedure Deleted(const rowID: WideString; const rowDataObj: IRow); dispid 1610743811;
  procedure StatusChanged(status: TableStatus); dispid 1610743812;
end;

IMyTableListener = interface(IDispatch)
  ['{INSERT ARBITRARY GUID HERE}']
  procedure Added(const rowID: WideString; const rowDataObj: IRow); 
  procedure Changed(const rowID: WideString; const rowDataObj: IRow); 
  procedure Deleted(const rowID: WideString; const rowDataObj: IRow);
  procedure StatusChanged(status: TableStatus);
end;


TMyTableListener = class (TAutoObject, IMyTableListener)
public
  procedure Added(const rowID: WideString; const rowDataObj: IRow); 
  procedure Changed(const rowID: WideString; const rowDataObj: IRow); 
  procedure Deleted(const rowID: WideString; const rowDataObj: IRow);
  procedure StatusChanged(status: TableStatus);
end;

{ ... }
var
Disp: IDispatch;
Dispint: ITableListener;
{ ... }
// this may require that TMyTableListener is registered...
Disp := CreateComObject(TMyTableListener) as IDispatch;
// alternatively, try this (not sure about syntax):
Disp := new TMyTableListener as IDispatch;
Disp.AddRef();   // in C++, at least, creating the class via new() results in a 0 refcount, so you need to AddRef() so that releasing the object destroys the object appropriately...
Dispint := ITableListener(Disp);
subscribeUpdate(updateType, Dispint);
{ ... }
0
votes

This issue is solved. Please see Troubleshooting COM error "The parameter is incorrect".

Many thanks to @EricBrown and @RemyLebeau for their assistance.