Page 1 of 1

script does not work in 64 bit AHK

Posted: 25 Aug 2017, 02:39
by need4speed
sorry if this ain't be a bug, but I don't see why this is should not work in the 64 bit Version.

to reproduce insert a long text in WordPad. the vertical scroll bar appears, after running the script WheelUP/Down are inverted in AutoHotkeyA32.exe & AutoHotkeyU32.exe. In AutoHotkeyU64.exe WheelUP/Down does not longer work.

Code: Select all

#NoTrayIcon
#SingleInstance, force
#MaxHotkeysPerInterval 250
SetTitleMatchMode, 2
CoordMode, Mouse, Screen

#If MouseIsOver("WordPad")
WheelUp::
	MouseGetPos, m_x, m_y
	hw_m_target := DllCall( "WindowFromPoint", "int", m_x, "int", m_y )
	SendMessage, 0x20A, -120 << 16, ( m_y << 16 )|m_x,, ahk_id %hw_m_target%
return

WheelDown::
	MouseGetPos, m_x, m_y
	hw_m_target := DllCall( "WindowFromPoint", "int", m_x, "int", m_y )
	SendMessage, 0x20A, 120 << 16, ( m_y << 16 )|m_x,, ahk_id %hw_m_target%
return
#If

MouseIsOver(WinTitle) {
    MouseGetPos,,, Win
    return WinExist(WinTitle . " ahk_id " . Win)
}

Re: script does not work in 64 bit AHK

Posted: 25 Aug 2017, 09:42
by just me
WindowFromPoint() has only one parameter, a POINT structure of 8 bytes. With AHK32 you have to split the structure into two parameters of 4 bytes ("Int", ..., "Int", .... With AHK64 you have to pass the 8 bytes as one parameter ("Int64", ....

Also, the defaullt return type of DllCall() is Int (4 bytes). The function you are calling returns a window handle (HWND) of type Ptr, which is 4 bytes for AHK32 and 8 bytes for AHK64 on Win x64. Without specifying the return type Ptr you will only get the lower 4 bytes of a 8 bytes handle.

This isn't a bug!

Re: script does not work in 64 bit AHK

Posted: 25 Aug 2017, 10:16
by wolf_II
Try also without DllCall:

Code: Select all

#If MouseIsOver("WordPad")
WheelUp::
    MouseGetPos, m_x, m_y,, Ctrl
    ControlGet, hCtrl, Hwnd,, %Ctrl%, A
    SendMessage, 0x20A, -120 << 16, ( m_y << 16 )|m_x,, ahk_id %hCtrl%
return

WheelDown::
    MouseGetPos, m_x, m_y,, Ctrl
    ControlGet, hCtrl, Hwnd,, %Ctrl%, A
    SendMessage, 0x20A, 120 << 16, ( m_y << 16 )|m_x,, ahk_id %hCtrl%
return
#If
I hope that helps.

Re: script does not work in 64 bit AHK

Posted: 25 Aug 2017, 11:54
by jeeswg
Note: you should do something like this:
(vPosX & 0xFFFF)|(vPosY<<16)
(vPosX & 0xFFFFFFFF)|(vPosY<<32)
notice the use of &, to make sure that negative as well as positive values can be handled.

I did various experiments re. this which I will publish in my mathematics tutorial.

Using similar logic to this:

Code: Select all

q::
VarSetCapacity(vData, 8, 0)
NumPut(-2, vData, 0, "Int")
NumPut(-2, vData, 4, "Int")
MsgBox, % NumGet(vData, 0, "Int")
MsgBox, % NumGet(vData, 4, "Int")
MsgBox, % Format("0x{:X}", NumGet(vData, 0, "Int64")) ;0xFFFFFFFEFFFFFFFE
MsgBox, % Format("0x{:X}", (-2 & 0xFFFFFFFF)|(-2 << 32)) ;0xFFFFFFFEFFFFFFFE
MsgBox, % Format("0x{:X}", (-2)|(-2 << 32)) ;incorrect: 0xFFFFFFFFFFFFFFFE
return
@just me: Why can't you use two Ints in x64? I'm trying to figure it out ...
INT INT
INT64
Both take up 8 bytes and don't require any padding. Am I missing something?
I would have thought that both methods would work in both x32 and x64.

Re: script does not work in 64 bit AHK

Posted: 25 Aug 2017, 15:29
by need4speed
I used "my" script without actually understanding it.
Thank you all for the code and explanations.

Re: script does not work in 64 bit AHK

Posted: 25 Aug 2017, 15:50
by just me
Hi jeeswg,

I have to correct myself a bit. All function parameters on x86 (32-bit) are passed using the stack. So it makes no difference whether you pass one Int64 or two Ints for a POINT structure.. Both will put 8 bytes onto the stack and the called function will fetch exactly this 8 bytes.

On x64 (64-bit) the first four parameters are passed using registers. The stack is only used for additional parameters. So you must pass the POINT structure which is the first parameter as one parameter.

Source: Overview of x64 Calling Conventions

Re: script does not work in 64 bit AHK

Posted: 25 Aug 2017, 16:44
by jeeswg
@need4speed: So it looks like this would work for your script:

Code: Select all

hw_m_target := DllCall( "WindowFromPoint", "int64", ( m_y << 32 )|( m_x & 0xFFFFFFFF ), "ptr" )
I might write it slightly differently like this:

Code: Select all

hw_m_target := DllCall("WindowFromPoint", "int64",(m_x&0xFFFFFFFF)|(m_y<<32), "ptr")
;or:
hWnd := DllCall("WindowFromPoint", Int64,(vPosX&0xFFFFFFFF)|(vPosY<<32), Ptr)
[EDIT:] I tested the script and it worked, although I was concerned that &0xFFFFFFF, might not work, if AHK tried to interpret &0xFFFFFFF by attempting to retrieve the address of a variable called '0xFFFFFFFF'. I.e. so in theory putting spaces around the '&' might be safer.
==================================================

@just me:
Thanks so much just me, I finally have some understanding why there is a difference.

This affects my script:
DllCall converter/cleaner (e.g. x32 to x64/x32 two-way compatible) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=31365
it suggests that all scripts, for x64/x32 compatibility, should aim to have the same number of parameters as the definition specifies, and not split them up.

Btw you noticed a lot of flaws with that initial script, in case there any more. I didn't think the script was necessarily perfect at the time, but there were more issues than expected.

==================================================

I don't 100% understand what they're talking about here, although I can sort of follow, in case there is anywhere that explains this better.

Overview of x64 Calling Conventions
https://msdn.microsoft.com/en-us/library/ms235286.aspx
The __fastcall convention uses registers for the first four arguments and the stack frame to pass additional arguments.
Parameter Passing
https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx