AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Function - Control_GetClassNN() - Get a control ClassNN

 
Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
ahklerner



Joined: 26 Jun 2006
Posts: 1381
Location: USA

PostPosted: Thu Oct 01, 2009 1:36 am    Post subject: Function - Control_GetClassNN() - Get a control ClassNN Reply with quote

I searched in vain for something to do this...
So here it is.
Gets the ClassNN for a given hWnd
Some commands allow usage of ClassNN for a control, however there is not a function to get the ClassNN of a control. all base functions return ClassName only.

i borrowed part of this function from SKAN....

Code:
;Control_GetClassNN()
;by ahklerner
;

Control_GetClassNN(hWndWindow,hWndControl){
   DetectHiddenWindows, On
   WinGet, ClassNNList, ControlList, ahk_id %hWndWindow%
   Loop, PARSE, ClassNNList, `n
   {
      ControlGet, hwnd, hwnd,,%A_LoopField%,ahk_id %hWndWindow%
      if (hWnd = hWndControl)
         return A_LoopField
   }
}

;return

;Test script
Gui, +LastFound
hWindow := WinExist()
Gui, Add, Text, hwndhWnd, some text
Gui, Show
WinGetClass, ClassNN, ahk_id %hWnd%
MsgBox % Control_GetClassNN(hWindow,hWnd)
ExitApp

_________________

ʞɔпɟ əɥʇ ʇɐɥʍ
Back to top
View user's profile Send private message
[VxE]



Joined: 07 Oct 2006
Posts: 3254
Location: Simi Valley, CA

PostPosted: Thu Oct 01, 2009 2:05 am    Post subject: Reply with quote

There is another way too...
_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!
Back to top
View user's profile Send private message
ahklerner



Joined: 26 Jun 2006
Posts: 1381
Location: USA

PostPosted: Tue Oct 06, 2009 4:48 am    Post subject: Reply with quote

i was interested in the dllcall version, but it just gets classname and not classNN Sad
_________________

ʞɔпɟ əɥʇ ʇɐɥʍ
Back to top
View user's profile Send private message
SKAN



Joined: 26 Dec 2005
Posts: 8688

PostPosted: Tue Oct 06, 2009 6:45 am    Post subject: Reply with quote

Avoiding LOOP...

Code:
Control_GetClassNN( hWnd,hCtrl ) { ; SKAN: www.autohotkey.com/forum/viewtopic.php?t=49471
 WinGet, CH, ControlListHwnd, ahk_id %hWnd%
 WinGet, CN, ControlList, ahk_id %hWnd%
 LF:= "`n",  CH:= LF CH LF, CN:= LF CN LF,  S:= SubStr( CH, 1, InStr( CH, LF hCtrl LF ) )
 StringReplace, S, S,`n,`n, UseErrorLevel
 StringGetPos, P, CN, `n, L%ErrorLevel%
 Return SubStr( CN, P+2, InStr( CN, LF, 0, P+2 ) -P-2 )
}
Back to top
View user's profile Send private message Send e-mail
ahklerner



Joined: 26 Jun 2006
Posts: 1381
Location: USA

PostPosted: Sun Oct 11, 2009 4:16 am    Post subject: Reply with quote

Very Nice! mine takes fewer query performance counter increments. at least here
Code:
freq := 0
Gui, +LastFound
hWindow := WinExist()
Gui, Add, Text, hwndhWnd, some text
Gui, Show
WinGetClass, ClassNN, ahk_id %hWnd%
;MsgBox % Control_GetClassNN(hWindow,hWnd)
;ExitApp

Loop 1000
{
   freq += 100
   DllCall("QueryPerformanceCounter", "Int64 *", CounterBefore1)
   Loop %freq%
      hWnd := Control_GetClassNN(hWindow,hWnd)
   DllCall("QueryPerformanceCounter", "Int64 *", CounterAfter1)
   DllCall("QueryPerformanceCounter", "Int64 *", CounterBefore2)
   Loop %freq%
      hWnd2 := sControl_GetClassNN(hWindow,hWnd)
   DllCall("QueryPerformanceCounter", "Int64 *", CounterAfter2)
   DllCall("QueryPerformanceFrequency","int64*",f)
   avg1 := (CounterAfter1 - CounterBefore1) / f
   avg2 := (CounterAfter2 - CounterBefore2) / f
   MsgBox % "queryperformancecounterfrequency: " . f. "`nloops: " . freq . "`navg QPC time is ahklerner:" . avg1 . "`navg QPC time is skan:" . avg2
}
Control_GetClassNN(hWndWindow,hWndControl){
   DetectHiddenWindows, On
   WinGet, ClassNNList, ControlList, ahk_id %hWndWindow%
   Loop, PARSE, ClassNNList, `n
   {
      ControlGet, hwnd, hwnd,,%A_LoopField%,ahk_id %hWndWindow%
      if (hWnd = hWndControl)
         return A_LoopField
   }
}


sControl_GetClassNN( hWnd,hCtrl ) { ; SKAN: www.autohotkey.com/forum/viewtopic.php?t=49471
 WinGet, CH, ControlListHwnd, ahk_id %hWnd%
 WinGet, CN, ControlList, ahk_id %hWnd%
 LF:= "`n",  CH:= LF CH LF, CN:= LF CN LF,  S:= SubStr( CH, 1, InStr( CH, LF hCtrl LF ) )
 StringReplace, S, S,`n,`n, UseErrorLevel
 StringGetPos, P, CN, `n, L%ErrorLevel%
 Return SubStr( CN, P+2, InStr( CN, LF, 0, P+2 ) -P-2 )
}

_________________

ʞɔпɟ əɥʇ ʇɐɥʍ
Back to top
View user's profile Send private message
SKAN



Joined: 26 Dec 2005
Posts: 8688

PostPosted: Tue Oct 13, 2009 10:13 am    Post subject: Reply with quote

ahklerner wrote:
mine takes fewer query performance counter increments. at least here

Code:
; ...
hWindow := WinExist()
Gui, Add, Text, hwndhWnd, some text
Gui, Show
; ...


You are creating only a single control. Rolling Eyes
In real world, the control list could be long where the Loop command can never match the speeds of String manipulation commands.

Code:
SetBatchLines -1
Run Calc
WinWait, Calculator ahk_class SciCalc
hWnd := WinExist( "Calculator ahk_class SciCalc" )
SendMessage, 0x111, 304,,, ahk_id %hWnd% ; MenuSelect : View > Scientific
ControlGet, hCtrl, Hwnd,, Button72, ahk_id %hWnd%

TC := A_TickCount
Loop 1000
  sControl_GetClassNN( hWnd,hCtrl )
TC1 := ( A_TickCount - TC ) / 1000

TC := A_TickCount
Loop 1000
  Control_GetClassNN( hWnd,hCtrl )
TC2 := ( A_TickCount - TC ) / 1000

MsgBox, 0, in Milliseconds, % "skan:`t"TC1 "`nahkl:`t" TC2

sControl_GetClassNN( hWnd,hCtrl ) { ; SKAN: www.autohotkey.com/forum/viewtopic.php?t=49471
 WinGet, CH, ControlListHwnd, ahk_id %hWnd%
 WinGet, CN, ControlList, ahk_id %hWnd%
 Clipboard := CN
 LF:= "`n",  CH:= LF CH LF, CN:= LF CN LF,  S:= SubStr( CH, 1, InStr( CH, LF hCtrl LF ) )
 StringReplace, S, S,`n,`n, UseErrorLevel
 StringGetPos, P, CN, `n, L%ErrorLevel%
 Return SubStr( CN, P+2, InStr( CN, LF, 0, P+2 ) -P-2 )
}

Control_GetClassNN(hWndWindow,hWndControl){
   DetectHiddenWindows, On
   WinGet, ClassNNList, ControlList, ahk_id %hWndWindow%
   Loop, PARSE, ClassNNList, `n
   {
      ControlGet, hwnd, hwnd,,%A_LoopField%,ahk_id %hWndWindow%
      if (hWnd = hWndControl)
         return A_LoopField
   }
}
Back to top
View user's profile Send private message Send e-mail
ghee22



Joined: 04 Jul 2009
Posts: 36

PostPosted: Sat Nov 07, 2009 2:26 pm    Post subject: Reply with quote

Micahs's script may be useful.
Back to top
View user's profile Send private message
Lexikos



Joined: 17 Oct 2006
Posts: 7295
Location: Australia

PostPosted: Sat Nov 07, 2009 7:19 pm    Post subject: Reply with quote

I was interested to try a couple different approaches, and I found that the poor performance of ahklerner's function with greater number of controls was not due to the use of Loop. Maybe no method using a scripted Loop will be as efficient as SKAN's method, but in ahklerner's case something else makes a much bigger difference: the conversion of each ClassNN back into a HWND, I believe.

Anyway, my first idea was to use EnumChildWindows. This is used internally by AutoHotkey to list controls and convert between HWND and ClassNN. The order in which EnumChildWindows enumerates controls determines the NN value and the order of controls in the list. The basic premise is to copy this in script, counting how many controls are encountered with the same class before the target control is found.

I think the main problem with that idea was the overhead of the callback required to enumerate controls. My second idea replaces the oft called script callback with a parsing loop, letting AutoHotkey do the control enumeration - i.e. WinGet,v,ControlListHwnd.

Each run of the benchmark begins with 16 controls. Each iteration calls each method 1000 times to retrieve the ClassNN of the last control, then shows the results. The average time in ms of each method and the factor by which the time increased are shown. Before continuing to the next iteration, the number of controls is doubled.
Code:
#NoEnv
DetectHiddenWindows, On
SetBatchLines, -1
SetFormat, FloatFast, 0.3
Gui, +LastFound
hWnd := WinExist()
i = 1000 ; iterations
n = 16 ; initial number of controls

Loop %n%
    Gui, Add, Text, hwndhCtrl

Loop
{

    TC := A_TickCount
    Loop %i%
        eControl_GetClassNN( hWnd,hCtrl )
    TC1 := ( A_TickCount - TC ) / i
   
    TC := A_TickCount
    Loop %i%
        lControl_GetClassNN( hWnd,hCtrl )
    TC2 := ( A_TickCount - TC ) / i

    TC := A_TickCount
    Loop %i%
        sControl_GetClassNN( hWnd,hCtrl )
    TC3 := ( A_TickCount - TC ) / i
   
    TC := A_TickCount
    Loop %i%
        aControl_GetClassNN( hWnd,hCtrl )
    TC4 := ( A_TickCount - TC ) / i
     
;     OutputDebug % n "`tE " TC1 " (" TC1/pTC1 ")`tL " TC2 " (" TC2/pTC2 ")`tS " TC3 " (" TC3/pTC3 ")`tA " TC4 " (" TC4/pTC4 ")"
    MsgBox % "Controls: " n "`n`n"
        . "E`t" TC1 "`t=prev*" TC1/pTC1 "`n"
        . "L`t" TC2 "`t=prev*" TC2/pTC2 "`n"
        . "S`t" TC3 "`t=prev*" TC3/pTC3 "`n"
        . "A`t" TC4 "`t=prev*" TC4/pTC4 "`n"
   
    Loop %n%
        Gui, Add, Text, hwndhCtrl
    n *= 2
    pTC1 := TC1, pTC2 := TC2, pTC3 := TC3, pTC4 := TC4
}

; Lexikos: Find ClassNN by enumerating child controls and counting
;           the number of controls of the target class.
eControl_GetClassNN(hWnd, hCtl)
{
    static sCtl, sCls, sProc, sNN, sRet
    if (A_EventInfo = sProc)
    {
        WinGetClass, cls, ahk_id %hWnd%
        if (cls == sCls)
        {
            sNN += 1
            if (hWnd = sCtl)
            {
                sRet := sCls sNN
                return false ; stop
            }
        }
        return true ; continue
    }
    if !sProc
        sProc := RegisterCallback(A_ThisFunc,"F")
    sCtl := hCtl
    WinGetClass, sCls, ahk_id %sCtl%
    sNN := 0
    sRet := ""
    DllCall("EnumChildWindows", "uint", hWnd, "uint", sProc, "uint", 0)
    return sRet
}

; Lexikos: Find ClassNN by retrieving list of HWNDs and counting
;           the number of controls of the target class.
lControl_GetClassNN(hwnd, hctl)
{
    WinGet, hlist, ControlListHwnd, ahk_id %hwnd%
    WinGetClass, tclass, ahk_id %hctl%
    Loop, Parse, hlist, `n
    {
        WinGetClass, lclass, ahk_id %A_LoopField%
        if (lclass == tclass)
        {
            nn += 1
            if A_LoopField = %hctl%
                return tclass nn
        }
    }
}

; SKAN
sControl_GetClassNN( hWnd,hCtrl ) { ; SKAN: www.autohotkey.com/forum/viewtopic.php?t=49471
 WinGet, CH, ControlListHwnd, ahk_id %hWnd%
 WinGet, CN, ControlList, ahk_id %hWnd%
 LF:= "`n",  CH:= LF CH LF, CN:= LF CN LF,  S:= SubStr( CH, 1, InStr( CH, LF hCtrl LF ) )
 StringReplace, S, S,`n,`n, UseErrorLevel
 StringGetPos, P, CN, `n, L%ErrorLevel%
 Return SubStr( CN, P+2, InStr( CN, LF, 0, P+2 ) -P-2 )
}

; ahklerner
aControl_GetClassNN(hWndWindow,hWndControl){
   WinGet, ClassNNList, ControlList, ahk_id %hWndWindow%
   Loop, PARSE, ClassNNList, `n
   {
      ControlGet, hwnd, hwnd,,%A_LoopField%,ahk_id %hWndWindow%
      if (hWnd = hWndControl)
         return A_LoopField
   }
}

SKAN's method still wins, but my enumeration and looping methods come close with a reasonable number of controls. Smile

Also note that SKAN's benchmark script fails completely on Windows 7. Wink
SciCalc -> CalcFrame
Back to top
View user's profile Send private message Visit poster's website
SKAN



Joined: 26 Dec 2005
Posts: 8688

PostPosted: Sun Nov 08, 2009 7:50 am    Post subject: Reply with quote

@Lexikos: Thanks for the info and the interesting benchmark. Smile

Last edited by SKAN on Wed Nov 18, 2009 8:57 pm; edited 1 time in total
Back to top
View user's profile Send private message Send e-mail
nick



Joined: 24 Aug 2005
Posts: 549
Location: Berlin / Germany

PostPosted: Sun Nov 08, 2009 10:35 am    Post subject: Reply with quote

FYI:
Code:
GetClassNN(HW, HC) { ; HW : Window's HWND, HC : Control's HWND
   VarSetCapacity(CL,256,0), HA := 0
   , DllCall("GetClassName", UInt,HC, Str,CL, Int,255)
   While HA := DllCall("FindWindowEx", UInt,HW, UInt,HA, UInt,&CL, UInt,0)
      If (HA = HC)
         Return CL . A_Index
   Return False
}

_________________
nick Wink
Back to top
View user's profile Send private message
Lexikos



Joined: 17 Oct 2006
Posts: 7295
Location: Australia

PostPosted: Sun Nov 08, 2009 10:44 am    Post subject: Reply with quote

Unless I'm mistaken, that method will iterate through the controls in z-order, which can vary at run-time and is quite possibly the wrong order. As I mentioned earlier, EnumChildWindows defines the order in which AutoHotkey assigns NN values to controls.
Back to top
View user's profile Send private message Visit poster's website
nick



Joined: 24 Aug 2005
Posts: 549
Location: Berlin / Germany

PostPosted: Sun Nov 08, 2009 11:18 am    Post subject: Reply with quote

Quote:
z-order, which can vary at run-time and is quite possibly the wrong order

What a pity! Sad
_________________
nick Wink
Back to top
View user's profile Send private message
Scoox



Joined: 28 Nov 2010
Posts: 35
Location: Wuxi, China

PostPosted: Sun Jan 16, 2011 5:10 pm    Post subject: Reply with quote

Not really what the original poster was asking but I stumbled upon this thread while looking for a way to determine the ClassNN of a control so I thought others would find it useful.

The following function returns the ClassNN of the currently focused control:

Code:
ControlFocusedClassNN()
{
   ControlGetFocus, ControlClassNN, A
   Return ControlClassNN
}


The following function returns the ClassNN of the control currently under the mouse:

Code:
ControlUnderMouseClassNN()
{
   MouseGetPos,,,, ControlClassNN, 1
   Return ControlClassNN
}
Back to top
View user's profile Send private message
mcouthon
Guest





PostPosted: Tue Jan 25, 2011 11:22 am    Post subject: Thank you very much!! Reply with quote

Scoox,
your post really saved my day. I always knew there had to be a way to do this without loops and all kinds of crazy stuff. Thank you so much!
Back to top
Display posts from previous:   
Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
Page 1 of 1

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group