Jump to content
Sign in to follow this  
bo8ster

How to get instance of a control?

Recommended Posts

bo8ster

From http://www.autoitscript.com/forum/index.php?showtopic=93527.

I to be able to get the ClassNN from a given control handle. This will involve getting the class name and the instance count from a given handle.

_WinGetCtrlInfo and _CtrlGetByPos are close however it uses WinGetClassList from a Window handle instead of from a control handle.

I can already get the class name so what I am really looking for is the HINSTANCE property of the control.

I have looked on MSDN at

GetClassLong but that does not give the instance

GetWindowLong with GWL_HINSTANCE but that is for Windows, not controls

GetClassInfo but that requires a instance as a param

WNDCLASS structure may contain what I am after however I am not sure how to extract the information.

Any ideas?

Thanks!


Post your code because code says more then your words can. SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y. Use Opt("MustDeclareVars", 1)[topic="84960"]Brett F's Learning To Script with AutoIt V3[/topic][topic="21048"]Valuater's AutoIt 1-2-3, Class... is now in Session[/topic]Contribution: [topic="87994"]Get SVN Rev Number[/topic], [topic="93527"]Control Handle under mouse[/topic], [topic="91966"]A Presentation using AutoIt[/topic], [topic="112756"]Log ConsoleWrite output in Scite[/topic]

Share this post


Link to post
Share on other sites
Valik

The instance is contrived by us. It is not a real thing.

Share this post


Link to post
Share on other sites
bo8ster

Ok, that's very interesting.

So how does something like ControlGetHandle(Classname:foo; Instance:2) work?

I can only guess it is something like the second instance of the foo class returned by WinGetClassList? (That's what I recon SmOke_N did for the mentioned functions).

Even then, unless the class names are unique how can you tell them apart?

Sorry for the questions, didn't expect would be Instance was contrived.

Edited by bo8ster

Post your code because code says more then your words can. SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y. Use Opt("MustDeclareVars", 1)[topic="84960"]Brett F's Learning To Script with AutoIt V3[/topic][topic="21048"]Valuater's AutoIt 1-2-3, Class... is now in Session[/topic]Contribution: [topic="87994"]Get SVN Rev Number[/topic], [topic="93527"]Control Handle under mouse[/topic], [topic="91966"]A Presentation using AutoIt[/topic], [topic="112756"]Log ConsoleWrite output in Scite[/topic]

Share this post


Link to post
Share on other sites
Valik

So how does something like ControlGetHandle(Classname:foo; Instance:2) work?

It enumerates instances of class foo and looks for the second one that occurs. It's really as obvious as it seems.

Even then, unless the class names are unique how can you tell them apart?

You can't. Changing GUIs cause broken scripts. That's why you should try to use control IDs instead of instances. Control IDs are less likely to change (the programmer has to actively change this but there's rarely a good reason to do so).

Share this post


Link to post
Share on other sites
Valik

This function should do what you want. It is, however, almost completely untested. In fact it's only been tested with the example you see here:

#include <WinAPI.au3>
#include <Array.au3>
Local Const $sProcess = "notepad.exe"
Local Const $sTitle = "Untitled -"
Local Const $sEdit = "Edit1"
Run($sProcess)
WinWait($sTitle)
Local $hEdit = ControlGetHandle($sTitle, "", $sEdit)
Local $sClassNN = _ControlGetClassnameNN($hEdit)
WinClose($sTitle)
MsgBox(4096, "", $sClassNN)

Func _ControlGetClassnameNN($hControl)
    If Not IsHWnd($hControl) Then Return SetError(1, 0, "")
    Local Const $hParent = _WinAPI_GetParent($hControl)
    If Not $hParent Then Return SetError(2, 0, "")
    Local Const $sList = WinGetClassList($hParent)
    Local $aList = StringSplit(StringTrimRight($sList, 1), @LF, 2)
    _ArraySort($aList)
     Local $nInstance, $sLastClass, $sComposite
     For $i = 0 To UBound($aList) - 1
         If $sLastClass <> $aList[$i] Then
            $sLastClass = $aList[$i]
            $nInstance = 1
        EndIf
        $sComposite = $sLastClass & $nInstance
        If ControlGetHandle($hParent, "", $sComposite) = $hControl Then Return $sComposite
        $nInstance += 1
    Next
    Return SetError(3, 0, "")
EndFunc    ; _ControlGetClassnameNN()

Share this post


Link to post
Share on other sites
bo8ster

Thanks Valik, that does seem to work, I have tested it with Scite (two instances Scintilla of there).

I had to change Local $aList = StringSplit(StringTrimRight($sList, 1), @LF, 2) to Local $aList = StringSplit(StringTrimRight($sList, 1), @LF, 1) to get it working.

Looking at StringSplit in the help, I cannot see why 2 is need for the flag param so assume its a type.

It enumerates instances of class foo and looks for the second one that occurs.

So once it finds the second instance of foo, or Scintilla (output window) how then is the handle acquired? I assume something like GetClassInfo cannot be used for this reason.

You can't. Changing GUIs cause broken scripts. That's why you should try to use control IDs instead of instances. Control IDs are less likely to change (the programmer has to actively change this but there's rarely a good reason to do so).

I like don't use controlIDs because they are dynamic, they have to be grabbed on the fly which is why "instance" is so good to use when writing ControlGetHandle calls (when text cannot be used).

Post your code because code says more then your words can. SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y. Use Opt("MustDeclareVars", 1)[topic="84960"]Brett F's Learning To Script with AutoIt V3[/topic][topic="21048"]Valuater's AutoIt 1-2-3, Class... is now in Session[/topic]Contribution: [topic="87994"]Get SVN Rev Number[/topic], [topic="93527"]Control Handle under mouse[/topic], [topic="91966"]A Presentation using AutoIt[/topic], [topic="112756"]Log ConsoleWrite output in Scite[/topic]

Share this post


Link to post
Share on other sites
Valik

Thanks Valik, that does seem to work, I have tested it with Scite (two instances Scintilla of there).

I had to change Local $aList = StringSplit(StringTrimRight($sList, 1), @LF, 2) to Local $aList = StringSplit(StringTrimRight($sList, 1), @LF, 1) to get it working.

Looking at StringSplit in the help, I cannot see why 2 is need for the flag param so assume its a type.

I use it because I despise returning the size in element 0 of an array.

So once it finds the second instance of foo, or Scintilla (output window) how then is the handle acquired? I assume something like GetClassInfo cannot be used for this reason.

We have the handle already.

I like don't use controlIDs because they are dynamic, they have to be grabbed on the fly which is why "instance" is so good to use when writing ControlGetHandle calls (when text cannot be used).

Um, what? You're almost completely wrong here. For most standard applications the Control ID will never change. Ever. Most applications specify IDs as compile-time in the resource script. Stuff like .NET or AutoIt don't have constant IDs but most any ATL, WTL, MFC or standard Windows program will have static IDs.

Share this post


Link to post
Share on other sites
bo8ster

I use it because I despise returning the size in element 0 of an array.

When I use 2 for the flag in StringSplit, _ArrayDisplay($aList) gives

[0]|1

[1]|Editmsctls_statusbar32

and the msg box is always blank. I changed it to two and it worked. I don't know why but thats what I found.

Um, what? You're almost completely wrong here. For most standard applications the Control ID will never change. Ever. Most applications specify IDs as compile-time in the resource script. Stuff like .NET or AutoIt don't have constant IDs but most any ATL, WTL, MFC or standard Windows program will have static IDs.

After some playing around it would appear that I am almost completely wrong. When I first started learning, I noticed that the program I was testing, (written with Borland's CodeGear C++ Builder) the Control IDs changed each time the program is loaded. It is like each controlID is assigned when the Control instantiated.

Example - Load, close, open up some other apps then load again. Its the same control.

Advanced (Class): [CLASS:TTntListView.UnicodeClass; INSTANCE:1]

ID: 159646496

Advanced (Class): [CLASS:TTntListView.UnicodeClass; INSTANCE:1]

ID: 153158630

Thats why i don't use IDs, good to know it can be used with most other apps.

I also notice that if the tabs the controls are on are not displayed (maybe loaded) just after loading, the control cannot be obtained with Class/Text - don't know why. I does strange stuff sometimes.

Quick question, how consistent is WinGetClassList? If there are 5 TTntListView classes, will WinGetClassList return the controls in the same order every time? Does the instance uniquely identify the same class/control every time or is there the possibility TTntListView.UnicodeClass1 can refer to ControlX one time and then ControlY another time?

Thanks


Post your code because code says more then your words can. SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y. Use Opt("MustDeclareVars", 1)[topic="84960"]Brett F's Learning To Script with AutoIt V3[/topic][topic="21048"]Valuater's AutoIt 1-2-3, Class... is now in Session[/topic]Contribution: [topic="87994"]Get SVN Rev Number[/topic], [topic="93527"]Control Handle under mouse[/topic], [topic="91966"]A Presentation using AutoIt[/topic], [topic="112756"]Log ConsoleWrite output in Scite[/topic]

Share this post


Link to post
Share on other sites
Valik

Quick question, how consistent is WinGetClassList? If there are 5 TTntListView classes, will WinGetClassList return the controls in the same order every time? Does the instance uniquely identify the same class/control every time or is there the possibility TTntListView.UnicodeClass1 can refer to ControlX one time and then ControlY another time?

There are no guarantees. It depends on how the window creates it's child controls. You have to observe the behavior of the application you are trying to automate to see if it behaves consistently.

Share this post


Link to post
Share on other sites
wraithdu

@bo8ster

What version of AutoIt are you using? The StringSplit() with flag 2 still returning the element count bug was something I reported a long time ago in some beta version that was eventually fixed.

Share this post


Link to post
Share on other sites
bo8ster

@bo8ster

What version of AutoIt are you using? The StringSplit() with flag 2 still returning the element count bug was something I reported a long time ago in some beta version that was eventually fixed.

From the help file - v3.2.12.1 - hmm I might need to update

Post your code because code says more then your words can. SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y. Use Opt("MustDeclareVars", 1)[topic="84960"]Brett F's Learning To Script with AutoIt V3[/topic][topic="21048"]Valuater's AutoIt 1-2-3, Class... is now in Session[/topic]Contribution: [topic="87994"]Get SVN Rev Number[/topic], [topic="93527"]Control Handle under mouse[/topic], [topic="91966"]A Presentation using AutoIt[/topic], [topic="112756"]Log ConsoleWrite output in Scite[/topic]

Share this post


Link to post
Share on other sites
Valik

:: rolls eyes ::

Share this post


Link to post
Share on other sites
bo8ster

I have updated and it is all working well :)

I have updated http://www.autoitscript.com/forum/index.php?showtopic=93527 to include _ControlGetClassnameNN, thanks for your help Valik.


Post your code because code says more then your words can. SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y. Use Opt("MustDeclareVars", 1)[topic="84960"]Brett F's Learning To Script with AutoIt V3[/topic][topic="21048"]Valuater's AutoIt 1-2-3, Class... is now in Session[/topic]Contribution: [topic="87994"]Get SVN Rev Number[/topic], [topic="93527"]Control Handle under mouse[/topic], [topic="91966"]A Presentation using AutoIt[/topic], [topic="112756"]Log ConsoleWrite output in Scite[/topic]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×