Собираем тестовый пример

Теперь, давайте соберем код. Прошу учесть, что практически не делается никаких проверок - это демонстрационный код. Но работающий.
В начале код dll c объектом.

library CalcDll;

uses

 SysUtils,

 Classes;

type

 HResult=Longint;

 ICalcBase=interface  //чисто абстрактный интерфейс

  procedure SetOperands(x,y:integer);

  procedure Release;

 end;

 ICalc=interface(ICalcBase)

  ['{149D0FC0-43FE-11D6-A1F0-444553540000}']

  function Sum:integer;

  function Diff:integer;

 end;

 ICalc2=interface(ICalcBase)

  ['{D79C6DC0-44B9-11D6-A1F0-444553540000}']

  function Mult:integer;

  function Divide:integer;

 end;

 MyCalc=class(TObject,ICalc,ICalc2) //два интерфейса

  fx,fy:integer;

 public

  procedure SetOperands(x,y:integer);

  function Sum:integer;

  function Diff:integer;

  function Divide:integer;

  function Mult:integer;

  procedure Release;

  function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;

  function _AddRef:Longint; stdcall;

  function _Release:Longint; stdcall;

 end;

const

 S_OK = 0;

 E_NOINTERFACE = HRESULT($80004002);

procedure MyCalc.SetOperands(x,y:integer);

begin

 fx:=x; fy:=y;

end;

function MyCalc.Sum:integer;

begin

 result:=fx+fy;

end;

function MyCalc.Diff:integer;

begin

 result:=fx-fy;

end;

function MyCalc.Divide:integer;

begin

 result:=fx div fy;

end;

function MyCalc.Mult:integer;

begin

 result:=fx*fy;

end;

procedure MyCalc.Release;

begin

 Free;

end;

function MyCalc.QueryInterface(const IID: TGUID; out Obj): HResult;

begin

 if GetInterface(IID, Obj) then

  Result := S_OK

 else

  Result := E_NOINTERFACE;

end;

function MyCalc._AddRef;

begin

end;

function MyCalc._Release;

begin

end;

procedure CreateObject(const IID: TGUID; var ACalc);

var

 Calc:MyCalc;

begin

 Calc:=MyCalc.Create;

 if not Calc.GetInterface(IID,ACalc) then

 Calc.Free;

end;

exports

 CreateObject;

begin

end.

А теперь тестер.

unit tstcl;

interface

uses

 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

 StdCtrls,ComObj;

type

 //обратите внимание! Используем один унифицированный интерфейс

 IUniCalc=interface  

  procedure SetOperands(x,y:integer);

  procedure Release;

  function Sum:integer;

  function Diff:integer;

 end;

 TForm1 = class(TForm)

  Button1: TButton;

  Button2: TButton;

  Button3: TButton;

  procedure FormCreate(Sender: TObject);

  procedure FormDestroy(Sender: TObject);

  procedure Button1Click(Sender: TObject);

  procedure Button2Click(Sender: TObject);

  procedure Button3Click(Sender: TObject);

 end;

var

 Form1: TForm1;

 _Mod:Integer; //хэндл модуля

 СreateObject:procedure (IID:TGUID; out Obj); //процедура из dll.

 Calc:IUniCalc; //это указатель на интерфейс котрый мы будем получать

 ICalcGUID:TGUID;

 ICalc2GUID:TGUID;

 flag:boolean; // какой интерфейс активный.

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);

begin

 _Mod:=LoadLibrary(PChar('C:\Kir\COM\SymplDll\CalcDll.dll'));

 //Эти GUID я просто скопировал из исходника CalcDll.dll

 ICalcGUID:=StringToGUID('{149D0FC0-43FE-11D6-A1F0-444553540000}');

 ICalc2GUID:=StringToGUID('{D79C6DC0-44B9-11D6-A1F0-444553540000}');

 flag:=true;

 СreateObject:=GetProcAddress(_Mod,'CreateObject');

 СreateObject(ICalcGUID,Calc);

 if Calc<>nil then

  Calc.SetOperands(10,5);

end;

procedure TForm1.FormDestroy(Sender: TObject);

begin

 if Calc<>nil then

  Calc.Release;

 FreeLibrary(_Mod);

end;

procedure TForm1.Button1Click(Sender: TObject);

begin

  ShowMessage(IntToStr(Calc.diff));

end;

procedure TForm1.Button2Click(Sender: TObject);

begin

  ShowMessage(IntToStr(Calc.Sum));

end;

procedure TForm1.Button3Click(Sender: TObject);

var

  tmpCalc:IUniCalc;

begin

  if flag then

  Calc.QueryInterface(ICalc2GUID,tmpCalc)

  else

  Calc.QueryInterface(ICalcGUID,tmpCalc);

  flag:=not flag;

  Calc:=tmpCalc;

end;

end.

Обратите вснимание, что происходит при нажатии на кнопку3. Мы используем ту же самую переменную, для работы со вторым интерфейсом! Этот пример показывает, что получая указатель на интерфейс, его методы мы получаем за счет смещения, от адреса который этот указатель содержит. Короче, мы получаем адрес таблицы методов.
Потыкайте, посмотрите что происходит.

Отправить комментарий

Проверка
Антиспам проверка
Image CAPTCHA
...