AutoHotkey Community

It is currently May 27th, 2012, 12:10 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 14 posts ] 
Author Message
PostPosted: October 1st, 2009, 2:36 am 
Offline

Joined: June 26th, 2006, 6:14 pm
Posts: 1379
Location: USA
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

_________________
Image
ʞɔпɟ əɥʇ ʇɐɥʍ


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 1st, 2009, 3:05 am 
Online
User avatar

Joined: October 7th, 2006, 8:45 am
Posts: 3330
Location: Simi Valley, CA
There is another way too...

_________________
Ternary (a ? b : c) guide     TSV Table Manipulation Library
Post code inside [code][/code] tags!


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 6th, 2009, 5:48 am 
Offline

Joined: June 26th, 2006, 6:14 pm
Posts: 1379
Location: USA
i was interested in the dllcall version, but it just gets classname and not classNN :(

_________________
Image
ʞɔпɟ əɥʇ ʇɐɥʍ


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 6th, 2009, 7:45 am 
Offline
User avatar

Joined: December 26th, 2005, 4:40 pm
Posts: 8776
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 )
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 11th, 2009, 5:16 am 
Offline

Joined: June 26th, 2006, 6:14 pm
Posts: 1379
Location: USA
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 )
}

_________________
Image
ʞɔпɟ əɥʇ ʇɐɥʍ


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 13th, 2009, 11:13 am 
Offline
User avatar

Joined: December 26th, 2005, 4:40 pm
Posts: 8776
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. :roll:
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
   }
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: November 7th, 2009, 3:26 pm 
Offline

Joined: July 4th, 2009, 6:53 pm
Posts: 36
Micahs's script may be useful.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: November 7th, 2009, 8:19 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7502
Location: Australia
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. :)

Also note that SKAN's benchmark script fails completely on Windows 7. ;)
SciCalc -> CalcFrame


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: November 8th, 2009, 8:50 am 
Offline
User avatar

Joined: December 26th, 2005, 4:40 pm
Posts: 8776
@Lexikos: Thanks for the info and the interesting benchmark. :)


Last edited by SKAN on November 18th, 2009, 9:57 pm, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: November 8th, 2009, 11:35 am 
Offline

Joined: August 24th, 2005, 5:29 pm
Posts: 549
Location: Berlin / Germany
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:


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: November 8th, 2009, 11:44 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7502
Location: Australia
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: November 8th, 2009, 12:18 pm 
Offline

Joined: August 24th, 2005, 5:29 pm
Posts: 549
Location: Berlin / Germany
Quote:
z-order, which can vary at run-time and is quite possibly the wrong order

What a pity! :(

_________________
nick :wink:


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 16th, 2011, 6:10 pm 
Offline

Joined: November 28th, 2010, 8:37 am
Posts: 48
Location: Wuxi, China
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
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject: Thank you very much!!
PostPosted: January 25th, 2011, 12:22 pm 
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!


Report this post
Top
  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 14 posts ] 

All times are UTC [ DST ]


Who is online

Users browsing this forum: No registered users and 3 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group