Написание plug-in модулей В Delphi

Создание программы для работы с plug-in

Создание программы для работы с plug-in

Давайте создадим собственный plug-inмодуль и тестовую программу для него, чтобы сделать все на практике своими руками. Начнем мы с написания основной программы. Для этого создайте новый проект простого приложения (Application). На главной форме мы разместим компоненты MainMenuи Memo1. В меню мы создадим два главных пункта: Файл и Plug-ins. В первом пункте можете создать подменю Выход, а второй нужно оставить пустым, потому что он будет заполняться функциями из дополнительного модуля.

 

Компонент Memolможно растянуть по всей форме, чтобы пример выглядел более солидно. Мой вариант программы вы можете увидеть на рисунке. 

 

В самом модуле в разделе type нужно объявить следующий объект:

type

TIPluginDemo = class public

function GetApplication: TApplication; virtual; stdcall; procedure AddMenuItem(MenuItemCapt: String;

Proc: TNotifyEvent); virtual; stdcall;

procedure AddItem(Item: String); virtual; stdcall; end;

 

Это объект, через который наша программа будет взаимодействовать с встраиваемым модулем. У этого объекта есть три метода.

  • GetApplication — с помощью данного метода модуль сможет получать ссылку на объект приложения главной программы. Хотя в своем примере я это использовать не буду, но все же решил показать, как передавать в дополнительный модуль ссылку на главное приложение. Эта возможность может понадобиться для модуля plug-ins, если он захочет создать какие-либо дополнительные окна, которые должны будут зависеть от главного приложения.
  • AddMenuItem — этот метод в главном окне будет создавать пункт меню, предназначенный для использования возможностей встраиваемого модуля.
  • AddItem — через этот метод встраиваемый модуль будет выводить информацию в главное окно, а точнее сказать в компонент Memo1.

Теперь посмотрим на реализацию всех этих методов в нашем приложении. Первым на очереди GetApplication:

function TIPluginDemo.GetApplication: TApplication;

begin

Result:=Application;

end;

 

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

 

Следующий метод — AddMenuItem:

procedure TIPluginDemo.AddMenuItem(MenuItemCapt: String;

Proc: TNotifyEvent);

var

NewItem: TMenuItem; begin

NewItem:=TMenuItem.Create(PluginDemoForm);

NewItem.Caption:=MenuItemCapt;

NewItem.onclick:=Proc;

PluginDemoForm.Utilities1.Add(NewItem);

end;

 

Здесь мы создаем подпункт в меню Plug-ins главного окна. В качестве заголовка пункта меню используется первый переданный параметр. В качестве обработчика события onclick для созданного пункта указывается процедура, переданная во втором параметре. Таким образом, дочерний модуль создает в главном окне пункт меню и назначает ему свой обработчик события.

 

Ну и последний метод — AddItem:

 

procedure TIPluginDemo.AddItem(Item: String);

begin

PluginDemoForm.Memo1.Lines .Add (Item) ; end;

 

Здесь просто выводится информация, переданная из модуля в компонент Memo1. Эту функцию наш метод может использовать для вывода на экран результатов каких-то расчетов, которые может выполнять дополнительный модуль.

 

Напоминаю, что все три функции и весь класс вообще предназначены для обеспечения взаимодействия встраиваемого модуля с главной программой.

Теперь, после ключевого слова implementation объявим следующее:

 

type

TInitPlugin = procedure(PlugClass: TIPluginDemo); const

PlugInitProc: PChar = 'InitPlugin';

 

В разделе type объявлена переменная TInitPlugin как процедура. Таким образом описывается название и параметры процедуры из модуля plug-in. Она будет вызываться из этой программы, а встраиваемый модуль будет инициализировать свои данные, например, добавлять необходимые ему пункты меню в главное окно.

 

В разделе const объявляется строковая константа со значением InitPlugin. Это имя процедуры инициализации (тип этой процедуры мы только что описали в разделе type) из встраиваемого модуля.

 

Самое последнее, что нам нужно сделать, прежде чем мы приступим к программированию, это объявить несколько переменных в разделе private:

 

private

{ Private declarations }

PInterface: TIPluginDemo; il:TList;

 

Первая переменная будет инициализировать модуль и хранить ссылку на него. Эта переменная должна быть доступной на протяжении всего времени выполнения программы. Вторая переменная — это список, в который мы будем вносить все указатели на загруженные модули PInterface, чтобы сохранять все ссылки целыми и невредимыми.

 

Для работы с дополнительными модулями у нас все готово. Теперь во время запуска программы мы должны запустить поиск в определенной директории на наличие dll- файлов. Для этого, в обработчике события OnCreate напишем следующий код:

 

 

procedure TPluginDemoForm.FormCreate(Sender: TObject); var

Found, Attr: Integer;

SearchRec: TSearchRec;

PluginHandle: THandle;

InitPlugin: TInitPlugin; begin il:=TList.Create;

PlugDir := ExtractFilePath(Application.ExeName) + 'PLUGINS\';

Attr := faReadOnly or faHidden or faSysFile or faArchive;

Found := FindFirst(PlugDir+'*.DLL', Attr, SearchRec); while Found = 0 do begin try

PluginHandle:=LoadLibrary(PChar(PlugDir+SearchRec.Name)); @InitPlugin:=GetProcAddress(PluginHandle,PlugInitProc); if Longint(@InitPlugin)<>0 then begin try

PInterface:=TIPluginDemo.Create;

InitPlugin(PInterface); il.Add(PInterface); except

raise Exception.Create('Ошибка загрузки !'); end end else

FreeLibrary(PluginHandle); except

raise Exception.Create('ОuIибка '+SearchRec.Name); end;

Found := FindNext(SearchRec); end;

FindClose(SearchRec); end;

 

 

В самом начале инициализируется список il. Затем заносим в переменную PlugDir директорию, в которой нужно будет искать дополнительные модули.

После этих приготовлений, запускается поиск файлов в указанной директории с помощью функции FindFirst. Если файл найден, то загружаем найденную библиотеку в память с помощью функции LoadLibrary. Следующим этапом ищем в загруженной библиотеке процедуру инициализации с помощью функции GetProcAddress. У этой функции имеется два параметра:

  • указатель на загруженную библиотеку;
  • второй параметр — имя процедуры, которую надо найти. Здесь мы указываем константу GetProcAddress, в которой храниться имя 'InitPlugin'.

Если результат выполнения функции GetProcAddress не равен нулю, значит процедура инициализации найдена и ее надо выполнить. Для этого сначала создаем объект типа TIPluginDemo — этой интерфейс, который мы создали для взаимодействия дополнительного модуля с главной программой. После этого вызываем процедуру InitPlugin из библиотеки, передавая ей указатель на созданный для взаимодействия интерфейс. Тут же добавляем переменную PInterface в список il для последующего использования.

 

Если функция инициализации не найдена, то выгружаем библиотеку, потому что это может быть любой dll-файл, не являющийся plug-in модулем для нашей программы. Делается это с помощью API функции FreeLibrary.

 

При событии OnDestroy главной формы мы должны уничтожить список:

 

procedure TPluginDemoForm.FormDestroy(Sender: TObject);

begin

il.Free;

end;

Это основное, что вам необходимо сделать для создания главного приложения, чтобы оно могло работать с plug-in модулями. Если вам нужны будут более сложные взаимодействия между главной программой и дополнительным модулем, то придется расширить возможности объекта TIPluginDemo.

dle

Помоги проекту! Расскажи друзьям об этом сайте: