@Jaafar Tribak
- Been using AddressOf for ages but never knew this. Did you learn about this in some advanced VB* textbook or something ?
No. I made a deduction based on my findings.
And when you say (delegate object), do you mean a propper vtable in memory with pointers to the IUnknown and maybe the IDispatch interfaces ?
Yes and no. You probably know that you can access standard modules methods like
this so it makes sense there is an underlying mechanism that does the same thing with AddressOf. The structure seems to be different though - meaning it definitely does not look like the AddressOf operator returns the address of an object derived from IUnknown or IDispatch. Unfortunately, the pointers at that 52 offset indicate a memory address where we don't have read permission.
- Now, going back to your mousehook project , I don't see in the code below any swapping taking place as much as I see overriding the FakeCallback delegate.
If my understanding is correct, after calling CopyMemory, fakePtr no longer contains a pointer to a delegate object created by vb for the FakeCallback function. Instead, fakePtr now contains a pointer to the delegate object created by vb for the MouseProc function.
Assuming my assumptions above are correct, I imagine the flow of code execution by VB will now be a 3 step process as follows:
Delegate of FakeCallback ----> Delegate of MouseProc -----> Actual MouseProc function
If one thing is certain is that AddressOf does not return the address of the method. Let's call this thing a delegate entity rather than a delegate object - probably should have said that since the start.
There is one good reason why I think we are definitely not swapping the whole delegate entity. If we were to swap the whole thing then surely nothing would change and the crash would still occur as if we did not swap at all. What this means is that those 52 bytes preceding the address we swap as well as the following 28 bytes (52 + 8+ 28) really do play a role because otherwise the crash would not get fixed.
So, what is this 88 byte entity? I can only think of the following:
1) it's a custom type structure
2) it's some sort of a manager object which is clearly not COM compatible
Regardless if 1) or 2) above is the actual implementation, at the 52 bytes offset we could have one of the following:
- function pointers OR
- actual PCode or assembly OR
-the address of an object being delegated with calling back
I obviously do now know which one it is or if something else but it's clear that the stuff we are swapping is unrelated with the method's signature.
Having said all that, I still don't see the logic as to why\how just delegating the call to an intermediary fake function actually fixes the callback stack parameters issue.
Without being able to prove it, I think I am swapping the address of the method while retaining the method signature which then somehow forces the intermediate entity to clean the stack itself.
- Finally, I see you breakdown the 52 offset value as ('PTR_SIZE * 6 + 4 = 52 on x64) what' exacltly does the 6 represent ? and the added 4 ? is that somewhat related to the vtable entries if we are talking about a propper object created by VB* ? but that again woudn't match with the 3 or 7 vtable entries.
That was a quick copy paste from a test code dealing with Timers. The posted code in the Mouse Scroll repo uses 52 offset directly.
I initially wrote the code for x32 as well and I was still thinking that the offset is a multiple of pointer positions (as in a vtable) but then I ditched the whole idea as I really did not need the fix for x32, only x64. I simply forgot to replace that for the Timers example which was only intended to explain the issue and how the fix works - please ignore.
Finally, this is how the 88 bytes look when compared using the addresses returned by AddressOf for 2 methods in the same module:
These are all 4 bytes values (Long). You can see that the pointers we are swapping are at bytes 52 to 60. All the other bytes are different with the exception of bytes 20 to 24. That could be a 4 byte flag or another 8 byte pointer between bytes 20 and 28 which just happen to point to close addresses (i.e. the high Long is the same while the low Long is different). Swapping those does not seem to do anything.
I realize this won't answer your questions but this is all I know so far about this thing. Cheers!