Trouble understanding callback function's args by address

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
Meow
Posts: 24
Joined: 21 Feb 2016, 22:48

Trouble understanding callback function's args by address

12 Apr 2019, 01:54

So here's what the docs have to offer about it:
https://autohotkey.com/docs/commands/RegisterCallback.htm#Indirect
I don't understand why would would add or subtract A_PtrSize from the args.
What does this do?
Also, adding +0 is just for ensuring that it's purely numeric, and not a numeric string, right?
Also, why in this example the ParamCount parameter is set to 3, even though only 2 arguments are passed though?

Here is an other example of a cool systemwide hook script I found with a Google search:

Code: Select all

#Persistent
mh:=new mouseHook("h")
mh.hook()
h(h,x,y){
	ToolTip, % "Mouse moved at " x A_Space y 
}
class mouseHook{
	; User methods
	hook(){
		if !this.hHook												; WH_MOUSE_LL := 14									  hMod:=0	 dwThreadId:=0
			this.hHook:=DllCall("User32.dll\SetWindowsHookEx", "Int", 14, "Ptr", this.regCallBack:=RegisterCallback(this.LowLevelMouseProc,"",4, &this), "Uint", 0, "Uint", 0, "Ptr")
		return
	}
	unHook(){
		if this.hHook
			DllCall("User32.dll\UnhookWindowsHookEx", "Uint", this.hHook)
		return this.hHook:=""
	}
	; Internal methods.
	__new(callbackFunc){
		(this.callbackFunc:= isObject(callbackFunc)  ? callbackFunc : isFunc(callbackFunc) ? func(callbackFunc) : "")
		if !this.callbackFunc
			throw exception("invalid callbackFunc")
	}
	LowLevelMouseProc(args*) {  
		; (nCode, wParam, lParam)
		Critical
		this:=Object(A_EventInfo)
		nCode:=NumGet(args-A_PtrSize,"Int")
		wParam:=NumGet(args+0,0,"Ptr")
		lParam:=NumGet(args+0,A_PtrSize,"UPtr") 
		x:=NumGet(lParam+0,0,"Int")
		y:=NumGet(lParam+0,4,"Int")
		flags:=NumGet(lParam+0,12,"UInt")
		this.callbackFunc.Call(flags,x,y)
		
		return DllCall("User32.dll\CallNextHookEx","Uint",0, "Int", nCode,"Uptr", wParam,"Ptr",lParam)
	}
	__Delete(){  
		this.unHook()
		if this.regCallBack
			DllCall("GlobalFree", "Ptr", this.regCallBack)
		return 
	}
}
esc::exitapp
In the callback function, we're getting the nCode, but I don't understand what is being done.
With what logic is wParam at offset 0 and lParam at offset 4 or 8? And why are we subtracting A_PtrSize from the arg when getting the nCode?


Why is for example this not correct?

Code: Select all

;using WH_MOUSE_LL the args we get are:

;                    32bit OS     64bit OS
;int    nCode        0            0
;WPARAM wParam       4            8
;LPARAM lParam       8            16


nCode := NumGet(args+0, 0, "Int")
wParam := NumGet(args+0, A_PtrSize, "Ptr")
lParam := NumGet(args+0, 2*A_PtrSize, "UPtr")

Any help would be appreciated,
Thanks.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Trouble understanding callback function's args by address

12 Apr 2019, 08:43

Adding +0 makes AHK treat var like a pointer and prevents AHK from interpreting said variable as a byref variable and numget the binary contents of its string buffer.

The example seems to be written for AHK 32 bit. The DllCall passes along a float and a 64 bit integer bringing the total size of parameter to float = 32 + int64 = 64 which is 96.
96 bits equals 3 32 bit parameters.

As the documentation states:
If the function is declared as variadic, its final parameter is assigned the address of the first callback parameter which was not assigned to a script parameter.
That means the address in args points to the n-th parameter with args being the n-th parameter in the function definition.
All methods have a hidden parameter named this - that means that args actually is the second parameter and not the first.
Which is also the reason why it points to the second parameter passed along: Which appears to point to wParam.
Recommends AHK Studio
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Trouble understanding callback function's args by address

12 Apr 2019, 15:15

If the function is declared as variadic, its final parameter is assigned the address of the first callback parameter which was not assigned to a script parameter.
hmmm this doc entry is not very clear at all. without ur clarification it can only be grasped in retrospect and/or after thinking about it for way too long and way too hard

the signature of LowLevelMouseProc(args*) expands to LowLevelMouseProc(this, args*). since u arent doing a method call(ie MyObj.myMethod()), but rather the DllCall calls LowLevelMouseProc() as a normal function, nCode is assigned to this and args(because it was declared as variadic) becomes a plain variable and gets assigned the address of the first DllCall callback parameter, which couldnt be assigned to a normal function parameter. since nCode was successfully assigned to the only normal function parameter(ie this in llmp(this, args*)), the next parameter that follows(wParam) will have to be assigned to the variadic args*

in conclusion, the author could have done nCode := this at the very start instead of -APtrSize but then ud be asking where this came from and why it doesnt refer to the mousehook instance. all around tricky stuff
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Trouble understanding callback function's args by address

12 Apr 2019, 15:57

And the upper bits might not be set correctly.
Recommends AHK Studio
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Trouble understanding callback function's args by address

13 Apr 2019, 07:27

Hi.

The reasoning behind doing ncode := numget() instead of ncode := this would be mostly because of,
the upper bits might not be set correctly.
although this doesn't matter in this particular code, since ncode is just passed on as "int" in the next dllcall.

Anyways, I would probably not recommend numget(p-a_ptrsize), because strictly speaking, there is actually no guarantee that this would be valid. On the other hand, other than the documentation example, there is no suggestion numget(p+a_ptrsize) would be valid either :terms:.

If you want to use a method as callback function, you can use :arrow: callbackcreate.

Cheers.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Trouble understanding callback function's args by address

13 Apr 2019, 07:55

i dont understand what ure both talking about. which upper bits might not be set correctly and why wouldnt they be?
also why wouldnt p ± a_ptrsize be valid?
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Trouble understanding callback function's args by address

13 Apr 2019, 08:00

which upper bits might not be set correctly and why wouldnt they be?
AutoHotkey 32-bit/64-bit: If an incoming parameter is intended to be 8-bit or 16-bit (or 32-bit on x64), the upper bits of the value might contain "garbage" which can be filtered out by using bitwise-and, as in the following examples:

why wouldnt p ± a_ptrsize be valid?
its final parameter is assigned the address of the first callback parameter which was not assigned to a script parameter.
It doesn't say anything about what lies adjacent to this address, the example shows that at least one parameter follows. Examples should be examples, not documentation.

Cheers.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Trouble understanding callback function's args by address

13 Apr 2019, 08:40

oh... i didnt read that part. sorry
i cant imagine a situation where that wont be the case. from script2.cpp:

Code: Select all

16868: for (i = 0; i < j; ++i)  // For each formal parameter that has a matching actual.
16869: 	func.mParam[i].var->Assign((UINT_PTR)params[i]); // All parameters are passed "by value" because an earlier stage ensured there are no ByRef parameters.
16870: if (func.mIsVariadic)
16871: 	// See the performance note further above.  Rather than having the "variadic" param remain empty,
16872: 	// pass it a pointer to the first actual parameter which wasn't assigned to a formal parameter:
16873: 	func.mParam[func.mParamCount].var->Assign((UINT_PTR)(params + i));
maybe it should be documented then

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Decar, doodles333, mikeyww and 213 guests