Как лучше добавить возможности плагина к программе Delphi

Я хочу добавить возможность пользователям писать плагины в программу, разработанную в Delphi. Программа представляет собой один исполняемый файл без использования DLL.

Это позволит сообществу пользователей писать расширения моей программе для доступа к внутренним данным и добавления возможностей, которые они могут найти полезными.

Я видел сообщение: Предложения по добавлению возможностей плагина?, но его ответы не кажутся переносимыми в программу Delphi.

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

Знаете ли вы о каких-либо ресурсах, компонентах или статьях, которые могли бы предложить, как лучше всего это сделать в Delphi, или у вас есть свои рекомендации?

Ответы

Ответ 1

Первый вопрос, который я задал бы вам, вам нужны плагины для доступа к пользовательскому интерфейсу вашего хост-приложения или добавления каких-либо элементов пользовательского интерфейса? Или плагины будут ограничены запросом и/или предоставлением данных вашему хост-приложению?

Последнее намного проще и открывает две возможности. Другие уже упомянули DLL, что является первым способом. Некоторые оговорки применяются - в общем, вы должны взаимодействовать с dll, используя только типы данных, которые используются в Windows API. Таким образом, вы можете быть уверены, что DLL-модули плагина поймут ваши типы данных, независимо от того, какой язык/компилятор они были созданы. (Например, используйте PChars, а не строки. Не переходите, как правило, к классам Delphi, таким как TStream to DLL. В некоторых случаях это будет работать, но в целом это небезопасно, потому что даже если DLL была скомпилирована в Delphi, возможно, это была другая версия компилятора с немного иной идеей о том, что такое TStream). Google для использования DLL в Delphi, и вы найдете много советов.

Еще один способ, который еще не упоминался, - включить скриптинг в самом приложении. Есть несколько очень способных сторонних скриптовых движков, как коммерческих, так и бесплатных, и большинство из них позволяют вам обменивать объекты Delphi с помощью script. Некоторые из этих библиотек поддерживают только Pascal как язык сценариев, другие позволят вам использовать Basic (возможно, лучше для начинающих пользователей) или на других языках. См. Например RemObjects Pascal Script (бесплатно) в http://www.remobjects.com/free.aspx.

Мое любимое решение для скриптинга на данный момент - Python для Delphi (P4D, также бесплатно) от http://mmm-experts.com/Products.aspx?ProductID=3 Он прекрасно взаимодействует с вашими классами через RTTI и позволяет выполнять код Python в вашем приложении Delphi, а также использовать классы Delphi в сценариях Python. Учитывая популярность Python, это может быть жизнеспособным решением, если вы хотите привлечь разработчиков к вашему проекту. Однако каждый пользователь должен будет установить дистрибутив Python.

Мне кажется, что барьер для входа, с точки зрения потенциальных авторов плагинов, ниже, если вы используете скрипты, чем если вы выберете DLL.

Теперь вернемся к моему первоначальному вопросу: все становится намного сложнее, если вам нужны плагины для взаимодействия с вашим пользовательским интерфейсом, например. путем размещения на нем элементов управления. В общем случае DLL не могут быть использованы для этого. Способ, разрешенный Borland/CodeGear, заключается в использовании пакетов (BPL). С помощью BPL вы можете получать и создавать экземпляры классов, предлагаемые плагином, как если бы они были объявлены в вашем хост-приложении. Уловка - все BPL должны быть скомпилированы с той же точной версией и сборкой Delphi, что и ваше основное приложение. По-моему, это делает пакеты совершенно непрактичными, так как трудно ожидать, что все потенциальные авторы плагинов по всему миру будут использовать ту же версию Delphi, что и вы. Большая ошибка.

Чтобы обойти это, я экспериментировал с другим подходом: продолжайте использовать библиотеки DLL и разрабатывайте синтаксис для плагина, чтобы описать его интерфейс, а затем создайте пользовательский интерфейс самостоятельно в главном приложении. (XML - удобный способ выразить пользовательский интерфейс, поскольку вы бесплатно получаете концепцию родительского права/вложенности.) Синтаксис описания пользовательского интерфейса может включать обратные вызовы в DLL, инициируемые при изменении содержимого или состояния элемента управления. Этот метод ограничит плагины набором элементов управления VCL, которое приложение уже использует или зарегистрировало. И это не однозарядная работа, в то время как BPL, безусловно, есть.

Google для "Плагины для Delphi" тоже. Есть некоторые готовые решения, но, насколько я знаю, они обычно используют BPL с ограниченной пользой.

Ответ 2

На самом деле, принятый ответ на вопрос, который вы цитируете, вполне подходит для Delphi. Ваши плагины будут DLL, и вы можете диктовать, что они должны экспортировать функцию с определенным именем и подписью. Затем ваша программа загрузит DLL (с ​​помощью LoadLibrary) и получит адрес функции (с помощью GetProcAddress). Если DLL не загружается или функции там нет, DLL не является подключаемым модулем для вашего приложения.

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

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

Ответ 3

Сначала я пошел на базовые плагины BPL и DLL. И заставил их тяжело трудиться.

Если вы используете систему BPL, вам необходимо сопоставить версию BPL с версией EXE. Это включает в себя обновления Delphi, которые могут что-то сломать. Я узнал (трудный путь), что если мне нужно включить все мои плагины с каждой версией, нет смысла иметь плагины вообще.

Затем я переключился на обычные DLL-плагины. Но эта система просто сложная база кода. И это не очень хорошо.

В то время, когда я искал сеть, я узнал Lua встроенный script язык и доставлял с ним. Lua - это 150K DLL, встраивание компилятора байт-кода, интерпретатора и очень простой и интеллектуальный язык динамического программирования.

Мои плагины - это простые сценарии lua. Легко mantaind и сделано. Есть примеры Delphi, поэтому вы можете экспортировать любой класс или процедуру в качестве таблицы или функции Lua. GUI или нет. Например, у меня была TurboPower Abbrevia в моем приложении для застежки. Я экспортировал свой класс zipping в lua, и теперь все плагины могут вызывать zip ('.', 'Dir.zip') и unzip(). Затем я переключился на 7zip и только реализовал старый класс для использования 7zip. Все плагины работают так же, как и они, с поддержкой нового zip ('.', 'Dir.7z').

Я сделал TLuaAction, который вызывает процедуру Execute(), Update(), Hint() из своего script.

Lua также имеет собственную систему плагинов, которая упрощает добавление функциональности к ней. Например, luacom make прост в использовании COM-автоматизации, luainterface позволяет вызывать .net от lua. Подробнее см. luaforge. В Delphi есть Lua IDE с источником.

Ответ 4

Я попытался сделать обзор всех таких параметров некоторое время назад. Вместе со своими читателями/комментаторами мы построили этот список:

  • DLL/BPL загружается из программы.
  • DLL/BPL загружается из песочницы (которая может быть другой копией программы или специализированного "серверного" приложения и которая связывается с основной программой через сообщения/сокеты/msmq/named pipes/mailslots/memory mapped files).
  • COM (в любом из его вариантов).
  • DDE (пожалуйста, не надо).
  • Внешняя программа, которая осуществляет связь через вход/выход stanard.
  • Внешняя программа, которая связывается через файлы (имя файла является параметром для программы).
  • Внешняя программа, которая работает через папку drop (полезна для пакетной обработки).
  • Внешняя программа, которая связывается с сообщениями Windows/windows sockets/msmq/named pipe/mailslots/memory mapped files/database publish-subscribe.

Ответ 5

Самый универсальный способ добавления подключаемых модулей - использовать COM. Хорошая книга, чтобы вы начали на дороге Delphi Com Programming от Eric Harmon. Хотя он был первоначально написан для версий 3-5 версии Delphi, содержимое книг по-прежнему действует с последними версиями Delphi.

Лично я использовал эту технику наряду с активными сценариями, чтобы разрешить настройку конечного пользователя.

Ответ 6

Я использую плагины для реализации большинства функций в игровом движке, который я создаю. Основной EXE состоит из движка script, менеджера подключаемого модуля, некоторых основных графических подпрограмм и не более того. Я использую TJvPluginManager из библиотеки JEDI VCL. Это очень хороший менеджер, и он может добавить практически все, что вы хотите для своей программы. Ознакомьтесь с демонстрационными примерами, прилагаемыми к пакету, чтобы узнать, как это работает. Единственным недостатком является то, что он добавляет много кода JCL/JVCL в вашу программу, но это не проблема, если вы уже используете другие компоненты JVCL.

Ответ 7

Если плагины будут разработаны в Delphi или С++ builder, используйте пакеты + интерфейсы. Delphi OTA - хороший пример для этого. Если плагины будут независимыми от языка, COM - хороший способ.

Дополнение: Если вы не будете использовать COM, вам может потребоваться предоставить SDK для каждого языка. И обработка данных между различными языками может быть болью (например, тип строки delphi). Поддержка Delphi COM отличная, вам не нужно беспокоиться о каких-то деталях. В основном это связано с поддержкой Delphi COM. Не пытайтесь снова изобрести колесо. Я удивлен, почему люди не склонны упоминать об этом.

Ответ 9

Вы можете посмотреть Hydra из Remobjects. Это позволит не только добавлять плагины, но и смешивать win32 и .net.