Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Потрепаться";
Текущий архив: 2003.11.24;
Скачать: [xml.tar.bz2];

Вниз

Давайте поговорим о разработки плагинов   Найти похожие ветки 

 
xGhost   (2003-11-01 10:12) [0]

Вот очень интересный а главное рабочий вариант создания плагинов :
Текст не мой , сразк предупреждаю ! :)

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

function PluginType : PChar;

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

function PluginName : PChar;

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

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

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

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

соответствующего плугина. Откомпилировать res фaйл можно так:

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

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

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

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

Прищипыванием её к программе!

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

Динамический

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

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


 
xGhost   (2003-11-01 10:12) [1]

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


 
xGhost   (2003-11-01 10:15) [2]

В общем я сделал так как описываеться в статье и у меня появилось несколько вопросов : как например передать некоторые переменные из плагина в exe файл ? я немного не шарю , может вы подскажете ! код рабочий и я думаю что нужно его только немного подкорректировать


 
xGhost   (2003-11-01 10:18) [3]

Вот готовый код того что тут есть , я немного переделал его чтобы он вызывал форму из dll , а вот параметры не могу сообразить как передавать :(

код : http://www.club-soft.narod.ru/plugins.rar


 
Calm   (2003-11-01 10:39) [4]


> как например передать некоторые переменные из плагина в
> exe файл ?


Код не читал, но если плугины основаны на обычных DLL, то IMHO никак.

P.S.
Обобщенное решение этой проблемы называется технологией COM


 
xGhost   (2003-11-01 11:33) [5]

Я имеол ввиду данные из exe в dll и наоборот ! как в dll только с помощью этого примера


 
DrPass   (2003-11-01 12:51) [6]

с помощью callback-функций, например. Exe передает в dll адреса, а процедуры/функции dll, когда надо, их вызывают


 
xGhost   (2003-11-01 13:13) [7]

> DrPass

Напиши подробней если не трудно , так хочешься понять как работают плагины , а опыта пока маловато :(


 
Юрий Зотов   (2003-11-01 14:01) [8]

> xGhost

Если Ваш плагин предназначен для использования ТОЛЬКО дельфишными программами, то Вы избавитесь от лишней головной боли, просто оформив его в виде пакета (BPL), а не DLL. Соответственно, программа должна компилиться c этим run-time пакетом, а пишется она самым обычным образом.

Кстати, в таком плагине можно без проблем использовать и любые объекты, и длинные строки, и динамические массивы. Вообще, в нем можно без проблем использовать все, что угодно.


 
xGhost   (2003-11-01 14:15) [9]

> Юрий Зотов

Спасибо учту , если найду информацию !
Мне просто очень понравился пример который я привёл ! там только добавить то что я хотел ( передача и получения значений ) с остальным я попробую справиться сам



Страницы: 1 вся ветка

Форум: "Потрепаться";
Текущий архив: 2003.11.24;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.5 MB
Время: 0.009 c
3-78796
Flash
2003-11-05 09:56
2003.11.24
lookup-поле + Grid


1-78924
Loki128
2003-11-12 08:39
2003.11.24
ListBox


8-79057
my4ga
2003-07-28 13:03
2003.11.24
звук


3-78780
Dmitriy O.
2003-11-05 16:44
2003.11.24
Как удалить все записи в таблице TADOTable


1-78903
Катерина
2003-11-12 15:30
2003.11.24
Создание метода RUN-TIME





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский