« Поставить закладку » « Сделать стартовой »

« Форумы » « Блоги » « Статьи » « Новости » « Файлы » « Realcoding IRC » « Site map » « Поиск »


Главная Главная
Анонсы Анонсы
Форумы Форумы
Каталог Каталог
Поиск Поиск
Опросы Опросы
Книжный магазин Книжный магазин
Реклама на сайте
Публикации Публикации
Партнеры Партнеры
Карта Карта сайта
Рассылки Рассылки
RSS экспорт
Настройки Настройки
О нас пишут О нас пишут
Контакты Контакты
Гостевая книга Гостевая книга


ПнВтСрЧтПтСбВс
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
    Популярное
Закругление углов без использования изображений

Работа с COM портами (CreateFile)

PHPShell - скрипт php, позволяющий выполнять на веб-сервере shell-команды

Системные рабочие потоки

Опыт использования системных ловушек или как я создавал программу по надзору за записью компакт-дисков

Экстремальное программирование и быстрая разработка ПО

Работа с регионами в Visual C++

Глава 3: Бремя выбора

Изменение клиентской программы, работающей с Web-службой

Многоязычные приложения в PHP




    Архив файлов



    Сообщества

    Документация

    Кто на сайте
Вы не зарегистрированы.
Имя:

Пароль:

Запомнить

Регистрация позволит Вам пользоваться дополнительными сервисами.
Сейчас на сайте:
Гостей: 125
Пользователей: 0

Статьи:: Delphi :: Разные статьи :: Принцип создания плагинов в 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, лежащей в папке ...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.
  • Когда вы сдаёте программу, напишите к ней уже готовых несколько плугинов, что бы юзеру было интересно искать новые.
  • Сделайте поддержку обновления через интернет. То есть программа заходит на ваш сервер, узнаёт, есть ли новые плугины или нет, если есть - то она их загружает. Этим вы увеличите спрос своей программы и конечно трафик своего сайта!



Рубрика: Разные статьи




Вышел MySQL 5.1.30, первый стабильный рели....

MySQL

После публикации 29 тестовых версий анонсирован первый стабильный релиз MySQL 5.1, пригодный для промышленной эксплуатации и обеспечивающий увеличение производительности для "тяжелых" SQL запросов, по сравнению с MySQL 5.0, примерно на 15-20%. Главные новшества появившиеся в MySQL 5.1:


Подробнее... | Рубрика: MySQL | Добавлено: 28.11.2008

Тестирование параллельных программ.

Тестирование

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


Подробнее... | Рубрика: Тестирование | Добавлено: 28.11.2008

Архитектура AMD64 (EM64T).

Архитектура AMD

Аннотация. В статье кратко рассматривается архитектура AMD64 компании AMD и ее реализация EM64T компании Intel. Описаны особенности архитектуры, ее возможности, достоинства и недостатки.


Подробнее... | Рубрика: Архитектура AMD | Добавлено: 27.11.2008

Остальные статьи:

Платформа 2009. Определяя будущее
Windows Vista Bridge Sample Library - упра...
Оптимизация 64-битных программ
Подгрузка через AJAX HTML-кода, содержащег...
Обзор нового релиза самой мощной Ajax библ...
Firebug 1.3 и 1.4 alpha — что нового и инт...
Релиз Microsoft Silverlight 2.0. Что новог...
XML документация в C#
Курсоры в MySQL 5
Microsoft опубликовала подробности о сесси...
Microsoft делится подробностями о том, что...
Тестируем новый javascript от нового брауз...
MySQL Query Cache
Использование провайдеров компиляции в As...
Чего мы ждем от C# 4.0
Delphi 2009 и C++Builder 2009
Джоэл Спольски и Джеф Этвуд запустили новы...
Поиск кода Google /* что нового? */
10 jQuery скриптов для улучшения интерфейс...
Генераторы отчетов FastReport 4 и QuickRep...


Цитата дня (все,добавить):

Портал фрилансеров

работа на дому


    Рубрикатор

Программирование

C/С++
Обучение
Windows API
XAML
Моделирование
Паттерны
Visual Basic 7 .NET
WxWidgets
Функции WinApi
Функции С++
Разработка под Mac OS
Eiffel
Visual Studio 2008
UI дизайн
Алгоритмы
Конкурсные статьи
Turbo Pascal
Visual Studio
CASE-средства
Visual Studio 2005
Без VCL
Delphi
Тех. документация
Тестирование
Software Testing
ООП
TCP/IP
Google Android
Windows Installer
.NET Framework
Драйвера
C# C Sharp
Справка
Проектирование
Информ. системы
Visual Basic
Assembler
Оптимизация кода
Gtk+
Компоненты
Реинжиниринг
Управление проектами
Extreeme programming
Lotus Notes
Алгебраическое проектирование


Интернет технологии

PHP
Perl
ASP
WAP
Cookies
SSI
CGI
Web Servers
VB Script
DNS
CSS
XML
Html
Java Script
Java2ME
Firewall
Flash
.htaccess
Apache
VRML
Протоколы
Поисковые системы
Технология JAVA
Учебник по PHP
Учебник по JavaScript
Учебник по XML
Java Q&A
AJAX
DHTML
XHTML
Dreamweaver
Web 2.0
Python
Вебмастеру
Cisco
Ruby on Rails
Silverlight

Базы данных

Access
InterBase
MySQL
Oracle
ADO .NET
Основы SQL
Учебник по Access 2002
MS
Microsoft FoxPro
Доступ к данным
XML в MS SQL Server 2000
ODBC и MyODBC
Обучение
Caché
DB2
PostgresSQL
Sybase
Теория
Хранилища данных
Безопасность
Реляционные данные
MySQL и mSQL

Остальное:

Разное
Обзоры книг
Безопасность
Графика и дизайн
Юмор
Linux
Фракталы
Microsoft Axapta
Многоядерность
Сети
Microsoft Office
Работа
MS-DOS
Криптография
Графика и игроделание
Новости SDK
Системы защиты
Учебник по AutoCad
CVS
Windows XP
Windows Server 2003
Windows Vista
Windows 7
Мероприятия