teadrinker wrote: ↑12 May 2019, 13:17
Formally, this value is a number, but AHK stores this value in memory as a string, and you can easily verify this:
As people are referring to this topic, I will point out that this is
technically correct, but misleading.
When you assign the result of a bitwise operator to a variable, AutoHotkey in fact stores
a 64-bit integer. When you access the variable with
&var or NumGet, or pass it to a command like MsgBox, a numeric string is computed and cached in the variable. Any subsequent access which needs a string will refer to this string, not the original number, which is also retained.
&var and NumGet will only let you examine the string, for backward-compatibility reasons. Using
Ord() does not prove anything, because Ord expects a string, and will attempt to convert whatever value you give it to a string in order to carry out its purpose.
For more details, see
Concepts - Caching.
This is a little different in v2, where the caching behaviour has been changed to preserve the original type of the value,
&var has been replaced with
StrPtr(var), and NumGet doesn't refer to a variable's (string) content directly.
If you pass the result of
(400 & 0xFFFFFFFF) | (500 << 32) directly to an
int64 parameter for WindowFromPoint, it will
not be converted to (or stored as) a string.
As for
passing POINT by value;
The target function doesn't know where the value came from; it only has the raw binary content of the stack or register. So for an 8-byte struct, if you compose a 64-bit integer which has the right raw binary value, it is sufficient to pass this number as "int64" because DllCall takes care of the details of passing an 8-byte value. Bitwise operators aren't the only way; you could prepare the struct with NumPut, then use
NumGet(struct, "int64") to get the value to pass to DllCall.
For 32-bit, int64 parameters are pushed onto the stack, occupying 8 bytes instead of the usual 4 bytes per parameter. For 64-bit, passing int64 is essentially the same, but all smaller parameters are widened to 64-bit, and the first four parameters are copied into registers as well.
Passing the x and y coordinates as individual int parameters works for 32-bit because they are simply pushed onto the stack, right to left, 4 bytes at a time. This would not work with smaller types, because each parameter would be widened to 32-bit. It also would not work for x64 because each parameter (int) would be widened to 64-bit.
For larger structs, there's no simple way to target both 32-bit and 64-bit with a single DllCall expression, because DllCall doesn't support passing values larger than int64. You would need to break the struct into individual int64 or int/uint parameters on 32-bit, and pass a single ptr on 64-bit. Fortunately, functions which take structs larger than 8 bytes by value are fairly rare.
Structs and unions of size 8, 16, 32, or 64 bits, and __m64 types, are passed as if they were integers of the same size. Structs or unions of other sizes are passed as a pointer to memory allocated by the caller.
Source:
x64 calling convention | Microsoft Docs
(There are other 32-bit and 64-bit platforms where some of the above may not apply; I'm referring only to the x86 and x86-64 platforms where AutoHotkey runs. I have no idea about ARM64...)