I've written a function that accepts a class type (T) and an interface type (I) and returns an interface (I) to the object (T). Here's the code.
interface
function CreateObjectInterface<T: Class, constructor; I: IInterface>(
out AObject: TObject): I;
...
implementation
function TORM.CreateObjectInterface<T, I>(out AObject: TObject): I;
begin
AObject := T.Create;
if not Supports(AObject, GetTypeData(TypeInfo(I))^.Guid, Result) then
begin
AObject.Free;
AObject := nil;
raise EORMUnsupportedInterface.CreateFmt(
'Object class "%s" does not support interface "%s"',
[AObject.ClassName, GUIDToString(GetTypeData(TypeInfo(I))^.GUID)]
);
end;
end;
The function works as expected with no memory leaks or other undesirables.
Are there other ways to achieve the same result?
There is a bug in this code. Supports will destroy your object instance if it supports IUnknown
but not the interface you are asking for.
Simple demonstration:
type
IFoo = interface
['{32D3BE83-61A0-4227-BA48-2376C29F5F54}']
end;
var
o: TObject;
i: IFoo;
begin
i := TORM.CreateObjectInterface<TInterfacedObject, IFoo>(o); // <- boom, invalid pointer
end.
Best to put IInterface
or IUnknown
as additional constraint to T
.
Or make sure that you are not destroying an already destroyed instance.
Unless you want to support dynamic QueryInterface
implementations (where the class does not implement the interface but QueryInterface
returns it) I would go with a Supports
call on the class:
function TORM.CreateObjectInterface<T, I>(out AObject: TObject): I;
begin
if not Supports(TClass(T), GetTypeData(TypeInfo(I))^.Guid) then
raise EORMUnsupportedInterface.CreateFmt(
'Object class "%s" does not support interface "%s"',
[AObject.ClassName, GUIDToString(GetTypeData(TypeInfo(I))^.GUID)]
);
AObject := T.Create;
Supports(AObject, GetTypeData(TypeInfo(I))^.Guid, Result);
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With