Possible improvements #3
Replies: 3 comments 5 replies
-
|
By the way, More correct would be something like: #If Win64 Then
Private Sub WritePtrNatively(ByRef ptrs() As LONG_PTR, ByVal ptr As LongPtr)
#Else
Private Sub WritePtrNatively(ByRef ptrs() As VbVarType, ByVal ptr As LongPtr)
#End If
ptrs(0) = ptr
End Subwhich would also remove the need to declare |
Beta Was this translation helpful? Give feedback.
-
|
Hi Cristian, thank you for taking the time to look this over and provide feedback! Just briefly, regarding the bulky constant declarations, I completely agree. I invite you to take a look at an even simpler init method I uploaded here: [https://github.com/WNKLER/RefTypes/blob/main/RefTypes_stdole.bas] Technically, this method depends on stdole, however the project already assumes a reference to stdole in order to support RefUnk. |
Beta Was this translation helpful? Give feedback.
-
|
FYI, I uploaded a new demo: It uses a new technique that overcomes some of the limitations/drawbacks of current solutions.
The caveat being that it only works for VBA and p-code applications. (at least, as currently implemented) |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hats off for finding this Ben! Thank you for sharing!
How it works
As you pointed out in your code comments, VBA can be tricked to interpret an array of UDTs as if it were an array of something else.
Quick example, the following is perfectly legal code:
The array element interpretation type, besides
VbVarType, can be any customEnumdefined in native VBA, or any typedef defined in any of the loaded libraries, as you already wrote.VbVarTypeis defined in VBE7.dll.The nice thing about the following definition in VBE7.dll internal type library, is that it allows an 8-Byte type:
and so code like the following allows us to write pointers:
So far, all of the above can also be achieved with calls to
LSetand custom UDTs.However, your method can also overwrite the underlying pointer of an uninitialized array with something like:
thus creating a fake array that we can then point wherever we want.
This is superior to other approaches like the following:
VariantCopyRtlMoveMemory/memmoveAPI callbecause it uses no dependency.
Suggested improvements
The current approach in 07e9b0d makes use of the same mechanism I described above. It initializes a bunch of fake arrays that can then read / write memory remotely.
However, it does one more thing - it manipulates offsets and array element sizes to write directly to variables declared at module level. This is very hard to follow even for advanced users. Plus it requires quite a lot of constants.
Improvements:
I would simplify to just initializing a single fake array of pointers. I would then use that fake array of pointers to initialize anything else needed without the burden of mantaining all that complex logic.
I would use a separate SAFEARRAY structure for each of the fake arrays. While VBA is single threaded, the Locals and Watch window can do asyncronous calls into VBA methods, and so while debugging, a call from one of these windows can change the current single SAFERRAY (e.g. calling
RefDbl) while VBA itself is trying to use the same SAFERRAY for something else (e.g. callingRefDate) leading to a crash of the app.I would also group the fake array with their corresponding SAFEARRAY into a separate custom structure - to keep related things together.
Without doing this for all of the data types you currently have, I would apply all of the above to something like the following:
I've only done just
IntegerandLongbut you get the idea - every single fake array (accesor) is isolated from the other ones and even points to a safe address after each method exits. This avoids any potential crashes with shared resources or accesing released memory.Looking forward to hear your thoughts.
Beta Was this translation helpful? Give feedback.
All reactions