Resolved How to resolve EIntfCastError when calling function in an Active X DLL

MWENV

Member
Joined
Aug 4, 2022
Messages
10
Programming Experience
10+
I'm developing a C# class library which calls functions and procedures in an ActiveX DLL developed in Delphi. For discussion sake, I'll refer to the Delphi DLL as Delphi.dll and the C# class library as CSharp.dll. A reference to Delphi.dll has been added to the C# project.

Delphi.dll includes a TCollection class, functions Get_Count(), Get_Item(), and procedures Add(), Remove(). CSharp.dll is able to call Get_Count(), Add() and Remove() without any issues, however a call to Get_Item() raises the following error:
C#:
Type: EIntfCastError
Message: Interface not supported
Here's the declaration for Get_Item() in Delphi.dll:
C#:
function TCollection.Get_Item(Index: OleVariant): IDispatch;
begin
  Result := fList.Items[ConvertIndex(Index)] as IDispatch;
end;
Here's an example of CSharp.dll calling Get_Item():
C#:
aRecord = myCollection.GetItem(1)
Where myCollection is type (Delphi.dll).Collection and I've tried declaring aRecord as type dynamic, object and (Delphi.dll).Collection.

I believe the error is due to Get_Item() returning type IDispatch, which C# does not know how to handle.

What modifications do I need to make in C# to resolve this issue?
 
Last edited by a moderator:
Solution
The issue has been resolved after the following changes were made to the C# dll:
1.) set ComVisble to true in AssemblyInfo.cs
2.) Changed the Project\Build setting to Register for COM interop (checked the box)

Skydiver I do appreciate your feedback over the past couple of days.
C# version 4 has dynamic keyword which knows how to talk to IDispatch. I think the issue lies elsewhere.

Please post the complete exception you are getting along with the callstack. That will give us more clues.
 
Most of the other instances of the exception I've stumbled across on Google seem to fall under two categories: the Delphi object was registered as 32-bit, while the app was running as 64-bit; or the Delphi COM object was registered with or instantiated with the wrong threading model. In both cases, the COM infrastructure is asking for an interface that is needed to support the needed marshalling (either across process bitness, or across threads).
 
C# version 4 has dynamic keyword which knows how to talk to IDispatch. I think the issue lies elsewhere.

Please post the complete exception you are getting along with the callstack. That will give us more clues.
Here is more information on the exception:
C#:
$exception    {"[SafeCall Exception]: Interface not supported"}    System.Runtime.InteropServices.COMException
Data    {System.Collections.ListDictionaryInternal}    System.Collections.IDictionary {System.Collections.ListDictionaryInternal}
ErrorCode    -2147418113    int
HResult    -2147418113    int
HelpLink    null    string
InnerException    null    System.Exception
Message    "[SafeCall Exception]: Interface not supported"    string
 
Last edited by a moderator:
Most of the other instances of the exception I've stumbled across on Google seem to fall under two categories: the Delphi object was registered as 32-bit, while the app was running as 64-bit; or the Delphi COM object was registered with or instantiated with the wrong threading model. In both cases, the COM infrastructure is asking for an interface that is needed to support the needed marshalling (either across process bitness, or across threads).
The error is encountered with the C# dll build\platform target set to Any CPU or x86. The error is also encountered with the Delphi dll placed in Windows\SysWOW64 and registered there (using regsvr32 in that directory) and when the Delphi dll is copied to a different directory and registered using regsvr32 from Windows\System32.

What's interesting is errors are not encountered when Get_Count, Add and Remove are called. None of those use IDispatch as a parameter or return type. Here's the code for those procedures and function in the Delphi dll:
C#:
function TCollection.Get_Count: Integer;
begin
  Result := fList.Count;
end;

procedure TCollection.Add(const Element, Before, After: IUnknown);
var
  InsertIndex: Integer;
begin
  // Determine where to insert
  if Before <> nil then
  begin
    InsertIndex := fList.IndexOf(Before as IUnknown);
    if InsertIndex < 0 then raise Exception.Create(SNotFound);
  end
  else if After <> nil then
  begin
    InsertIndex := fList.IndexOf(After as IUnknown);
    if InsertIndex < 0 then raise Exception.Create(SNotFound);
    Inc(InsertIndex);
  end
  else
    InsertIndex := fList.Count;
  // Insert Element into list
  fList.Insert(InsertIndex, Element as IUnknown);
end;

procedure TCollection.Remove(Index: OleVariant);
begin
  fList.Delete(ConvertIndex(Index));
end;
 
Last edited by a moderator:
The error is encountered with the C# dll build\platform target set to Any CPU or x86. The error is also encountered with the Delphi dll placed in Windows\SysWOW64 and registered there (using regsvr32 in that directory) and when the Delphi dll is copied to a different directory and registered using regsvr32 from Windows\System32.
Okay, the first attempts to cover the possible bitness mismatch, but the various locations does not address the threading model mismatch.
 
What is the type of the object inside the collection that is being returned from the Delphi code? Does that type support IDispatch?
 
Okay, the first attempts to cover the possible bitness mismatch, but the various locations does not address the threading model mismatch.
The threading model of the Delphi.dll is multi-threaded apartment model and the C# dll is single threaded apartment model.
 
What is the type of the object inside the collection that is being returned from the Delphi code? Does that type support IDispatch?
The type of object inside the collection is TAutoObject and is declared as:
TCollection = class(TAutoObject, ICollection)

According to Delphi documentation, TAutoObject is a CoClass that supports the IDispatch interface and can be used as a base class for ActiveX Automation servers. IDispatch provides access to properties and methods exposed by an object by calling a method or by accesssing a property of a specified dispatch interface.
 
Just to be clear, the C# dll being developed does not expose classes as COM Objects.

A reference to the Delphi.dll was added via Project\References\Add Reference.... enabling access within the C# dll to Types, functions, procedures, properties etc. exposed by the Delphi.dll

The C# dll creates various collections of type (Delphi.dll)Collection. These collections are essentially dynamic collections of different objects. For example, a Collection could hold objects of Type Person, Car etc. There is no issue adding objects to collections by invoking Collection.Add, getting the count of objects in a collection by invoking Collection.Get_Count or removing objects from a collection by invoking Collection.Remove. An error is only encountered when invoking Collection.Get_Item().

The return type of Get_Item is IDispatch whereas the return type of Get_Count is integer. This would seem to suggest marshalling of unmanaged type IDispatch is the problem (because Get_Count has no issue returning an integer). C# expects a dyamic to be returned from Get_Item but a cast error is being encountered. Can you provide an example of C# code which knows how to talk to IDispatch in terms of using dynamic?
 
Here's a simple example of C# dll code being used to add a Person object to a Collection.

Person is a Type defined in the C#.dll
Collection is a Type defined in the Delphi.dll
C#:
Person aPerson = new Person("Joe", 25);
Collection people = new Collection();
people.Add(aPerson, null, null); //this adds a person object to the people Collection, no error encountered
Console.WriteLine(people.Get_Count()); //this returns 1, no error encountered
Person anotherPerson = people.Get_Item(1); //this raises EIntfCastError within the Delphi.dll
Add is a method defined in the Delphi.dll
Get_Count is a function defined in the Delphi.dll
Get_Item is a function defined in the Delphi.dll

C# is expecting a dynamic to be returned from Get_Item. IDispatch is the return type defined for Get_Item in the Delphi.dll
 
Last edited by a moderator:
The threading model of the Delphi.dll is multi-threaded apartment model
Hmmm... From the CoInitializeEx() documentation:
[in] dwCoInit

The concurrency model and initialization options for the thread. Values for this parameter are taken from the COINIT enumeration. Any combination of values from COINIT can be used, except that the COINIT_APARTMENTTHREADED and COINIT_MULTITHREADED flags cannot both be set. The default is COINIT_MULTITHREADED.
 
Let me make sure that I understand correctly, then. You put a non-COM object that does not support IDispatch into a Delphi collection.

Then you ask that object to be pulled out from the Delphi collection as an object exposing an IDispatch interface? Or at least that is how I am reading this line:
C#:
Result := fList.Items[ConvertIndex(Index)] as IDispatch;

How is the IDispatch interface implementation for that object supposed to magically appear?
 
Back
Top Bottom