The main reference is the Barry Kelly article: An ugly alternative to interface to object casting.
Here is a re-factored version, as included in our
SQlite3Commons.pas unit. It will use the as operator
for newer versions, but use fast pascal code for compilers which do not support
this syntax.
{$ifndef ISDELPHI2010}
type
TObjectFromInterfaceStub = packed record
Stub: cardinal;
case integer of
0: (ShortJmp: shortint);
1: (LongJmp: longint)
end;
PObjectFromInterfaceStub = ^TObjectFromInterfaceStub;
{$endif}
/// low-level function to retrieve the class instance implementing a given
// interface
function ObjectFromInterface(const aValue: IInterface): TObject; {$ifdef HASINLINE}inline;{$endif}
begin
if aValue=nil then begin
result := nil;
exit;
end;
{$ifdef ISDELPHI2010}
result := aValue as TObject; // slower but always working
{$else}
with PObjectFromInterfaceStub(PPointer(PPointer(aValue)^)^)^ do
case Stub of
$04244483: result := pointer(PtrInt(aValue)+ShortJmp);
$04244481: result := pointer(PtrInt(aValue)+LongJmp);
else result := nil;
end;
{$endif}
end;
I suspect you'll find the resulting code more easy to read (perhaps not to understand), than the original.
Of course, we added support to out TInterfacedObjectFake
fake class used to implement
Interface-based services in mORMot, as such:
with PObjectFromInterfaceStub(PPointer(PPointer(aValue)^)^)^ do
case Stub of // address of VMT[0] entry, i.e. QueryInterface
$04244483: result := pointer(PtrInt(aValue)+ShortJmp);
$04244481: result := pointer(PtrInt(aValue)+LongJmp);
else
if Stub=PCardinal(@TInterfacedObjectFake.FakeQueryInterface)^ then
result := TInterfacedObjectFake(pointer(aValue)).SelfFromInterface else
result := nil;
end;
In its implementation, the as operator is able to find out
the object implementing our TInterfacedObjectFake "virtual
class".
In all cases, above code is very efficient, and will be easy to maintain.
