Принцип створення плагінів в 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, що лежить в папці … Delphi5BIN.

Завантаження плагіна


Перейдемо до теоретичної частини.


Якщо плагін це 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.

Пара порад:



Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*