Домой | Софт | Мастерская | Лирика | ЧаВО | Юмор | ![]() |
В этой статье будет рассмотрен способ реализации поддержки плагинов в своем приложении при помощи интерфейсов в среде разработки Delphi.
Данная реализация системы плагинов имеет ряд преимуществ по сравнению с другими системами (dll, packages, classes):
Если вы незнакомы с интерфейсами, то почитать о них вы можете в справочной системе, Object Pascal Language Guide. Или в книге Тейкстры и Пачеко "Delphi 5"
Эта статья содержит уже готовую к работе систему, а также примеры пары плагинов.
Итак, наша система основана на интерфейсах. Для начала, нам нужно определить какие типы плагинов мы хотим поддерживать и описать для каждого типа плагина свой интерфейс. По сути интерфейс - это описание функциональности и свойств соответствующего типа плагина. Следует очень внимательно подойти к процессу написания наборов интерфейсов, т.к. неудачно составленный набор значительно осложнит жизнь в будущем как вам, так и разработчикам плагинов. Нужно заранее предусматривать возможность расширения функциональности и добавления новых типов плагинов.
Очевидно, что у всех плагинов, какого бы типа они не были, существуют свойства и функции общие для всех них. Поэтому для таких свойств и функций можно объявить интерфейс, который мы назовем базовым. Каждый плагин обязан реализовать этот интерфейс. Реализовывать или нет другие интерфейсы это дело автора плагина.
Какие же свойства и функции общие для всех плагинов?
Во-первых, это уникальный идентификатор плагина, в качестве которого можно использовать GUID - это будет гарантировать уникальность идентификатора (для его генерации в среде Delphi нужно нажать
Ctrl + Shift + G) . Этот идентификатор можно будет использовать, например, для того, чтобы позволить пользователю отключить загрузку указанного им плагина, или для того чтобы хранить настройки плагина.Во-вторых, это данные об авторе плагина, например Имя и E-mail.
Название плагина, также будет не лишним.
Рано или поздно любой плагин будет выгружен, поэтому мы должны иметь возможность предупредить его об этом.
Таким образом, базовый интерфейс может иметь такой вид:
IPlugin = interface(IUnknown) ['{970F72FC-9D35-449C-B1EC-F25B2908AD59}'] function getName: WideString; stdcall; function getVendorName: WideString; stdcall; function getVendorEMail: WideString; stdcall; function getID: WideString; stdcall; procedure BeforeUnload; stdcall; property Name: WideString read getName; property VendorName: WideString read getVendorName; property VendorEMail: WideString read getVendorEMail; property ID: WideString read getID; end;Из названий ясно назначение того или иного метода/свойства.
Так как мы описали базовый интерфейс для всех плагинов, то теперь можно более подробно рассмотреть, что же такое плагин в нашей системе. Плагин - это просто DLL, которая содержит экспортируемую функцию LoadPlugin, результат которой - указатель на класс реализующий, по крайней мере, базовый интерфейс.
Т.е. исходный текст простейшего плагина выглядит следующим образом:
library simpleplugin; uses PluginSDK, SimplePluginClass in 'SimplePluginClass.pas'; {$R *.res} function LoadPlugin: IPlugin; stdcall; begin try Result:= TSimplePlugin.Create; except Result:= nil; end; end; exports LoadPlugin; begin end.Полные исходные коды плагина вы найдете в разделе "Ссылки". Там есть пример плагина IInfoPlugin возвращающего имя пользователя.
Для работы с плагинами нам понадобится менеджер, который будет загружать и выгружать их. В "Ссылках" вы можете взять уже готовый менеджер плагинов. Он умеет загружать их из указанной папки, выгружать, и предупреждать их об выгрузке. Рассмотрим его устройство. Это класс с несколькими методами и полями.
TPluginManager = class(TObject) private FHandles: TDLLsHandles; FPlugins: TPluginList; FInfoPlugins: TInfoPluginList; function AddPlugin(plug: IPlugin): Boolean; procedure CallBeforeUnload; public constructor Create; destructor Destroy; override; procedure LoadPlugins(const Folder: String); procedure UnloadPlugins; property Plugins: TPluginList read FPlugins; property InfoPlugins: TInfoPluginList read FInfoPlugins; end;Когда вы вызовете метод LoadPlugins, то менеджер плагинов будет перебирать все файлы *.dll и загружать их. Затем он пытается получить адрес функции LoadPlugin и вызывает ее. Если ее результат не nil, то он добавляет полученный указатель в список всех плагинов. А затем он начинает перебирать интерфейсы (при добавлении новых интерфейсов, их обработку вам нужно добавить самим, по аналогии) для того, чтобы понять какого типа является данный плагин и добавляет его в список соответствующей категории.
Ну вот собственно и все, посмотреть примеры, как уже говорилось ранее вы можете в разделе "Ссылки".
Примеры, менеджер плагинов - здесь.
Книги по Delphi - здесь. Особенно советую почитать Пачеко. У него очень хорошо написано про интерфейсы. Также полезно почитать "Inside COM / Основы COM".
Слава Антонов © 2002 — August 13, 2008 |
|