Quick question - I've just been testing overwriting methods of a class by changing entries in its VTable using low level copy memory api.
Background
I've had some success, and can swap 2 entries in the VTable of a class if they have the same signature. So a class definition like this:
Option Explicit
Public Sub Meow()
Debug.Print "Meow"
End Sub
Public Sub Woof()
Debug.Print "Woof"
End Sub
... generates a VTable like this:
... and I can swap the entries at positions 7 and 8 to make cls.Meow
print Woof
and vice-versa. I can also swap the entry from the VTable of one class with the VTable of an entirely different one (provided I don't try to dereference the implicit this
pointer by calling Me.anything
)
So I can make another class
Option Explicit
Public Sub Tweet()
Debug.Print "Tweet"
End Sub
and swap the behaviour of Woof
from one with Tweet
from the other. Not too complicated, I can share the code if people need it.
What I can't do...
... however, is figure out how to swap a class method with a method from a standard module?
Based on this article, it appears that the COM machinery which VBA is built on requires 2 things of class methods which VBA hides:
- They have an implicit
this
pointer - They return an HRESULT (
typedef long
)
So I thought
Public Sub Meow()
in a class module Class1
is equivalent to
Public Function Meow(ByVal this As LongPtr) As Long
I've also tried
Public Function Meow(ByRef meObj As Class1) As Long
Public Function Meow(ByRef meObj As Class1) As LongPtr 'but HResult is 32 bit int
Public Sub Meow(ByVal this As LongPtr)
etc. But VBA always crashes when I try to invoke the method from the VTable. So I'm at a bit of a loss. I wonder if things are different on a 64 bit computer, or if the standard module functions do something weird to the calling stack. The thing is I've seen examples of code where the entire VTable is assembled from standard module functions, so I know it's possible but just not sure how to convert the signatures correctly
How can I overwrite a VTable entry with a method defined in a standard module?