I’ve been mucking around with Allen Bauer’s code for a generic multicast event dispatcher (see his blog posts about it here).
He gives just enough code to make me want to use it, and unfortunately he hasn’t posted the full source. I had a bash at getting it to work, but my assembler skills are non-existent.
My problem is the InternalSetDispatcher method. The naive approach is to use the same assembler as for the other InternalXXX methods:
procedure InternalSetDispatcher;
begin
XCHG EAX,[ESP]
POP EAX
POP EBP
JMP SetEventDispatcher
end;
But this is used for procedures with one const parameter, like this:
procedure Add(const AMethod: T); overload;
And SetDispatcher has two parameters, one a var:
procedure SetEventDispatcher(var ADispatcher: T; ATypeData: PTypeData);
So, I assume that the stack would get corrupted. I know what the code is doing (cleaning up the stack frame from the call to InternalSetDispatcher by popping the hidden reference to self and I assume the return address), but I just can’t figure out that little bit of assembler to get the whole thing going.
EDIT: Just to clarify, what I am looking for is the assembler that I could use to get the InternalSetDispatcher method to work, ie, the assembler to cleanup the stack of a procedure with two parameters, one a var.
EDIT2: I’ve amended the question a little, thank you to Mason for his answers so far. I should mention that the code above does not work, and when SetEventDispatcher returns, an AV is raised.
The answer, after I have done a lot of running around on the web, is that the assembler assumes that a stack frame is present when calling in to InternalSetDispatcher.
It seems that a stack frame was not being generated for the call to InternalSetDispatcher.
So, the fix is as easy as turning on stack frames with the {$stackframes on} compiler directive and rebuilding.
Thanks Mason for your help in getting me to this answer. 🙂
Edit 2012-08-08: If you’re keen on using this, you might want to check out the implementation in the Delphi Sping Framework. I haven’t tested it, but it looks like it handles different calling conventions better than this code.
Edit: As requested, my interpretation of Alan’s code is below. On top of needing stack frames turned on, I also needed to have optimization turned on at the project level for this to work: