При работе с COM-интерфейсами в среде Delphi и .NET могут возникать различные проблемы, одна из которых связана с неправильной передачей интерфейсов между этими технологиями. В статье рассмотрим, почему может возникать ошибка System.InvalidCastException при попытке передать интерфейс из .NET в Delphi, и как её можно решить.
Описание проблемы
Разработчики часто сталкиваются с проблемой, когда при передаче интерфейса из приложения на .NET в библиотеку, написанную на Delphi, возникает ошибка System.InvalidCastException. Это происходит на стороне .NET, и код не достигает Delphi-компонентов.
Пример ActiveX-библиотеки в Delphi
Рассмотрим простой пример ActiveX-библиотеки, созданной в Delphi. Библиотека содержит два объекта автоматизации: MyContent и MyContainer. Объект MyContainer имеет метод Add, который принимает интерфейс IMyBase, от которого наследуется IMyContent. Интерфейс IMyBase является производным от IDispatch.
library DelphiComLib
{
// Описание интерфейсов и классов
// ...
};
Реализация классов в Delphi
Реализация классов в библиотеке может быть минимальной, и реализация метода Add может быть оставлена пустой. Класс MyContainer и MyContent создаются следующим образом:
unit Unit1;
{$WARN SYMBOL_PLATFORM OFF}
interface
uses
ComObj, ActiveX, DelphiComLib_TLB, StdVcl;
type
TMyContainer = class(TAutoObject, IMyContainer)
protected
procedure Add(const AMyBase: IMyBase); safecall;
end;
implementation
uses ComServ;
procedure TMyContainer.Add(const AMyBase: IMyBase);
begin
// Операции с AMyBase
end;
initialization
TAutoObjectFactory.Create(ComServer, TMyContainer, Class_MyContainer,
ciMultiInstance, tmApartment);
end.
// Аналогично для MyContent
Использование библиотеки в .NET
После регистрации библиотеки и добавления ссылки на неё в консольное приложение .NET, попытка использовать метод Add приводит к ошибке System.InvalidCastException:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DelphiComLib;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
IMyContainer container = new MyContainer();
IMyContent content = new MyContent();
container.Add(content);
}
}
}
Альтернативное решение
Если создать класс в .NET, который явно реализует интерфейс IBase, передача интерфейса в Delphi-библиотеку будет успешной.
Подтвержденный ответ
Проблема заключается в некорректном приведении типов на стороне Delphi. Класс TMyContent должен явно реализовывать интерфейс IMyBase, чтобы приведение типов было корректным:
type
TMyContent = class(TAutoObject, IMyContent, IMyBase)
// ...
end;
Это позволит корректно использовать TMyContent в контексте IMyBase для любых клиентских приложений, включая Delphi, C++, .NET и другие.
Заключение
При работе с COM-интерфейсами важно соблюдать правила реализации интерфейсов и корректно обрабатывать приведение типов. В данном случае, явно реализовав интерфейс IMyBase в классе TMyContent, можно решить проблему с передачей интерфейса из .NET в Delphi.
Проблема заключается в несовместимости типов интерфейсов при передаче из приложения на .NET в библиотеку, созданную на Delphi, что приводит к ошибке `System.InvalidCastException` на стороне .NET.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS