Создание модулей расширения с использованием технологии COM

Автор - Непряхин Алексей, специально для Realcoding.NET (c) 2004

Примеры к статье: com_plugins.rar

Начало

            Для создания модулей расширения в среде Borland Delphi на сегодняшний день применяются 3 основные технологии:

  • DLL
  • COM
  • Packages

Недостатком технологии 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 варианта:

  1. Плагин запустит приложение COMCalc.exe и будет продолжать работать
  2. Плагин не сможет запустить приложение 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, Серия Мастер Класс.



Опубликовал admin
19 Июл, Понедельник 2004г.



Программирование для чайников.