(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

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

Источник: Delphirus
rolcom

Иногда нужные мысли приходят после того, как программа сдана заказчику. Для этого придумали плагины. плагины - это простая 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.

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

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


 Распечатать »
 Правила публикации »
  Обсудить материал в конференции Micro Focus/Borland » [3]
Написать редактору 
 Рекомендовать » Дата публикации: 07.05.2008 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
IBM RATIONAL Quality Manager Quality Professional Authorized User Single Install License + Sw Subscription & Support 12 Months
ZBrush 4R6 Win Commercial Single License ESD
erwin Data Modeler Standard Edition r9.7 - Product plus 1 Year Enterprise Maintenance Commercial
ReSharper - Commercial annual subscription
IBM Domino Enterprise Server Processor Value Unit (PVU) License + SW Subscription & Support 12 Months
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Безопасность компьютерных сетей и защита информации
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
СУБД Oracle "с нуля"
3D и виртуальная реальность. Все о Macromedia Flash MX.
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
Обсуждения в форумах
Пишу программы на заказ профессионально (2243)
Пишу программы на заказ на языках Pascal (численные методы, списки, деревья, прерывания) под...
 
Пишу программы на Lazarus (20)
Предлагаю разработку программ на заказ. Примеры программ: www.itproportal.ru
 
Специалист по reverse engineering (2)
Предлагаю услуги по реверсу и модификации различных программ.
 
Помощь по MS Access (327)
Доброе время суток. Случайно оказался на этом сайте, искал статьи по OLAP. Вижу, что...
 
Ищу программиста для написания программы (16)
Ищу программиста ,владеющего Вижуал Бэйсик и программированием в Экселе, для написания...
 
 
 



    
rambler's top100 Rambler's Top100