Hack #7: Interface to Object [in The Delphi Magazine]
Due to the length and style, the following hack has been turned into a The Delphi Magazine article. IMO, this is simply the best Delphi magazine for professional developers and I highly recommend a subscription. Don't forget to get the Collection CD to read all my old articles :-) (in addition lots of other great articles too, of course).
Read the magazine article (update: in the October issue) to get the complete hack, explanations, history, the clean alternative, sample code and .NET comparison. As a teaser, here is the actual hack code:
function GetImplementingObject(const I: IInterface): TObject;
const
AddByte = $04244483;
AddLong = $04244481;
type
PAdjustSelfThunk = ^TAdjustSelfThunk;
TAdjustSelfThunk = packed record
case AddInstruction: longint of
AddByte : (AdjustmentByte: shortint);
AddLong : (AdjustmentLong: longint);
end;
PInterfaceMT = ^TInterfaceMT;
TInterfaceMT = packed record
QueryInterfaceThunk: PAdjustSelfThunk;
end;
TInterfaceRef = ^PInterfaceMT;
var
QueryInterfaceThunk: PAdjustSelfThunk;
begin
Result := Pointer(I);
if Assigned(Result) then
try
QueryInterfaceThunk := TInterfaceRef(I)^.QueryInterfaceThunk;
case QueryInterfaceThunk.AddInstruction of
AddByte: Inc(PAnsiChar(Result), QueryInterfaceThunk.AdjustmentByte);
AddLong: Inc(PAnsiChar(Result), QueryInterfaceThunk.AdjustmentLong);
else
Result := nil;
end;
except
Result := nil;
end;
end;
16 comments:
It doesn't look good in a RSS aggregator, such as SharpReader. Appears black on blue. Very very hard to read.
Chee Wee. ;o)
So? Sue me...! :-P
Seriously, that does sound like a bug in your RSS reader?
I like the classic Delphi colors ;).
> I like the classic Delphi colors ;).
Actually they're the original Turbo Pascal (and TC) colors (says an old-enough-to-have-actually-been-a-programmer-before-Delphi-existed programmer ) :-)
Matthijs Hebly, The Netherlands
First, I must add a disclaimer to the fact that I did not read The Delphi Magazine article, but I agree with you that it has the best content for the price.
The hack is certainly 'cool' and will be a hack solution in some cases... but in this is not a good thing to use because the whole objective of interfaces is to hide the implimentation from the user of the interface. If you misused this call, would it introduce implementation dependancies to the user of the interface? This would violate the Dependency Inversion Principle of OO design.
Ref www.objectmentor.com
John,
Indeed - that's what I say in the TDM article as well ;). And I show how to solve it the clean way. This is a last-resort hack when there so no other way to perform a task.
>Actually they're the original Turbo >Pascal (and TC) colors (says an >old-enough-to-have-actually-been-a-programmer-before-Delphi-existed >programmer ) :-)
I still use them in delphi, cause I'm so used to the TP colors. *chuckle*
I prefer black as my background color in the text editor: less straining on my eyes for prolonged coding sessions! :)
Similar, but not exactly equal, to the Twilight color scheme: I start with that scheme then make a couple changes...
But, for display in a webpage, this TP classic style has a bit more oomph...
Now I understand the reference to "The Delphi Magazine" which I though was dead: it is dead, it's just DelphiFeeds picking up your old articles because you're changing your site! :)
Note to those wanting to use this hack in newer versions of Delphi (2009+): You must change the two occurrences of PChar to PAnsiChar, otherwise you will get twice the increment (PChar is 2 bytes now by default).
Man, that was exactly what I needed! Thanx a lot!
Note also that for later versions of Delphi (since Delphi 2005 AFAIR), you have the "as" operator. See my own version in http://blog.synopse.info/post/2012/06/13/Retrieve-the-object-instance-from-an-interface
I tried this code but it cannot was compiled in my machine.
Incompatible types: 'TObject' and '_Pointer' << compiled error in the line below:
Result := Pointer(I);
How do I fix it ?
You probably have strict pointer types turned on in compiler options - you can probably compile the code by changing it to:
Result := TObject(Pointer(I));
Thank you for your quick answer.
Post a Comment