Интерфейсы и плагины

Дело в том, что методу Sort совсем не обязательно самому сравнивать и переставлять элементы вектора, эти операции можно поручить самому вектору. Поэтому я ввел два метода, которые обеспечивают именно сравнение и перестановку элементов, принимая на вход их индексы. Вот как выглядит метод Compare:clip0038 Кстати, если список параметров выглядит непривычно, то это всего лишь потому, что у меня установлено отображение библиотеки типов на IDL, языке определения интерфейсов. По умолчанию же в Delphi стоит отображение в нотации паскаля. Но в IDL видно, что на самом деле результат любого метода имеет тип HResult. И менять его так просто нельзя, это - соглашение, принятое для интерфейсов автоматизации. Каждый метод должен вернуть свой код завершения. Ничего страшного, параметр Result имеет модификаторы out, retval, и при отображении все будет нормально и привычно (если, конечно, действует соглашение safecall). Вот, кстати, мои настройки:clip0039 Интерфейсы, кстати, создались именно дуальные, поэтому методы будут иметь модификатор safecall. Так вот, в результате работы метод Compare возвращает константу из набора CompareResult, которая показывает порядок элементов с индексами Index1 и Index2 относительно друг друга. Этого вполне достаточно для большинства методов сортировки.После того, как библиотека создана, ее надо сохранить и зарегистрировать. Регистрация - вторая справа иконка, с узнаваемым значком реестра. Собственно, все, что она делает - это именно регистрация библиотеки в реестре. После этого библиотеку можно закрыть и приступить к реализации этих интерфейсов.Путь прежний: создаем новую библиотеку типов. Вот только добавлять будем не COM Object, а Automation Object, который работает с библиотекой типов и реализует необходимую функциональность. Сначала создадим объект для интерфейса IVector:clip0040 Будет создан модуль, содержащий в себе класс с именем, как несложно догадаться, TVector, и реализующий интерфейс IVector. Вот только не тот интерфейс, что нам нужен. Дело в том, что для COM не так важны названия интерфейсов, как их идентификаторы. И вот IID этого интерфейса совсем другой. Поэтому открываем библиотеку типов этой ActiveX library (по-английски, а то какая-то тавтология получается) и нагло удаляем оттуда интерфейс IVector, оставив только кокласс Vector. Теперь, чтобы стал известен наш интерфейс, нужно сделать пару не таких уж тривиальных шагов: встать на корень дерева, открыть вкладку uses и в контекстном меню вкладки выбрать "Show all type libraries". Затем долго листать список, пока не наткнешься на библиотеку SortIntf, и выбрать ее. Если ее там нет, то надо ее зарегистрировать (см выше). После этого снова выбрать в меню пункт "Show selected". Все, интерфейс стал известен. Теперь нужно добавить этот интерфейс на вкладку Implements кокласса Vector:clip0041 Снова воспользовавшись контекстным меню. Проект, кстати, я назвал VectorLib. Вот и все, остается только нажать на кнопку обновления, и в модуле будут автоматически сгенерированы шаблоны для методов. Кроме, того, в каталоге проекта будет создан файл SortIntf_TLB.pas, представляющий собой описание нашей библиотеки на паскале. Его нужно подключить к проекту, и записать в секцию uses модуля. После этого можно реализовывать методы интерфейса:

unit CVector;
{$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.
Немного поясню. Хотя Count и Elem объявлены как свойства (property), их все равно надо реализовывать через методы Get_... и Set_.... Просто потому, что у интерфейса, собственно говоря, данных нет, есть только методы. И, кстати, метод Compare приобрел вполне цивилизованный вид, как, впрочем, и все остальные. Это произошло именно из-за модификатора safecall.Реализацию я выбрал самую простую, через динамический массив. Не думаю что нужно комментировать код, все должно быть достаточно понятно. Свойство Elem имеет тип Variant, для универсальности.Теперь нужно опять зарегистрировать получившийся сервер, и у нас появится кокласс, который реализует вектор целых чисел.Вторая библиотека - реализация интерфейса ISort, который будет сортировать методом пузырька. Создается аналогично предыдущей, только на этот раз кокласс называем "Sort" и, подключив библиотеку SortIntf, реализуем интерфейс ISort:
unit CSort;
{$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.

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

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