DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

13 Nov 2017, 11:12

Following on from a discussion here:
DLLCall assistance please for UUP direct apply project - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=39845

And ultimately clearing up some issues from a while ago, here:
GUI COMMANDS: COMPLETE RETHINK - Page 2 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 95#p138495

I'm providing some examples re. DllCall and IntP/UIntP (aka Int*/UInt*) etc, which I believe to be correct.

When using DllCall, sometimes the call requires a pointer to an Int/Int64 etc, you can use VarSetCapacity and NumGet/NumPut to create a variable and read/write from it, but often you can use a shorthand that is much simpler to use.

Using UIntP as an example, sometimes you want to receive data, in which case you need a variable, sometimes you want to send data, in which case can specify a variable or a put a hardcoded number directly into the DllCall line. If you want to both send and receive data using the same UInt, you need a variable.

Some examples:

Code: Select all

;UIntP: receive values
q:: ;Edit control - get text selection start/end points
ControlGet, hCtl, Hwnd,, Edit1, A
DllCall("user32\SendMessage", Ptr,hCtl, UInt,0xB0, UIntP,vPos1, UIntP,vPos2, Ptr) ;EM_GETSEL := 0xB0
MsgBox, % vPos1 " " vPos2
return

;UIntP: receive values (longer alternative)
w:: ;Edit control - get text selection start/end points
ControlGet, hCtl, Hwnd,, Edit1, A
VarSetCapacity(vPos1, 4, 0)
VarSetCapacity(vPos2, 4, 0)
DllCall("user32\SendMessage", Ptr,hCtl, UInt,0xB0, Ptr,&vPos1, Ptr,&vPos2, Ptr) ;EM_GETSEL := 0xB0
vPos1 := NumGet(&vPos1, 0, "UInt")
vPos2 := NumGet(&vPos2, 0, "UInt")
MsgBox, % vPos1 " " vPos2
return

;Int64P: receive values
e:: ;get high-precision duration of event
DllCall("QueryPerformanceFrequency", Int64P,vQPF)
DllCall("QueryPerformanceCounter", Int64P,vQPC1)
Sleep, 1000
DllCall("QueryPerformanceCounter", Int64P,vQPC2)
MsgBox, % (((vQPC2-vQPC1)/vQPF)*1000)
return

;==================================================

;UIntP: send/receive values using the same variable
r:: ;get A_ComputerName/A_UserName manually
;A_ComputerName
;MAX_COMPUTERNAME_LENGTH := 31
VarSetCapacity(vComputerName, 32*2)
vSize := 32
DllCall("kernel32\GetComputerName", Str,vComputerName, UIntP,vSize)
MsgBox, % vSize " " vComputerName

;A_UserName
;UNLEN := 256
VarSetCapacity(vUserName, 257*2)
vSize := 257
DllCall("advapi32\GetUserName", Str,vUserName, UIntP,vSize)
MsgBox, % vSize " " vUserName
return

;UIntP: send/receive values using the same variable (longer alternative)
t:: ;get A_ComputerName/A_UserName manually
;A_ComputerName
;MAX_COMPUTERNAME_LENGTH := 31
VarSetCapacity(vComputerName, 32*2)
VarSetCapacity(vSize, 4)
NumPut(32, &vSize, 0, "UInt")
DllCall("kernel32\GetComputerName", Str,vComputerName, Ptr,&vSize)
vSize := NumGet(&vSize, 0, "UInt")
MsgBox, % vSize " " vComputerName

;A_UserName
;UNLEN := 256
VarSetCapacity(vUserName, 257*2)
VarSetCapacity(vSize, 4)
NumPut(257, &vSize, 0, "UInt")
DllCall("advapi32\GetUserName", Str,vUserName, Ptr,&vSize)
vSize := NumGet(&vSize, 0, "UInt")
MsgBox, % vSize " " vUserName
return

;==================================================

;UIntP: send values
y:: ;date local to date UTC
vDate := A_Now
vDate -= 1601, Seconds
vIntervals1 := vDate*10000000
DllCall("kernel32\LocalFileTimeToFileTime", Int64P,vIntervals1, Int64P,vIntervals2)
vDate := 1601
vDate += % vIntervals2//10000000, Seconds
FormatTime, vDate, % vDate, yyyy-MM-dd HH:mm:ss
MsgBox, % vDate
return

;UIntP: send values (hard-coded)
u:: ;date local to date UTC
vDate := 2000
vDate -= 1601, Seconds
vIntervals1 := vDate*10000000
MsgBox, % vIntervals1

DllCall("kernel32\LocalFileTimeToFileTime", Int64P,125911584000000000, Int64P,vIntervals2)
vDate := 1601
vDate += % vIntervals2//10000000, Seconds
FormatTime, vDate, % vDate, yyyy-MM-dd HH:mm:ss
MsgBox, % vDate
return

;==================================================
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

31 Jan 2019, 09:16

Is either one of these preferable for some reason? E.g. better performance, e.g. style. Which would you use?

Code: Select all

if A_Is64bitOS && !(A_PtrSize = 8)
	DllCall("kernel32\Wow64DisableWow64FsRedirection", Ptr,0)
if A_Is64bitOS && !(A_PtrSize = 8)
	DllCall("kernel32\Wow64DisableWow64FsRedirection", PtrP,0)
Btw Wow64RevertWow64FsRedirection wants a PVOID (a Ptr), so on that basis I expect PtrP.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4704
Joined: 17 Jul 2016, 01:02
Contact:

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

31 Jan 2019, 09:39

from the function documentation I don't see how ptr, 0 is even valid. The parameter is PVOID*, i.e., void**.
swagfag
Posts: 6219
Joined: 11 Jan 2017, 17:59

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

31 Jan 2019, 09:40

neither

Code: Select all

DllCall("kernel32\Wow64DisableWow64FsRedirection", "Ptr*", 0)
i dont understand why "P" and unquoted arg types made the cut in v2
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

31 Jan 2019, 10:07

- @Helgef: Could you explain why that would be invalid? Is it not true to say that: by specifying Ptr,0, you're passing a null, equivalent to PtrP,0. Also, is not true to say that: PtrP/IntP etc aren't even needed, they add convenience, but you can always use Ptr.
- @swagfag: Ptr/PtrP et al could be reserved variables like A_ variables in AHK v2.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4704
Joined: 17 Jul 2016, 01:02
Contact:

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

31 Jan 2019, 10:31

Could you explain why that would be invalid?
The function expects an address
Wow64DisableWow64FsRedirection wrote:Parameters
OldValue [out]
The WOW64 file system redirection value. The system uses this parameter to store information necessary to revert (re-enable) file system redirection.
It doesn't say this parameter can be NULL.
Ptr,0, you're passing a null, equivalent to PtrP,0
They are not equivalent. PtrP, 0 doesn't pass 0 to the function, it passes an address to a a_ptrsize:ed value, in this case the value is 0.

Cheers.

Edit: Yes, you can always use ptr.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

31 Jan 2019, 10:48

- Many thanks Helgef.
- The form PtrP,var makes sense, it creates/updates a variable with a value. But I couldn't see any mention of the following in the documentation (I could have missed it): PtrP,0 or PtrP,123 etc. If that has the effect of safely creating and immediately deleting a temporary variable, it would be useful if that was stated somewhere. (A candidate for the 'Suggestions on documentation improvements' thread.) Otherwise that would be doing something undocumented, with no guarantee of safety/success.
- Otherwise Ptr,&A_SafeDump might be useful, as somewhere to dump the value if we don't want it. (Where the size of A_SafeDump is at least 8 bytes.)

- So Ptr,0 can be unsafe (although if so, why have I never experienced a crash) and PtrP,0 is undocumented (unless I missed it in the documentation) and anything undocumented could be unsafe. Cheers.
Last edited by jeeswg on 31 Jan 2019, 11:26, edited 2 times in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4704
Joined: 17 Jul 2016, 01:02
Contact:

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

31 Jan 2019, 11:15

For the most part I don't understand your above post.
What I mentioned is documented, and hard to miss,
Append an asterisk (with optional preceding space) to any of the above types to cause the address of the argument to be passed rather than the value itself
Dllcall is unsafe in general, especially if you don't know what you're doing.

Cheers.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

31 Jan 2019, 11:20

- Yes, and that makes sense for PtrP,var.
- But what about: PtrP,0 or PtrP,123? Since '0' and '123' aren't variables and don't have addresses. Is it safe to pass '0' or '123'? Thanks.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

09 Mar 2019, 19:36

- I mention the 'Ptr,0' and 'PtrP,0' issue, here:
Suggestions on documentation improvements - Page 26 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=13&t=1434&p=262959#p262959
- I sum it up like this:
- 'Ptr,0', is the memory at address 0 write-protected, or is a crash possible?
- 'PtrP,0', does this write to the variable called '0', does it write to and then discard a temporary variable? What happens?
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4704
Joined: 17 Jul 2016, 01:02
Contact:

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

10 Mar 2019, 03:49

- 'PtrP,0' What happens?
I already answered this, and the documentation did too,
helgef wrote:PtrP, 0 doesn't pass 0 to the function, it passes an address to a a_ptrsize:ed value, in this case the value is 0.
docs wrote:Append an asterisk (with optional preceding space) to any of the above types to cause the address of the argument to be passed rather than the value itself

- 'Ptr,0', is the memory at address 0 write-protected, or is a crash possible?
ptr, 0 passes an a_ptrsize:ed integer to the function, in this case the integer 0. What the function does with it is outside of the callers control. Passing an address to a write-protected memory block doesn't generally imply some kind of safety.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

10 Mar 2019, 04:06

- Thanks Helgef, you've reminded me of some of the possibilities I wasn't directly considering. Much appreciated.
- It is pretty fiddly, here is a summary:

- PtrP,myvar will pass &myvar (the address of myvar)
- PtrP,myvalue will create a variable (behind-the-scenes, that we don't have direct access to, and that we won't know the address of) e.g. newvar, its value will be myvalue, it will pass &newvar (the address of newvar)

- Ptr,0 will pass the value 0
- in some situations the function expects a value, it sees 0 as a value (this is fine)
- in some situations the function expects an address, it sees 0 and does nothing (e.g. the MSDN page will state this, that 0 i.e. NULL is handled differently)
- in some situations the function expects an address, sees 0 and tries to write to address 0, and so the question is, does AHK protect bytes 0-7 from being written to

- If the summary can be further improved, do make any suggestions. Thanks.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
nnnik
Posts: 4499
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

10 Mar 2019, 04:27

does AHK protect bytes 0-7 from being written to
AHK has no control over that - it's the systems job.
Recommends AHK Studio
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

10 Mar 2019, 04:31

OK, but can't a process ordinarily protect parts of its address space from being written to, e.g. via VirtualProtect, or are some parts exempt from being protected like that?
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4704
Joined: 17 Jul 2016, 01:02
Contact:

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

10 Mar 2019, 06:26

The very short part of the documentation covering the * or p suffix already summarise the behaviour correctly, and explicitly states,
Since variables in AutoHotkey have no fixed type, the address passed to the function points to temporary memory rather than the variable itself.
I do not understand what write-protected memory has to do with this topic. If you pass invalid values to a function you have no guarantees.

Cheers.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

10 Mar 2019, 06:49

- Sometimes the user will do something they shouldn't do. E.g. they thought that 0 would be treated as NULL rather than as a valid address. Some Winapi functions protect you (treat 0 as NULL), some don't (treat 0 as a valid address).
- You shouldn't always protect the user from themselves, but AutoHotkey is generally good at protecting the user when it can.
- The question is whether AutoHotkey can protect, or tries to protect, the user. Or, perhaps the system already protects the user in some way.
- I would mention this 'pointer to address 0' issue in the documentation, and in a tutorial. Cheers.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
nnnik
Posts: 4499
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

10 Mar 2019, 08:03

Thats something AutoHotkey cannot do - it's a windows thing.
Recommends AHK Studio
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

10 Mar 2019, 08:37

- Do you have any sources? I haven't found anything good online so far.
- In this example, I try to read from/write to address 1, which fails, and to a variable, which succeeds. Why does the address 1 attempt fail?

Code: Select all

q:: ;attempt to write at address 1 and to variable
DllCall("kernel32\SetLastError", UInt,0)
NumPut(1234, 1+0, 0, "UInt")
vErrorLevel := ErrorLevel
MsgBox, % A_LastError "`r`n" vErrorLevel ;0 0

DllCall("kernel32\SetLastError", UInt,0)
vNum := NumGet(1+0, 0, "UInt")
vErrorLevel := ErrorLevel
MsgBox, % vNum "`r`n" A_LastError "`r`n" vErrorLevel ;0 0

VarSetCapacity(vData, 4)

DllCall("kernel32\SetLastError", UInt,0)
NumPut(1234, &vData, 0, "UInt")
vErrorLevel := ErrorLevel
MsgBox, % A_LastError "`r`n" vErrorLevel ;1234 0 0

DllCall("kernel32\SetLastError", UInt,0)
vNum := NumGet(&vData, 0, "UInt")
vErrorLevel := ErrorLevel
MsgBox, % vNum "`r`n" A_LastError "`r`n" vErrorLevel ;0 0
return
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4704
Joined: 17 Jul 2016, 01:02
Contact:

Re: DllCall: IntP/UIntP, Int64P/UInt64P, PtrP/UPtrP

10 Mar 2019, 08:46

NumPut/Get doesn't set errorlevel,
numput wrote:If the target address is invalid, an empty string is returned. However, some invalid addresses cannot be detected as such and may cause unpredictable behaviour.
How AHK detects invalid addresses isn't documented. Iirc it deems addresses in the range 0...0xffff invalid as these are reserved by the system. v2 will throw an exception.

You should never attempt to read from, or write to, any random memory location.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Bing [Bot], iguru42, Spawnova and 39 guests