Интерфейсы и плагины
Дело в том, что методу Sort совсем не обязательно самому сравнивать и переставлять элементы вектора, эти операции можно поручить самому вектору. Поэтому я ввел два метода, которые обеспечивают именно сравнение и перестановку элементов, принимая на вход их индексы. Вот как выглядит метод Compare: Кстати, если список параметров выглядит непривычно, то это всего лишь потому, что у меня установлено отображение библиотеки типов на IDL, языке определения интерфейсов. По умолчанию же в Delphi стоит отображение в нотации паскаля. Но в IDL видно, что на самом деле результат любого метода имеет тип HResult. И менять его так просто нельзя, это - соглашение, принятое для интерфейсов автоматизации. Каждый метод должен вернуть свой код завершения. Ничего страшного, параметр Result имеет модификаторы out, retval, и при отображении все будет нормально и привычно (если, конечно, действует соглашение safecall). Вот, кстати, мои настройки: Интерфейсы, кстати, создались именно дуальные, поэтому методы будут иметь модификатор safecall. Так вот, в результате работы метод Compare возвращает константу из набора CompareResult, которая показывает порядок элементов с индексами Index1 и Index2 относительно друг друга. Этого вполне достаточно для большинства методов сортировки.После того, как библиотека создана, ее надо сохранить и зарегистрировать. Регистрация - вторая справа иконка, с узнаваемым значком реестра. Собственно, все, что она делает - это именно регистрация библиотеки в реестре. После этого библиотеку можно закрыть и приступить к реализации этих интерфейсов.Путь прежний: создаем новую библиотеку типов. Вот только добавлять будем не COM Object, а Automation Object, который работает с библиотекой типов и реализует необходимую функциональность. Сначала создадим объект для интерфейса IVector: Будет создан модуль, содержащий в себе класс с именем, как несложно догадаться, TVector, и реализующий интерфейс IVector. Вот только не тот интерфейс, что нам нужен. Дело в том, что для COM не так важны названия интерфейсов, как их идентификаторы. И вот IID этого интерфейса совсем другой. Поэтому открываем библиотеку типов этой ActiveX library (по-английски, а то какая-то тавтология получается) и нагло удаляем оттуда интерфейс IVector, оставив только кокласс Vector. Теперь, чтобы стал известен наш интерфейс, нужно сделать пару не таких уж тривиальных шагов: встать на корень дерева, открыть вкладку uses и в контекстном меню вкладки выбрать "Show all type libraries". Затем долго листать список, пока не наткнешься на библиотеку SortIntf, и выбрать ее. Если ее там нет, то надо ее зарегистрировать (см выше). После этого снова выбрать в меню пункт "Show selected". Все, интерфейс стал известен. Теперь нужно добавить этот интерфейс на вкладку Implements кокласса Vector: Снова воспользовавшись контекстным меню. Проект, кстати, я назвал VectorLib. Вот и все, остается только нажать на кнопку обновления, и в модуле будут автоматически сгенерированы шаблоны для методов. Кроме, того, в каталоге проекта будет создан файл SortIntf_TLB.pas, представляющий собой описание нашей библиотеки на паскале. Его нужно подключить к проекту, и записать в секцию uses модуля. После этого можно реализовывать методы интерфейса:
{$WARN SYMBOL_PLATFORM OFF}
interface
uses
ComObj, ActiveX, VectorLib_TLB, StdVcl, SortIntf_TLB;
type
TVector = class(TAutoObject, IVector)
private
FArray: array of integer;
protected
function Compare(Index1, Index2: Integer): CompareResult; safecall;
function Get_Count: Integer; safecall;
function Get_Elem(Index: Integer): OleVariant; safecall;
procedure Exchange(Index1, Index2: Integer); safecall;
procedure Set_Count(Value: Integer); safecall;
procedure Set_Elem(Index: Integer; Value: OleVariant); safecall;
{ Protected declarations }
end;
implementation
uses ComServ;
function TVector.Compare(Index1, Index2: Integer): CompareResult;
begin
Result := crLower;
if FArray[Index1] > FArray[Index2] then
Result := crGreater;
if FArray[Index1] = FArray[Index2] then
Result := crEqual;
end;
function TVector.Get_Count: Integer;
begin
Result := Length(FArray);
end;
function TVector.Get_Elem(Index: Integer): OleVariant;
begin
Result := FArray[Index];
end;
procedure TVector.Exchange(Index1, Index2: Integer);
var
T: integer;
begin
T := FArray[Index1];
FArray[Index1] := FArray[Index2];
FArray[Index2] := T;
end;
procedure TVector.Set_Count(Value: Integer);
begin
if Value <> Length(FArray) then
SetLength(FArray, Value);
end;
procedure TVector.Set_Elem(Index: Integer; Value: OleVariant);
begin
FArray[Index] := Value;
end;
initialization
TAutoObjectFactory.Create(ComServer, TVector, Class_Vector,
ciMultiInstance, tmApartment);
end.
{$WARN SYMBOL_PLATFORM OFF}
interface
uses
ComObj, ActiveX, SortLib_TLB, StdVcl, SortIntf_TLB;
type
TSort = class(TAutoObject, ISort)
protected
procedure Sort(const Vector: IVector); safecall;
{ Protected declarations }
end;
implementation
uses ComServ;
procedure TSort.Sort(const Vector: IVector);
var
I, J: Integer;
begin
for I := Vector.Count - 1 downto 0 do
for J := 0 to Vector.Count - 2 do
if Vector.Compare(J, J + 1) = crGreater then
Vector.Exchange(J, J + 1);
end;
initialization
TAutoObjectFactory.Create(ComServer, TSort, Class_Sort,
ciMultiInstance, tmApartment);
end.
Отправить комментарий