The Curse of the Changing Controls Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

The Curse of the Changing Controls

13 Jan 2017, 15:58

Okay, boy am I beating my head against this one. >.>

I'm writing a script to interface with a program that has a fairly complicated GUI. A GUI that was, apparently, written by drunk monkeys. The main part of the GUI is a set of tabs to switch between different sections of the GUI. Each section has its own controls, and there are some controls up at the top that never change.

Now, here is the part that is pissing me off: The class of some of the controls changes based on how many of the tabs have been accessed in the current session. For example, one of the main controls at the top is TEdit15 when the program first opens. However, if I switch to the third tab, suddenly that control becomes TEdit17 - and stays at that number even when I switch back to first tab.

So far I've been using a hack - I figured out exactly what the changes were, tracked them in a variable, and refer to TEdit%variable% whenever I need that control. Unfortunately, it seems that other controls in the GUI also sometimes change their class in less predictable ways.

Is there any more accurate way to refer to a control than by class? I'm getting pretty frustrated with this... >.<
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: The Curse of the Changing Controls

13 Jan 2017, 16:32

Some techniques I use regarding controls:

ControlGet, hCtl, Hwnd, , Edit1, A

WinGet, vWinStyle, Edit1, A
WinGet, vWinExStyle, Edit1, A

hWndParent := DllCall("user32\GetAncestor", Ptr,hWnd, UInt,1, Ptr) ;GA_PARENT = 1
hWndOwner := DllCall("user32\GetWindow", Ptr,hWnd, UInt,4, Ptr) ;GW_OWNER = 4

hCtl is consistent whereas on a few programs ClassNN changes.
Sometimes you can distinguish different controls of the same class by their window styles/ExStyles, or by information about their parent windows (or siblings or children windows).

In this example I used a parent control, to identify the desired toolbar control in Internet Explorer:

Code: Select all

WinGet, hWnd, ID, ahk_class IEFrame
JEE_IntExpFindBarHide(hWnd)
Return

JEE_IntExpFindBarHide(hWnd)
{
ControlGet, hCtl, Hwnd, , FindBarClass1, ahk_id %hWnd%
if ErrorLevel
Return

;ToolbarWindow321 (the 1 is relative to FindBarClass, not IEFrame)
ControlClick, ToolbarWindow321, ahk_id %hCtl%
Return
}
In Internet Explorer, there are controls such as Internet Explorer_Server1, of the form 'Internet Explorer_ServerNN'. The ClassNN changes based on the most recently active tab.

Btw in Notepad, there is a control called 'Edit1'. Its class is 'Edit', and AutoHotkey adds the 1, as it is the first Edit control to be found when controls are enumerated.
Hence 'ClassNN'. 'Edit' or 'SysListView32' will make sense to programmers generally, but 'Edit1' or 'SysListView321' is an AutoHotkey thing.

You can do:

Code: Select all

ControlGet, hCtl, Hwnd, , Edit1, A
WinGetClass, vWinClass, ahk_id %hCtl%
MsgBox % vWinClass
Return
;it will return 'Edit', not 'Edit1'
(A lot of the 'Win' commands work on controls too such as WinGetPos.)
Last edited by jeeswg on 13 Jan 2017, 17:54, edited 1 time 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
MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Re: The Curse of the Changing Controls

13 Jan 2017, 16:56

Ah, I see, so the issue is with AutohotKey rather than the people who developed the GUI. They made foolish choices in so many other places that I just assumed it was another of theirs. :P

Sounds like the bit about HWNDs is exactly what I need. So (a little helpfile research later) if I use MouseGetPos to retrieve the HWND of a control, that will give me something to refer to it by that will never change?
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: The Curse of the Changing Controls

13 Jan 2017, 17:34

Yes, AutoHotkey's ClassNN method is very good, but sometimes it's not the best way, and ControlGet's Hwnd subcommand is the way to go.
Haha what else is wrong with the particular software you're using?

Yes:
MouseGetPos, vPosX, vPosY, hWnd, hCtl, 2
or
ControlGetFocus, vCtlClassNN, A
ControlGet, hCtl, Hwnd, , %vCtlClassNN%, A
can be good ways to proceed.
To my knowledge window hWnds, and control hWnds (or hCtls) always stay the same, for the lifetime of the window/control.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Re: The Curse of the Changing Controls

13 Jan 2017, 18:05

The "for the lifetime" thing is a bit of a problem, because it leaves me with a catch 22 - I have to find the control in the first place in order to grab the HWND of the control.

Basically I'm gonna have to loop a bit of code in the background that waits for the program to open and immediately grabs the relevant HWNDs before they can change. :)
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: The Curse of the Changing Controls

13 Jan 2017, 18:12

Haha once you know, you know, but you have to find out first.
Good luck.
Btw is there any predictability about the order.
Like if you click on a control what happens to its number.
Also, ControlGetPos might be useful.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Re: The Curse of the Changing Controls

16 Jan 2017, 10:21

There is predictability to the changes, but the big problem is if the script is restarted, or the program is restarted, in some odd order that messes up my ability to predict which numbers the controls have at that time.

The solution I came up with is hilariously janky, but totally works: since the controls never move their relative position in the window, when I need to figure out the HWNDs I use a series of MouseMove + MouseGetPos to quickly move the mouse to each control and grab its HWND, then back to original position. XD
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: The Curse of the Changing Controls

16 Jan 2017, 10:29

MaxAstro wrote:The solution I came up with is hilariously janky, but totally works: since the controls never move their relative position in the window, when I need to figure out the HWNDs I use a series of MouseMove + MouseGetPos to quickly move the mouse to each control and grab its HWND, then back to original position. XD
thats a good idea. sometimes stuff like that is necessary

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

Re: The Curse of the Changing Controls

16 Jan 2017, 13:23

Can you not use ControlGetPos or WinGetPos to get the controls' positions?
Also see AccViewer as a guide to things you might write using the Acc library,
that might help you establish which control is in which position.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Re: The Curse of the Changing Controls

17 Jan 2017, 16:28

Again, the issue with ControlGetPos is not having a reliable way to identify the control's ClassNN - if I had a foolproof way of determining that, I wouldn't need to be clever with MouseGetPos.

It doesn't look like AccViewer offers much different information than WindowSpy; what is the Acc library?
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: The Curse of the Changing Controls

17 Jan 2017, 16:58

Acc library has special functions that can interact with GUI windows,
controls and subelements (if that's the right word) of windows/controls.
AccViewer uses the Acc library functions and is far more powerful than
AU3_Spy.exe (Active Window Info) (Window Spy).
Also note that AccViewer has a 'show more' button.

Presumably if you're clicking on the controls with the mouse,
to grab control hWnds, they have different positions,
and if they have different positions, you can refer to each control
by it's position, and then get it's hWnd.
Where have I faltered logically?

e.g.

Code: Select all

;q::
WinGet, hWnd, ID, A
vClass := "Edit"
Loop, 100
{
ControlGet, hCtl, Hwnd, , % vClass A_Index, ahk_id %hWnd%
if !hCtl
break
ControlGetPos, vPosX, vPosY, vPosW, vPosH, % vClass A_Index, ahk_id %hWnd%
vOutput .= vPosY "`t" hCtl "`r`n"
}
Clipboard := vOutput
MsgBox % "done"
Return
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Re: The Curse of the Changing Controls

17 Jan 2017, 17:04

Oh duh, I was thinking of ControlGetPos backwards - I thought it returned the position of a control, not returned the control at a position.

Yeah, that is smarter, and avoids flickering the mouse. Thank you, that is great! :)

EDIT: No wait, it looks like ControlGetPos does return the position of a control. Is there a syntax to use it the other way around?
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: The Curse of the Changing Controls

17 Jan 2017, 18:03

Put Acc.ahk in your Lib folder
and try this:

Acc library (MSAA) and AccViewer download links - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=26201

Code: Select all

q::
vPosX := 100, vPosY := 100
oAcc := Acc_ObjectFromPoint("", vPosX, vPosY)
hWnd := Acc_WindowFromObject(oAcc)
WinGetClass, vWinClass, ahk_id %hWnd%
MsgBox % vWinClass
JEE_RetX()
HELP: Is there a way to do this via standard commands?

Btw what program is this, and what class are the controls?
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
gwarble
Posts: 524
Joined: 30 Sep 2013, 15:01

Re: The Curse of the Changing Controls

17 Jan 2017, 19:54

Its possible that the controls aren't changing classNN but rather the original Tedit15 may have been hidden or deleted and Tedit17 made visible or created (technically a different control that looks the same and has the same position, but is coded differently in the background)

Maybe try to gather the control's classNN or hWnd right before reading the data from the control instead
EitherMouse - Multiple mice, individual settings . . . . www.EitherMouse.com . . . . forum . . . .
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: The Curse of the Changing Controls  Topic is solved

17 Jan 2017, 23:52

MaxAstro wrote: EDIT: No wait, it looks like ControlGetPos does return the position of a control. Is there a syntax to use it the other way around?
if the Acc solution doesn't work, there are two different ControlFromPoint() functions, see these two links:

https://autohotkey.com/board/topic/2402 ... use/page-2
https://autohotkey.com/board/topic/1545 ... -pos-mode/

first one looks shorter and doesn't require the intermiate Enum func

MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Re: The Curse of the Changing Controls

18 Jan 2017, 11:25

jeeswg wrote:Put Acc.ahk in your Lib folder and try this:

...

Btw what program is this, and what class are the controls?
The program is one you almost certainly won't have heard of, unless you have worked IT at a grocery store. :) The controls are a mix of TEdit, THNumEdit, TListView, and TPanel. Originally I thought it was just some of the TEdit controls that would change, but a couple of the TPanel controls and at least one THNumEdit do as well.

I'll give the Acc library code a try if guest3456's solution doesn't work; I'd rather not have to rely on an outside library if I don't have to, especially since people other than me need to use this script on computers I don't have physical access to.
gwarble wrote:Its possible that the controls aren't changing classNN but rather the original Tedit15 may have been hidden or deleted and Tedit17 made visible or created (technically a different control that looks the same and has the same position, but is coded differently in the background)
I know that it's the same control because the hWND doesn't change when the classNN changes.
guest3456 wrote:if the Acc solution doesn't work, there are two different ControlFromPoint() functions, see these two links:

https://autohotkey.com/board/topic/2402 ... use/page-2
https://autohotkey.com/board/topic/1545 ... -pos-mode/

first one looks shorter and doesn't require the intermiate Enum func
Thanks, that ControlFromPoint function looks like exactly what I need, I'll give it a try.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: The Curse of the Changing Controls

18 Jan 2017, 12:03

I like guest3456's solution, so I hope it works, I was looking for such a solution in the new/old forums but couldn't find one. I did find the OnMessage one though, but would prefer to avoid using OnMessage.

Btw the Acc library is just an ahk file with 200 lines of code (various functions), that you could copy into your script, at the bottom, if you needed to (instead of placing the file in the Lib folder).
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Re: The Curse of the Changing Controls

18 Jan 2017, 12:57

jeeswg wrote:Btw the Acc library is just an ahk file with 200 lines of code (various functions), that you could copy into your script, at the bottom, if you needed to (instead of placing the file in the Lib folder).
Good to know, I'll take a look at it.
MaxAstro
Posts: 557
Joined: 05 Oct 2016, 13:00

Re: The Curse of the Changing Controls

01 Feb 2017, 13:09

Since an update was requested: The first ControlFromPoint function did not work, but the second did. Had a bit of fun implementing that in my code and changing everything around to use Hwnds instead of ClassNNs, but it is now working cleanly - no more problems with grabbing the wrong control.

Thanks for everyone's help, this was a complicated problem and one that I wasn't sure had a clean solution. :)
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: The Curse of the Changing Controls

01 Feb 2017, 13:17

Cheers MaxAstro, thanks for responding to my request!
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot] and 157 guests