Воскресенье, 09.02.2025
Королевство Delphi
Главное меню
Статьи
Наш опрос
Нравится раздел статьи?
Всего ответов: 68
Статистика
Онлайн всего: 1
Гостей: 1
Пользователей: 0
Форма входа
Главная » Статьи » Разные » Примеры Delphi

Принцип создания плагинов в Delphi

Иногда нужные мысли приходят после того, как программа сдана заказчику. Для этого придумали плугины. Плугины - это простая dll библиотека, в которой обязательно присутствует ряд процедур и функций, которые выполняют определенные разработчиком действия, например (из моей практики):

function PluginType : PChar;

функция, определяющая назначение плугина.

function PluginName : PChar;

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

function PluginExec(AObject: ТТип): boolean;

главный обработчик, выполняет определённые действия и возвращает TRUE;

и ещё, я делал res файл с небольшим битмапом и компилировал его вместе с плугином, который отображался в меню соответствующего плугина. Откомпилировать res фaйл можно так:

  1. создайте файл с расширением *.rc
  2. напишите в нём : bitmap RCDATA LOADONCALL 1.bmp где bitmap - это идентификатор ресурса RCDATA LOADONCALL - тип и параметр 1.bmp - имя локального файла для кампиляций
  3. откомпилируйте этот файл программой brcc32.exe, лежащей в папке ...\Delphi5\BIN\ .

Загрузка плагина

Перейдём к теоретической части.

Раз плугин это dll значит её можно подгрузить следующими способами:

  • Прищипыванием её к программе!
function PluginType : PChar; external 'myplg.dll';
// в таком случае dll должна обязательно лежать возле exe и мы не можем передать
// туда конкретное имя! не делать же все плугины одного имени! это нам не подходит.
// Программа просто не загрузится без этого файла! Выдаст сообщение об ошибке.
// Этот способ может подойти для поддержки обновления вашей программы!
  • Динамический

это означает, что мы грузим её так, как нам надо! Вот пример:

var
 // объявляем процедурный тип функции из плугина
 PluginType: function: PChar;
 //объявляем переменную типа хендл в которую мы занесём хендл плугина
 PlugHandle: THandle;

procedure Button1Click(Sender: TObject);
begin
 //грузим плугин
 PlugHandle := LoadLibrary('MYplg.DLL');
 //Получилось или нет?
 if PlugHandle <> 0 then
 begin
 // ищем функцию в dll
 @PluginType := GetProcAddress(plugHandle,'Plugintype');
 if @PluginType <> nil then
 //вызываем функцию
 ShowMessage(PluginType);
 end;
 //освобождаем библиотеку
 FreeLibrary(LibHandle);
end;

Вот этот способ больше подходит для построения плугинов!

Функции:

//как вы поняли загружает dll и возвращает её хендл
function LoadLibrary(lpLibFileName : Pchar):THandle;
// пытается найти обработчик в переданной ей хендле dll,
// при успешном выполнении возвращает указатель обработчика.
function GetProcAddress(Module: THandle; ProcName: PChar): TFarProc 
//освобождает память, занитую dll
function FreeLibrary(LibModule: THandle);

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

Вот полноценный пример реализации простой программы для поддержки плугинов...

Исходный текст модуля программы:

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
 Dialogs, Menus, Grids, DBGrids;

type
 TForm1 = class(TForm)
 MainMenu1: TMainMenu;
 //меню, которое будет содержать ссылки на плугины
 N1231: TMenuItem;
 procedure FormCreate(Sender: TObject);
 private
 { Private declarations }
 //лист, в котором мы будем держать имена файлов плугинов
 PlugList : TStringList;
 //Процедура загрузки плугина
 procedure LoadPlug(fileName : string);
 //Процедура инициализации и выполнения плугина
 procedure PlugClick(sender : TObject);
 public
 { Public declarations }
end;

var
Form1: TForm1;

implementation
{$R *.DFM}

Процедура загрузки плугина. Здесь мы загружаем, вносим имя dll в список и создаём для него пункт меню; загружаем из dll картинку для пункта меню

procedure TForm1.LoadPlug(fileName: string);
var
 //Объявление функции, которая будет возвращать имя плугина
 PlugName : function : PChar;
 //Новый пункт меню
 item : TMenuItem;
 //Хендл dll
 handle : THandle;
 //Объект, с помощью которого мы загрузим картинку из dll
 res :TResourceStream;
begin
 item := TMenuItem.create(mainMenu1); //Создаём новый пункт меню
 handle := LoadLibrary(Pchar(FileName)); //загружаем dll
 if handle <> 0 then //Если удачно, то идём дальше...
 begin
 @PlugName := GetProcAddress(handle,'PluginName'); //грузим процедуру
 if @PlugName <> nil then
 item.caption := PlugName
 //Если всё прошло, идём дальше...
 else
 begin
 ShowMessage('dll not identifi '); //Иначе, выдаём сообщение об ошибке
 Exit; //Обрываем процедуру
 end;
 PlugList.Add(FileName); //Добавляем название dll
 res:= TResourceStream.Create(handle,'bitmap',rt_rcdata); //Загружаем ресурс из dll
 res.saveToFile('temp.bmp'); res.free; //Сохраняем в файл
 item.Bitmap.LoadFromFile('Temp.bmp'); //Загружаем в пункт меню
 FreeLibrary(handle); //Уничтожаем dll
 item.onClick:=PlugClick; //Даём ссылку на обработчик
 Mainmenu1.items[0].add(item); //Добавляем пункт меню
 end;
end;

Процедура выполнения плугина. Здесь мы загружаем, узнаём тип и выполняем

procedure TForm1.PlugClick(sender: TObject);
var
 //Объявление функции, которая будет выполнять плугин
 PlugExec : function(AObject : TObject): boolean;
 //Объявление функции, которая будет возвращать тип плугина
 PlugType : function: PChar;
 //Имя dll
 FileName : string;
 //Хендл dll
 handle : Thandle;
begin
 with (sender as TmenuItem) do
 filename:= plugList.Strings[MenuIndex];
 //Получаем имя dll
 handle := LoadLibrary(Pchar(FileName)); //Загружаем dll
 //Если всё в порядке, то идём дальше
 if handle <> 0 then
 begin
 //Загружаем функции
 @plugExec := GetProcAddress(handle,'PluginExec');
 @plugType := GetProcAddress(handle,'PluginType');
 //А теперь, в зависимости от типа, передаём нужный ей параметр...
 if PlugType = 'FORM' then
 PlugExec(Form1)
 else
 //Если плугин для формы, то передаём форму
 if PlugType = 'CANVAS' then
 PlugExec(Canvas)
 else
 //Если плугин для канвы, то передаём канву
 if PlugType = 'MENU' then
 PlugExec(MainMenu1)
 else
 //Если плугин для меню, то передаём меню
 if PlugType = 'BRUSH' then
 PlugExec(Canvas.brush)
 else
 //Если плугин для заливки, то передаём заливку
 if PlugType = 'NIL' then
 PlugExec(nil);
 //Если плугину ни чего не нужно, то ни чего не передаём
 end;
 FreeLibrary(handle); //Уничтожаем dll
end;

procedure TForm1.FormCreate(Sender: TObject);
var
 SearchRec : TSearchRec; //Запись для поиска
begin
 plugList:=TStringList.create; //Создаём запись для имён dll'ок
 //ищем первый файл
 if FindFirst('*.dll',faAnyFile, SearchRec) = 0 then
 begin
 LoadPlug(SearchRec.name); //Загружаем первый найденный файл
 while FindNext(SearchRec) = 0 do
 LoadPlug(SearchRec.name);
 //Загружаем последующий
 FindClose(SearchRec); //Закрываем поиск
 end;
 //Левые параметры
 canvas.Font.pitch := fpFixed;
 canvas.Font.Size := 20;
 canvas.Font.Style:= [fsBold];
end;

end.

Здесь написан простой исходный текст dll, то есть нашего плугина. Он обязательно возвращает название, тип и выполняет свои задачи

library plug;

uses
 SysUtils, graphics, Classes, windows;

{$R bmp.RES}

function PluginType : Pchar;
begin
 //Мы указали реакцию на этот тип
 Plugintype := 'CANVAS';
end;

function PluginName:Pchar;
begin
 //Вот оно, название плугина. Эта строчка будет в менюшке
 PluginName := 'Canvas painter';
end;

Функция выполнения плугина! Здесь мы рисуем на переданной канве анимационную строку.

function PluginExec(Canvas:TCanvas):Boolean;
var
 X : integer;
 I : integer;
 Z : byte;
 S : string;
 color : integer;
 proz : integer;
begin
 color := 10;
 proz :=0;
 S:= 'hello всем это из плугина ля -- ля';
 for Z:=0 to 200 do
 begin
 proz:=proz+2;
 X:= 0;
 for I:=1 to length(S) do
 begin
 X:=X + 20;
 Canvas.TextOut(X,50,S[i]);
 color := color+X*2+Random(Color);
 canvas.Font.Color := color+X*2;
 canvas.font.color := 10;
 canvas.TextOut(10,100,'execute of '+inttostr(proz div 4) + '%');
 canvas.Font.Color := color+X*2;
 sleep(2);
 end;
 end;
 PluginExec:=True;
end;

exports
 PluginType, PluginName, PluginExec;

end.

Пару советов:

  • Не оставляйте у своих плугинов расширение *.dll, это не катит. А вот сделайте, например *.plu . Просто в исходном тексте плугина напишите {$E plu} Ну и в исходном тексте программы ищите не Dll, а уже plu.
  • Когда вы сдаёте программу, напишите к ней уже готовых несколько плугинов, что бы юзеру было интересно искать новые.
  • Сделайте поддержку обновления через интернет. То есть программа заходит на ваш сервер, узнаёт, есть ли новые плугины или нет, если есть - то она их загружает. Этим вы увеличите спрос своей программы и конечно трафик своего сайта!

Получить ссылку на материал

Категория: Примеры Delphi | Добавил: Барон (19.12.2011)
Просмотров: 1042 | Теги: delphi, плагин | Рейтинг: 0.0/0
[ Пожертвования для сайта ] [ Пожаловаться на материал ]

Если вам помог материал сайта кликните по оплаченной рекламе размещенной в центре

Поиск
Категории раздела
Delphi.NET [3]
Kylix Delphi for Linux [9]
Советы Дельферу [6]
Хитрости в Delphi [2]
Обзор Delphi [45]
Инсталлятор [11]
Пользовательский интерфейс [18]
Примеры Delphi [93]
Функции и процедуры [15]
Разные [31]
Королевство Delphi © 2010-2025
Яндекс цитирования