Динамически загружаемый код обмена / передача объектов BPL - PullRequest
4 голосов
/ 09 марта 2011

Я возился с идеей использования динамической загрузки BPL и передачи экземпляров объектов из основного приложения в метод в BPL. Это создает проблему единиц измерения между приложением и BPL.

Я написал небольшой прототип, который сделал это, и мне было любопытно, как Delphi внутренне управляет различиями между классами, определенными в приложении, и BPL.

Например, скажем, базовый класс виджетов, такой как:

TmyWidget = class
private
  fId:Integer;
  fDescription:String;
public
  procedure DoSomething1();
end;

Теперь приложение и BPL создаются с использованием модуля, содержащего класс TmyWidget. Позже что-то меняется в TMyWidget, и приложение перестраивается, но BPL нет (или наоборот). Я добавил другой метод DoSomething2 (), создал в приложении экземпляр TmyWidget и передал его в BPL для обработки и основной пример, это сработало. Но это явно чревато потенциальными проблемами.

Если другой динамически загруженный BPL также использует TmyWidget, все становится еще интереснее. Кажется, это работает, но это определенно не кажется идеальным.

Основной вопрос - как обычно передавать объекты в основное приложение и из него, а также в библиотеки DLL или BPL? Я никогда не пытался сделать это раньше и, вероятно, по уважительной причине, но у меня есть идея, которая поддается такому подходу ...

Я полагаю, что лучший подход - это сериализовать объект, передать эти байты и десериализовать его в DLL / BPL, причем этот процесс учитывает возможные различия версий между хостом и динамически загружаемым модулем, но я надеялся новая опция SimpleSharedMem может принести эту новую функциональность без дополнительных затрат на сериализацию, но, похоже, она будет не очень полезна, если вы не будете строго сохранять приложение и перестраивать dll при любых изменениях общего кода ... но в этом прототипе приложение будет оставайтесь достаточно постоянными, и динамически загружаемые модули будут часто меняться с добавлением функций в TmyWidget. (Серверное приложение служит фабрикой для создания TmyWidget на основе клиентских запросов, и приложение передает экземпляры различным модулям для обработки.)

Ответы [ 2 ]

10 голосов
/ 09 марта 2011

... было любопытно, как Delphi внутренне управляет различиями между классами, определенными в приложении, и BPL

Delphi управляет этим, не разрешая этого. У вас не может быть устройства с одним и тем же именем в нескольких пакетах одновременно: если вы это сделаете, вы получите сообщение об ошибке, говорящее о чем-то похожем на Package XYZ already contains ABC (давно этого не видел ...). Поскольку имя типа включает в себя имя модуля, вы не можете иметь один и тот же тип в двух разных пакетах. Если это не интерфейс, определяемый его GUID, но это другая история.

... как обычно можно передавать объекты в основное приложение и из него, а также в библиотеки DLL или BPL?

Вы не передаете объекты в DLL, это не очень хорошая идея. Когда вам нужно передать объекты в BPL, убедитесь, что базовый класс для этого BPL определен в третьем BPL.

Пример. Полиморфное поведение вашего TmyWidget, вероятно, определяется с помощью некоторых виртуальных методов. Убедитесь, что у вас есть класс TmyWidgetBase, который определяет все эти виртуальные методы, извлекает все ваши TmyWidget из этого базового класса и передает объекты типа TmyWidgetBase. Убедитесь, что класс TmyWidgetBase находится в своем собственном пакете.

Когда я попытался сделать это, у меня получился крошечный «загрузчик» exe и много BPL. По сути, вся логика была в BPL, чтобы облегчить прохождение объектов вокруг.

6 голосов
/ 10 марта 2011

Один из проектов, над которыми я работал, успешно использует большое количество пакетов времени выполнения уже более десяти лет, поэтому я поделюсь с вами своим опытом работы с пакетами.

Как указал Космин, разные пакеты не могут содержать одинаковые единицы. Если вы используете неявное связывание, добавление пакета в предложение требует другого пакета или добавление пакета в список Пакеты времени выполнения в параметрах проекта, компилятор сделает всю работу за вы и сообщите одно из следующих сообщений об ошибке:

E2199: Packages '%s' and '%s' both contain unit '%s' (если ваш проект компиляции зависит от двух пакетов, содержащих один и тот же модуль)

E2200: Package '%s' already contains unit '%s' (если вы компилируете пакет, содержащий модуль, он уже содержится в одном из пакетов, от которых он зависит)

Если вы используете явное связывание, используя LoadPackage, обычно попытка проверки выполняется во время выполнения (хотя ее можно обойти) и вызывает:

EPackageError: Невозможно загрузить пакет '% S.' Он содержит единицу "% s", которая также содержится в пакете "% s"

Устранить эти ошибки не так уж и сложно.

Если у вас есть два пакета, в которых оба должны использовать блок, просто позвольте одному из них содержать блок, а другому - первый. package dependency graph

Если у вас есть два пакета, которые должны использовать друг друга, вам придется переместить эти блоки в новый пакет, от которого могут зависеть оба. dependency graph

Преимуществом неявно связанных пакетов является то, что вы можете напрямую обращаться к определениям классов, как если бы они были статически связаны. Просто добавьте модуль к условию использования модуля, в котором вам нужно его использовать. Компилятор и среда выполнения позаботятся о разрешении всего.

Явно связанные пакеты должны будут полагаться на регистрацию класса в разделе инициализации.

...