Есть такая задача. Необходимо преобразовывать IUnknown->Pointer и обратно. Проблема состоит в том, что при преобразовании Pointer->IUnknown экземпляр уже вполне может быть уничтожен. Для безопасного преобразования была написана функция:
function SafePointerToInterface(var APointer: Pointer;
ARequiredIID: TGUID): IInterface;
begin
Result := nil;
if (not Assigned(APointer)) then
begin
Exit;
end;
try
IInterface(APointer).QueryInterface(ARequiredIID, Result);
CheckSupports(Result, ARequiredIID);
except
on E: Exception do
begin
APointer := nil;
Result := nil;
end;
end;
end;
Все было бы хорошо, но вот почемуто иногда, после уничтожения экземпляра, она приводит к зависанию приложения. Может кто нибудь предолжет более корректную реализацию данной функции?
Здравствуйте, Karluha, Вы писали:
D>>Напрашивается вопрос: для чего была произведено приведение IUnknown в Pointer. Есть догадка — для того чтобы запихтуть эго в какую то структуру, которая поддерживает только указатели.
K>Необходимо это для организации взаимных ссылок между двумя экземплярами, например Parent-Child. Это возможно только через Pointer, особенно если экземпляры описаны в разных, ничего не знающих друг о друге Library. Это значит что и нотификаций быть никаких не может, т.к. я ссылаюсь на чужой экземпляр IUnknown и при этом не хочу его держать.
Тебе необходимо организовать механизм WeakReference.
Вот набросал за пару минут пример реализации такого взаимодействия (untested):
unit Unit1;
interface
uses
Windows, SysUtils, Classes;
type
TWeakReference = class;
IParent = interface
['{1D408CF3-962A-4FAE-ABC4-1910F6F89205}']
procedure AddWeakRefernce (aReference : TWeakReference);
procedure RemoveWeakRefernce (aReference : TWeakReference);
end;
TAbstractParent = class(TInterfacedObject, IParent)
private
FReferences : TList;
protected
procedure AddWeakRefernce (aReference : TWeakReference);
procedure CleanupWeakReferences;
function NeedReferencesList: TList;
procedure RemoveWeakRefernce (aReference : TWeakReference);
public
destructor Destroy; override;
end;
TWeakReference = class
private
FReference: IUnknown;
protected
function GetReference: IUnknown;
procedure SetReference(Value: IUnknown);
public
constructor Create (aReference : IUnknown);
destructor Destroy; override;
property Reference: IUnknown read GetReference write SetReference;
end;
TAbstractChild = class
private
FParent : TWeakReference;
protected
function GetParent: IUnknown;
procedure SetParent(Value: IUnknown);
public
constructor Create;
destructor Destroy; override;
property Parent: IUnknown read GetParent write SetParent;
end;
implementation
//==================================================================================================
// class TWeakReference
//==================================================================================================
constructor TWeakReference.Create(aReference: IInterface);
begin
inherited Create;
Reference := aReference;
end;
destructor TWeakReference.Destroy;
begin
Reference := nil;
inherited;
end;
function TWeakReference.GetReference: IUnknown;
begin
Result := FReference;
end;
procedure TWeakReference.SetReference(Value: IUnknown);
var
aParent : IParent;
begin
if FReference = Value then
Exit;
if Supports (FReference, IParent, aParent) then
aParent.RemoveWeakRefernce(Self);
if Supports (Value, IParent, aParent) then
aParent.AddWeakRefernce(Self);
Pointer (FReference) := Pointer (Value);
end;
//==================================================================================================
// class TAbstractParent
//==================================================================================================
destructor TAbstractParent.Destroy;
begin
CleanupWeakReferences;
inherited;
end;
procedure TAbstractParent.AddWeakRefernce(aReference: TWeakReference);
begin
NeedReferencesList.Add (aReference);
end;
procedure TAbstractParent.CleanupWeakReferences;
var
K: Integer;
begin
if FReferences = nil then
Exit;
{ In this place pefrormance can be increased }
while (FReferences <> nil) and (FReferences.Count > 0) do
TWeakReference (FReferences [FReferences.Count - 1]).Reference := nil;
FreeAndNil (FReferences);
end;
function TAbstractParent.NeedReferencesList: TList;
begin
if FReferences = nil then
FReferences := TList.Create;
Result := FReferences;
end;
procedure TAbstractParent.RemoveWeakRefernce(aReference: TWeakReference);
begin
if FReferences = nil then
Exit;
FReferences.Remove(aReference);
if FReferences.Count = 0 then
FreeAndNil (FReferences);
end;
//==================================================================================================
// class TAbstractChild
//==================================================================================================
constructor TAbstractChild.Create;
begin
FParent := TWeakReference.Create(nil);
end;
destructor TAbstractChild.Destroy;
begin
FParent.Free;
inherited;
end;
function TAbstractChild.GetParent: IUnknown;
begin
Result := FParent.Reference;
end;
procedure TAbstractChild.SetParent(Value: IUnknown);
begin
if Parent = Value then
Exit;
FParent.Reference := Value;
{ in this place you should add code that appends this object as a children to a Parent}
end;
end.
Удачи!