Начало
Для создания модулей расширения в среде
Borland Delphi на сегодняшний
день применяются 3 основные технологии:
Недостатком технологии
DLL является сложность
разработки прикладного программного интерфейса. Недостатком при использовании
Packages является жесткая привязка к Delphi и C++ Builder,
что является крайне не желательным при сегодняшней распространенности других
средств разработки, например: Microsoft Visual Studio.
Таким образом, технология
COM
предоставляет программисту возможность не привязываться к конкретному продукту
для разработки ПО.
Приступим
Для
демонстрации технологии разработки плагинов я придумал довольно простую
программу, которая будет производить различные операции над двумя вещественными
числами.
Шаг 1
Для начала нам необходимо определится, какие функции будет выполнять
плагин. Скорее всего, он должен получить 2 числа, выполнить над ними какие-либо
операции и возвратить результат в программу. При использовании обычных DLL мы просто сделали бы функцию следующего вида
function F(a,
b: extended):extended. При использовании
COM технологии, в
данном примере, всё будет немного сложнее. Нам придется разработать интерфейс
для приложения и для плагина.Интерфейсный модуль:
unit PlugIntf;
interface
const
Class_CalcAPI: TGUID = '{DA18785D-BF58-4C2B-A816-EA1272DDF09E}';
type
ICalcAPI = interface
['{21F0FFFE-9FC7-4C6C-87CE-9BAF44628E46}']
procedure GetResult(const Result: Extended);
procedure ShowMessage(const S: WideString);
end;
IPluginAPI = interface
['{F114301D-075E-4A75-B431-62409F406348}']
procedure Init();
procedure Funct(A, B: Extended);
end;
implementation
end.
Константа
Class_CalcAPI будет использоваться нами в плагинах для
соединения с приложением и передачи ему результатов.
Реализация интерфейса ICalcAPI является довольно простой, её можно
посмотреть в исходном коде приложения. Для автоматического создания такого кода,
кроме реализации методов интерфейса, можно поступить следующим образом: создать
новый COM
объект (вкладка ActiveX)
автоматически будет создан модуль примерно следующего
содержания:
unit Unit2;
{$WARN SYMBOL_PLATFORM OFF}
interface
uses
Windows, ActiveX, Classes, ComObj, PlugIntf;
type
TCalcAPI = class(TComObject, ICalcAPI)
protected
procedure GetResult(const Result: Extended);
procedure ShowMessage(const S: WideString);
end;
implementation
uses Forms, ComServ, Unit1, SysUtils;
{ TCalcAPI }
procedure TCalcAPI.GetResult(const Result: Extended);
begin
(Application.MainForm as TForm1).Edit3.Text := FloatToStr(Result);
end;
procedure TCalcAPI.ShowMessage(const S: WideString);
begin
Form1.Memo1.Lines.Add(S)
end;
initialization
TComObjectFactory.Create(ComServer, TCalcAPI, Class_CalcAPI,
'CalcAPI', '', ciMultiInstance, tmSingle);
end.
Следует
обратить внимание на последние строки данного модуля. При автоматическом
создании данного модуля константа
Class_CalcAPI
будет находится в данном модуле. Я намеренно перенес данную константу в модуль с
интерфейсами т.к. мы будем её использовать в плагинах, а им будет доступен
только модуль с заголовками. В принципе на этом реализация программного
интерфейса для приложения завершена.
Шаг 2
Для создания
плагина нам потребуется всего один файл
PlugIntf.pas,
т.к. в нем содержится вся необходимая информация.
Для того
чтобы создать модуль необходимо сначала создать библиотеку, которая будет
содержать данный плагин, затем реализовать программный интерфейс плагина.
Для создания
библиотеки необходимо сделать следующее на странице
ActiveX выбрать ActiveX Library, после этого будет автоматически создан необходимый код для нашей
библиотеки.
library Project1;
uses
ComServ;
exports
DllGetClassObject,
DllCanUnloadNow,
DllRegisterServer,
DllUnregisterServer;
{$R *.RES}
begin
end.
Затем добавим COM
Объект который будет реализовывать интерфейс для плагина.
мастер автоматически создаст заготовку для реализации
нашего плагина.
unit Unit1;
{$WARN SYMBOL_PLATFORM OFF}
interface
uses
Windows, ActiveX, Classes, ComObj;
type
TCOMCalcDivPlugin = class(TComObject)
protected
end;
const
Class_COMCalcDivPlugin: TGUID = '{FF85A614-170B-4885-878B-886D321B9E95}';
implementation
uses ComServ;
initialization
TComObjectFactory.Create(ComServer, TCOMCalcDivPlugin, Class_COMCalcDivPlugin,
'COMCalcDivPlugin', '', ciMultiInstance, tmApartment);
end.
Далее необходимо подключить к
данному модулю модуль
PlugIntf.pas и
реализовать методы интерфейса IPluginAPI. В итоге у нас получится что-то вроде
следующего кода:
unit Unit1;
{$WARN SYMBOL_PLATFORM OFF}
interface
uses
Windows, ActiveX, Classes, ComObj, PlugIntf;
type
TCOMCalcAddPlugin = class(TComObject, IPluginAPI)
private
FCalcAPI: ICalcAPI;
protected
procedure Init();
procedure Funct(A, B: Extended);
end;
const
Class_COMCalcAddPlugin: TGUID = '{8AAA1D29-3C8A-438E-9A78-637072EDCC3F}';
implementation
uses ComServ;
{ TCOMCalcAddPlugin }
procedure TCOMCalcAddPlugin.Funct(A, B: Extended);
begin
FCalcAPI.GetResult(A+B);
end;
procedure TCOMCalcAddPlugin.Init;
begin
FCalcAPI := CreateComObject(Class_CalcAPI) as ICalcAPI;
FCalcAPI.ShowMessage('Plugin ADD Init...');
end;
initialization
TComObjectFactory.Create(ComServer, TCOMCalcAddPlugin, Class_COMCalcAddPlugin,
'COMCalcAddPlugin', '', ciMultiInstance, tmSingle);
end.
Рекомендую обратить внимание на
реализацию метода Init
в нем мы подключаемся к уже существующему
интерфейсу. Если попытаться вызвать методы данного плагина из другого
приложения, то (в зависимости от реализации
COM серверов) могут быть 2
варианта:
- Плагин запустит приложение
COMCalc.exe
и будет продолжать работать
- Плагин не сможет запустить приложение
COMCalc.exe и
вылетит с ошибкой.
В моей практике случалось и то и
другое.
На этом наш плагин готов к
работе осталось только его вызвать.
Шаг 3
Для простоты я создал следующий файл:
[simple]
add={8AAA1D29-3C8A-438E-9A78-637072EDCC3F}
sub={D645945D-E9D7-44DC-A269-0839F9DC118C} В данном файле напротив имени
плагина находится его GUID,
по которому он будет вызваться в нашем приложении.
Код для вызова плагина
приводится ниже. Ничего особенно сложного я в данном коде не вижу. На мой взгляд
данный код не должен нуждаться в комментариях, т.к. он довольно простой.
var
ini: TIniFile;
PlugGUID: String;
PlugName: String;
Plugin: IPluginAPI;
begin
if ListBox1.ItemIndex > -1 then
begin
ini := TIniFile.Create(ExtractFilePath(Application.ExeName)+'plugins.ini');
PlugName := ListBox1.Items[ListBox1.ItemIndex];
try
PlugGUID := ini.ReadString('simple',PlugName,'');
finally
ini.Free;
end;
Plugin := CreateComObject (StringToGUID(PlugGUID)) as IPluginAPI;
Plugin.Init;
Plugin.Funct(StrToFloat(Edit1.Text),StrToFloat(Edit2.Text));
endelse
ShowMessage('необходимо выбрать плагин')
end;
В принципе можно было сделать
так, чтобы плагины регистрировали сами себя при установке, но так как данная
статься является всего лишь показывает методику разработки плагинов на основе
технологии COM, то я
не стал рассказывать об этом.
Заключение
Здесь я привожу несколько замечаний по статье:
- В статье ни разу я не указывал путь к плагинам. При
использовании
COM технологии можно вообще забыть про пути, т.к. при
регистрации библиотеки в системном реестре прописывается путь к
ней, а при вызове система сама находит данную библиотеку.
- Если просто скомпилировать данный пример и
запустить, то скорее всего он у вас не будет работать, после
компиляции плагинов необходимо их зарегистрировать. Это можно
сделать двумя путями
- В командной строку написать
regsvr32 <имя плагина>.dll
- В меню
делфи Run -> Register ActiveX Server
- Не буду отрицать, что у технологии COM нет
недостатков. Например ограниченность типов данных.
Для более
подробного знакомства с данной технологией я рекомендую всем книгу «Делфи и
технология COM», Питер
2003, Серия Мастер Класс.
Автор -
Непряхин Алексей
|