![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
COM [Delphi, Windows]
vk220 © (2004-05-07 17:01:00)Проблема такая: есть интерфейс Data.
Есть подчинённые ему интерфейсы Field.
При создании Fieldфункция _AddRefвызывается конструктором Field.
А при уничтожении Field:
Field := nil;
проверяется счётчик ссылок (в модуле System функ. _Release) и т.к. их не 0,
Fieldпросто не удаляется... соответсвенно проц. BeforeDestructionне вызывается.
Я не очень хорошо знаю технологию COM, если кто-нибудь понял изложенное выше, помогите,
пожалуйста.
Также буду благодарен за ссылки, где можно почитать о COM. (в Delphi)
Бином Ньютоныч (2004-05-09 09:01:00) [1]>vk220 © (08.05.04 19:47) [3]
Как видишь, в моем примере нет ни одного явного вызова методов IUmknown, тем не менее объекты уничтожаются в нужный момент. Интерфейс в Delphi относится к типам с автоматическим управлением временем жизни. Компилятор сам вставляет вызовы AddRef и Release при присвоении/освобождении интерфейсных переменных. Самому делать эти вызовы нужно только в редких, особых случаях, четко представляя себе происходящее.
var
A: IData;
B: IField;
A:=TData.Create;
Здесь будет создан объект TData, получен указатель на его интерфейс IData и, в процессе присвоения его переменной А, будет вызван метод AddRef.
A.GetField(B);
Здесь тоже самое для объекта TField. Кроме того, указатель на IUnknown TData будет сохранен в поле FController объекта TField, при этом будет автоматически вызван IUnknown.AddRef объекта TData. Теперь счетчик будет содержать 2.
A:=nil
Будет вызван метод Release объекта TData, но объект не будет уничтожен, т.к. сохраняется ссылка на него в TField.FController.
B:=nil;
Здесь будет вызван Release объекта TField, при этом его счетчик ссылок обнулится, в результате чего будет автоматически вызван его деструктор. В процессе уничтожения объекта будет автоматически освобождена ссылка, хранящаяся в поле FController с вызовом Release объекта TData. Его счетчик ссылок обнулится и он тоже будет уничтожен.
Если же у тебя при освобождении интерфейсной переменной объект не уничтожается, то это значит, что где-то осталась неосвобожденная ссылка, либо был лишний несбалансированный вызов AddRef. Возможно, ты используешь перекрестные ссылки:
TData хранит IField, а TField хранит IData.
В таких случаях следует одно из полей сделать типа Pointer и при обращении к нему использовать прямое привидение. При этом автоматический подсчет ссылок производиться не будет.
vk220 (2004-05-08 19:47:00) [2]>Не нужно вызывать AddRef в конструкторе
Я убрал из конструктора эту команду. Счётчик ссылок тем не менее увеличивается. Как у Data, так и у Field.
Я вот чего не могу понять: Счётчик ссылок увеличивается/уменьшается автоматически, или мне надо самому вызывать _AddRef и _Release?
Увеличивается он ещё как, а вот убавляться совсем не хочет.
Бином Ньютоныч (2004-05-07 20:25:00) [3]Не нужно вызывать AddRef в конструкторе. Как я понял, Field возвращается клиенту методами Data, и Data должен жить, пока жив хотя-бы один Field. Тогда следует в том или ином виде использовать аггрегацию. Пожалуй, наиболее наглядно это можно сделать так:
IField = interface;
IData = interface
procedure GetField(out Field: IField);
end;
TData = class(..., IData)
procedure GetField(out Field: IField);
end;
TField = class(..., IField)
FController: IUnknown;
constructor Create(Controller: IUnknown);
end;
procedure TData.GetField(out Field: IField);
begin
Field:=TField.Create(Self);
end;
constructor TField.Create(Controller: IUnknown);
begin
FController:=Controller;
end;
Это очень простой случай, зато все наглядно. Также внимательно присмотрись к реализации в TComObject методов IUnknown для самого IUnknown и для других интерфейсов, держа в уме, что аггрегироваться объект может не только по IUnknown, но и по любому другому интерфейсу. Главное четко представлять, когда объект должен оперировать собственным счетчиком ссылок, а когда переправлять вызов контроллеру.
clickmaker (2004-05-07 18:47:00) [4]http://rsdn.ru/summary/266.xml