Delphi 3. Библиотека программиста

       

Интерфейсные формы


Когда я занялся реализацией интерфейсов из листинга 10.3, неожидан новозникли проблемы — моя система «зависала» при каждом вызове AddNotifiee(Self) из формы, реализующей IFrame. Хотя решение оказалось простым, мне пришлось в течение многих часов изобретать и проверять различные гипотезы. Чтобы вы лучше поняли суть происходившего, потребуется некоторая дополнительная информация.

Документация Delphi 3 достаточно четко объясняет, что каждый объект, реализующий какой-то интерфейс, должен также реализовать интерфейс IUnknown, в котором производятся подсчет ссылок и запросы поддерживаемых интерфейсов. Если компилятор встретит следующее объявление:

type IFoo = interface procedure Foo; end; TFoo = class (TObject, IFoo) procedure Foo; end;

procedure TFoo.Foo; begin end;

он пожалуется на наличие необъявленных идентификаторов QueryInterface, _AddRef и _Release. Вам придется явным образом реализовать IUnknown или создавать свой объект на базе TInterfaced, а не TObject. С другой стороны, следующий фрагмент не вызовет у компилятора никаких проблем:

type
TFoo = class (TForm, IFoo) procedure Foo; end; procedure TFoo.Foo; begin end;

Это означает, что фирма Borland реализовала IUnknown где-то в недрах VCL и у нас стало одной заботой меньше, не так ли?

Нет, не так. При передаче TForm в качестве интерфейсной ссылки VCL выдает ошибку защиты (GPF). Хотя класс TComponent и реализует методы IUnknown, это вряд ли поможет тем из нас, кто захочет воспользоваться интерфейсами в приложении. Вызовы IUnknown передаются FVCLComObject — указателю, значение которого задается лишь при вызове GetComObject для получения интерфейсной ссылки объекта. Более того, GetComObject задает значение FVCLComObject лишь в том случае, если вы использовали VCLCom в своем проекте. Если сделать это, GetComObject начинает жаловаться на то, что фабрика класса (class factory) не была зарегистрирована, и… на этом я прекратил свои исследования. Возможно, все это очень здорово, если вы собираетесь использовать COM-объекты совместно с другими приложениями, но совершенно не подходит, если нужно всего лишь добавить интерфейсы к формам.

Намного проще будет заглянуть в реализацию TInterfacedObject и включить в TForm простую, независимую реализацию IUnknown, а затем порождать формы от TInterfacedForm вместо TForm.

Листинг 10.3. Модуль INTERFACEDFORMS.PAS



unit InterfacedForms; // Copyright © 1997 by Jon //Shemitz, all rights reserved. // Permission is hereby granted to freely //use, modify, and // distribute this source code PROVIDED //that all six lines of // this copyright and contact notice are //included without any // changes. Questions? Comments? Offers of work? //mailto:jon@midnightbeach.com // -------------------------------------------- // Добавление в TForm функциональной реализации IUnknown. interface uses Classes, Forms; type TInterfacedForm = class (TForm, IUnknown) private fRefCount: integer; protected function QueryInterface( const IID: TGUID; Obj): Integer; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; public property RefCount: integer read fRefCount write fRefCount; end; implementation uses Windows; // для E_NOINTERFACE // Код IUnknown основан на исходном тексте TInterfacedObject function TInterfacedForm.QueryInterface ( const IID: TGUID; out Obj): Integer; begin if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE; end; function TInterfacedForm._AddRef: Integer; begin Inc(fRefCount); Result := fRefCount; end; function TInterfacedForm._Release: Integer; begin Dec(fRefCount); Result := fRefCount; if fRefCount = 0 then Destroy; end; end.

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



Содержание раздела