Главная » Delphi » Новые типы интерфейсов в библиотеке типов

0

Как и подобает каждому приличному разработчику Delphi, для определения новых экземпляров объектов автоматизации до сих пор  использовался редактор библиотек типов.  Но можно  легко попасть в ситуацию, когда один  из методов для нового интер фейса  включает в себя параметр типа интерфейса COM, который не поддерживается по умолчанию в редакторе библиотеки типов.  А поскольку  редактор библиотеки ти пов не позволяет работать с типами, о которых он не знает, то как же тогда завершить такое определение метода?

Прежде чем перейти к подробностям, важно  понять причины подобного поведе ния редактора библиотеки типов.  Если при  создании нового метода  в редакторе биб лиотеки типов  просмотреть типы, доступные в разделе Type вкладки  Parameters, то можно  увидеть такие  интерфейсы, как IDataBroker, IDispatch, IEnumVARIANT, IFont, IPicture, IProvider, IStrings и IUnknown. Почему  же  доступны  только эти интерфейсы? Что  делает их такими особенными? На самом деле в них нет ничего необычного —  просто они  являются типами, которые определены в библиотеках ти пов,   используемых  данной  библиотекой  типов.   По  умолчанию библиотека  типов Delphi  автоматически использует библиотеку типов  Borland Standard VCL и библио теку типов  OLE Automation. Для определения конфигурации собственной библиоте ки типов  выделите корневой узел в изображении дерева  на левой  панели редактора библиотеки  типов  и  перейдите  во  вкладку  Uses  на  правой  панели.  Типы,  содержа щиеся в библиотеках типов, используемых  данной  библиотекой,  станут  автоматиче

ски доступными в раскрывающемся списке редактора библиотеки типов.

Зная  все это,  нетрудно догадаться о том, что,  если интерфейс, который необходи мо использовать в качестве рассматриваемого параметра метода,  определен в биб лиотеке типов, то можно  просто использовать эту библиотеку типов  — и проблема бу дет решена. Но как быть,  если интерфейс в библиотеке типов  не определен? Ведь су ществует  довольно много  интерфейсов COM,  которые определяются только  инстру ментальными  средствами  комплекта   разработчика  программного обеспечения   (SDK — Software Development Kit) в файлах заголовков или IDL и не содержатся в библиоте ках типов.  В этом  случае лучше всего  определить параметр метода  с помощью типа IUnknown. Интерфейс типа  IUnknown может  быть опрошен с помощью метода  Que- ryInterface непосредственно в реализации метода,  что  позволит определить кон кретный тип  интерфейса, с которым предстоит работать. Необходимо также  обяза тельно описать этот  параметр метода  как тип IUnknown, что должно  обеспечить под держку соответствующего интерфейса. Следующий  фрагмент кода служит примером реализации такого  метода:

procedure TSomeClass.SomeMethod(SomeParam: IUnknown);

var

Intf: ISomeComInterface;

begin

Intf := SomeParam as ISomeComInterface;

// Остальная часть реализации метода

end;

Напомним, что  интерфейс, к которому приводят тип  IUnknown, должен  быть  ин терфейсом, для которого модели  COM известен способ  передачи параметров (маршалинга). Это означает, что он должен  быть либо определен в какой нибудь биб лиотеке типов, либо  должен  быть  типом, совместимым со стандартным маршалером автоматизации, либо рассматриваемый сервер COM должен  предоставить библиотеку DLL  с  заместителем заглушкой   (proxy/stub),  способной выполнить маршалинг ин терфейса.

Обмен двоичными данными

Рано  или поздно, но все же придется осуществлять обмен  блоками  двоичных дан ных  между клиентом и сервером автоматизации. Поскольку модель  COM  не поддер живает операций обмена  обычными указателями, решить задачу с помощью привыч ной  операции передачи указателя  не удастся.  Поэтому  воспользуемся другим,  более сложным способом. Самый  простой способ  обмена  двоичными данными между кли ентами и серверами автоматизации состоит в использовании массива  байтов  типа SafeArray. Delphi  успешно  инкапсулирует массивы  этого  типа  в переменных типа OleVariant. Достаточно изощренный пример подробных действий показан в лис тингах  15.13 и 15.14, содержащих код модулей клиента и сервера, в которых поля тек стового редактора используются для демонстрации методов передачи двоичных дан ных, представленных в виде массивов байт типа SafeArray.

Листинг 15.13. Модуль сервераunit ServObj;

interface uses

ComObj, ActiveX, Server_TLB;

type

TBinaryData = class(TAutoObject, IBinaryData)

protected

function Get_Data: OleVariant; safecall;

procedure Set_Data(Value: OleVariant); safecall;

end;

implementation

uses ComServ, ServMain;

function TBinaryData.Get_Data: OleVariant;

var

P: Pointer;

L: Integer;

begin

// Переместить данные из поля memo в массив

L := Length(MainForm.Memo.Text);

Result := VarArrayCreate([0, L – 1], varByte);

P := VarArrayLock(Result);

try

Move(MainForm.Memo.Text[1], P^, L);

finally

VarArrayUnlock(Result);

end;

end;

procedure TBinaryData.Set_Data(Value: OleVariant);

var

P: Pointer;

L: Integer;

S: string;

begin

// Переместить данные из массива в поле memo

L := VarArrayHighBound(Value, 1) -

VarArrayLowBound(Value, 1) + 1;

SetLength(S, L);

P := VarArrayLock(Value);

try

Move(P^, S[1], L);

finally

VarArrayUnlock(Value);

end;

MainForm.Memo.Text := S;

end;initialization

TAutoObjectFactory.Create(ComServer, TBinaryData,

Class_BinaryData,

ciSingleInstance, tmApartment);

end.

Листинг 15.14. Модуль клиента

unit CliMain;

interface uses

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

Dialogs, StdCtrls, ExtCtrls, Server_TLB;

type

TMainForm = class(TForm)

Memo: TMemo;

Panel1: TPanel;

SetButton: TButton;

GetButton: TButton;

OpenButton: TButton;

OpenDialog: TOpenDialog;

procedure OpenButtonClick(Sender: TObject);

procedure FormCreate(Sender: TObject);

procedure SetButtonClick(Sender: TObject);

procedure GetButtonClick(Sender: TObject);

private

FServer: IBinaryData;

end;

var

MainForm: TMainForm;

implementation

{$R *.DFM}

procedure TMainForm.FormCreate(Sender: TObject);

begin

FServer := CoBinaryData.Create;

end;

procedure TMainForm.OpenButtonClick(Sender: TObject);

begin

if OpenDialog.Execute then

Memo.Lines.LoadFromFile(OpenDialog.FileName);

end;

procedure TMainForm.SetButtonClick(Sender: TObject);var

P: Pointer;

L: Integer;

V: OleVariant;

begin

// Послать серверу данные поля memo

L := Length(Memo.Text);

V := VarArrayCreate([0, L – 1], varByte);

P := VarArrayLock(V);

try

Move(Memo.Text[1], P^, L);

finally

VarArrayUnlock(V);

end;

FServer.Data := V;

end;

procedure TMainForm.GetButtonClick(Sender: TObject);

var

P: Pointer;

L: Integer;

S: string;

V: OleVariant;

begin

// Получить от сервера данные поля memo

V := FServer.Data;

L := VarArrayHighBound(V, 1) – VarArrayLowBound(V, 1) + 1;

SetLength(S, L);

P := VarArrayLock(V);

try

Move(P^, S[1], L);

finally

VarArrayUnlock(V);

end;

Memo.Text := S;

end;

end.

Источник: Тейксейра, Стив, Пачеко, Ксавье.   Borland Delphi 6. Руководство разработчика. : Пер.  с англ. — М. : Издательский дом “Вильямс”, 2002. —  1120 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии