Page 1 of 2
Child gadget enumeration (Windows)
Posted: Sun Feb 05, 2017 11:37 am
by Justin
Functions to enumerate child gadgets, useful if you want to resize using your own layout now that the container gadgets support the resize event.
Code: Select all
EnableExplicit
Macro GadgetFromHwnd(hwnd)
GetProp_(hwnd, "PB_ID")
EndMacro
Procedure GetHwnd(object.i)
If IsWindow(object)
ProcedureReturn WindowID(object)
ElseIf IsGadget(object)
ProcedureReturn GadgetID(object)
EndIf
EndProcedure
;Gets the first child gadget of a window or gadget container.
;item : for panel gadgets the panel item, -1 to get the selected panel.
Procedure GetFirstChildGadget(parentGadget.i, item.i = -1)
Define.i hwParent, hwnd, gadget, x
hwParent = GetHwnd(parentGadget)
If hwParent
If IsWindow(parentGadget)
hwnd = GetWindow_(hwParent, #GW_CHILD)
gadget = GadgetFromHwnd(hwnd)
If IsGadget(gadget)
ProcedureReturn gadget
EndIf
ElseIf IsGadget(parentGadget)
If GadgetType(parentGadget) = #PB_GadgetType_Panel
If item < -1 : item = -1 : EndIf
If item = -1
item = GetGadgetState(parentGadget)
EndIf
;Go to the panel item
x = 0
hwnd = GetWindow_(hwParent, #GW_CHILD)
While x < item
hwnd = GetWindow_(hwnd, #GW_HWNDNEXT)
x = x + 1
Wend
;Get first child of this panel item
gadget = GadgetFromHwnd(GetWindow_(hwnd, #GW_CHILD))
If IsGadget(gadget)
ProcedureReturn gadget
EndIf
Else ;All other gadgets.
gadget = GadgetFromHwnd(GetWindow_(hwParent, #GW_CHILD))
If IsGadget(gadget)
ProcedureReturn gadget
EndIf
EndIf
EndIf
EndIf
EndProcedure
Procedure GetNextSiblingGadget(gadget.i)
Define.i hwnd
hwnd = GetWindow_(GadgetID(gadget), #GW_HWNDNEXT)
gadget = GadgetFromHwnd(hwnd)
If IsGadget(gadget)
ProcedureReturn gadget
EndIf
EndProcedure
;- TEST
Global.i be, mainWin
Procedure clickHandler()
Define.i gadget, gadget2
gadget = GetFirstChildGadget(mainWin)
While gadget
Debug GetGadgetText(gadget)
If GadgetType(gadget) = #PB_GadgetType_Panel
gadget2 = GetFirstChildGadget(gadget)
While gadget2
Debug "--- " + GetGadgetText(gadget2)
gadget2 = GetNextSiblingGadget(gadget2)
Wend
EndIf
gadget = GetNextSiblingGadget(gadget)
Wend
EndProcedure
mainWin = OpenWindow(#PB_Any, 0, 0, 322, 220, "Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
be = ButtonGadget(#PB_Any, 0, 0, 80, 24,"Enumerate")
BindGadgetEvent(be, @clickHandler(), #PB_EventType_LeftClick)
PanelGadget(1, 8, 30, 306, 180)
AddGadgetItem (1, -1, "Panel 1")
ButtonGadget(2, 10, 15, 80, 24,"Button 1")
AddGadgetItem (1, -1,"Panel 2")
ButtonGadget(3, 95, 15, 80, 24,"Button 2")
CloseGadgetList()
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Re: Child gadget enumeration (Windows)
Posted: Sun Feb 05, 2017 1:06 pm
by Dude
Nice code, Justin.
Is there a way to do this with third-party windows? Like, to enumerate Calculator and make the debug output show "1", "2", "3", "+", "-", etc?
Re: Child gadget enumeration (Windows)
Posted: Sun Feb 05, 2017 2:33 pm
by Keya
Dude wrote:Is there a way to do this with third-party windows? Like, to enumerate Calculator and make the debug output show "1", "2", "3", "+", "-", etc?
Windows only
Code: Select all
Procedure EnumChildren(hWnd.i)
Protected nexthwnd.i, szClass.s{1024}, szText.s{1024}
nexthwnd = GetWindow_(hwnd, #GW_CHILD | #GW_HWNDFIRST)
While nexthwnd <> 0
GetClassName_(nexthwnd, @szClass, SizeOf(szClass))
;GetWindowText_(nexthwnd, @szText, SizeOf(szText))
SendMessage_(nexthwnd, #WM_GETTEXT, SizeOf(szText), @szText)
PrintN(" CHILD: Class=" + szClass + " Text=" + szText)
EnumChildren(nexthwnd)
nexthwnd = GetWindow_(nexthwnd, #GW_HWNDNEXT)
Wend
EndProcedure
Procedure cbEnumParents(hWnd.i, lNotUsed.i)
Protected szClass.s{1024}, szText.s{1024}
GetClassName_(hWnd, @szClass, SizeOf(szClass))
GetWindowText_(hWnd, @szText, SizeOf(szText))
PrintN("PARENT=" + szText)
EnumChildren(hWnd)
ProcedureReturn 1
EndProcedure
OpenConsole()
;// DEMO 1 - ENUM PARENT WINDOWS
;hWnd = #HWND_DESKTOP
;EnumWindows_(@cbEnumParents(), hWnd)
;// DEMO 2 - ENUM CHILDREN OF A PARENT WINDOW
RunProgram("calc.exe")
Delay(500) ;wait for window to load, there are better ways but this will do for demo
hWnd = FindWindow_(#Null, "Calculator")
EnumChildren(hWnd)
Input()
Re: Child gadget enumeration (Windows)
Posted: Sun Feb 05, 2017 2:38 pm
by Bisonte
@Keya:
hWnd is an os-handle. To avoid strange errors ... always youse INTEGER for it... not long.
Re: Child gadget enumeration (Windows)
Posted: Sun Feb 05, 2017 3:02 pm
by Keya
good catch thankyou
Re: Child gadget enumeration (Windows)
Posted: Mon Feb 06, 2017 6:40 am
by Dude
Doesn't work, Keya. Only the "0" button of Calculator shows, with nothing for everything else on Calculator's window.
Also doesn't show anything when I try it with Word's "About" dialog box.

Re: Child gadget enumeration (Windows)
Posted: Mon Feb 06, 2017 8:13 am
by Keya
"doesn't work" might be an exaggeration. It's better than your version anyway

I don't claim it's completely bug free though lol. btw i updated it to use WM_GETTEXT instead of GetWindowText, it seems to be able to get some text that GetWindowText cant (like the main textbox where numbers are calculated/displayed). For whatever reason.
This is what i get for the main window (XP):
Code: Select all
CHILD: Class=Edit Text=0.
CHILD: Class=Button Text=Hyp
CHILD: Class=Button Text=Inv
CHILD: Class=Button Text=
CHILD: Class=Button Text=Sta
CHILD: Class=Button Text=Hex
CHILD: Class=Button Text=Dec
CHILD: Class=Button Text=Oct
CHILD: Class=Button Text=Bin
CHILD: Class=Button Text=
CHILD: Class=Button Text=
CHILD: Class=Button Text=Degrees
CHILD: Class=Button Text=Radians
CHILD: Class=Button Text=Grads
CHILD: Class=Button Text=Qword
CHILD: Class=Button Text=Dword
CHILD: Class=Button Text=Word
CHILD: Class=Button Text=Byte
CHILD: Class=Button Text=Ave
CHILD: Class=Button Text=Sum
CHILD: Class=Button Text=s
CHILD: Class=Button Text=Dat
CHILD: Class=Button Text=F-E
CHILD: Class=Button Text=dms
CHILD: Class=Button Text=sin
CHILD: Class=Button Text=cos
CHILD: Class=Button Text=tan
CHILD: Class=Button Text=(
CHILD: Class=Button Text=Exp
CHILD: Class=Button Text=x^y
CHILD: Class=Button Text=x^3
CHILD: Class=Button Text=x^2
CHILD: Class=Button Text=)
CHILD: Class=Button Text=ln
CHILD: Class=Button Text=log
CHILD: Class=Button Text=n!
CHILD: Class=Button Text=1/x
CHILD: Class=Button Text=MC
CHILD: Class=Button Text=MR
CHILD: Class=Button Text=MS
CHILD: Class=Button Text=M+
CHILD: Class=Button Text=pi
CHILD: Class=Button Text=7
CHILD: Class=Button Text=4
CHILD: Class=Button Text=1
CHILD: Class=Button Text=0
CHILD: Class=Button Text=A
CHILD: Class=Button Text=8
CHILD: Class=Button Text=5
CHILD: Class=Button Text=2
CHILD: Class=Button Text=+/-
CHILD: Class=Button Text=B
CHILD: Class=Button Text=9
CHILD: Class=Button Text=6
CHILD: Class=Button Text=3
CHILD: Class=Button Text=.
CHILD: Class=Button Text=C
CHILD: Class=Button Text=/
CHILD: Class=Button Text=*
CHILD: Class=Button Text=-
CHILD: Class=Button Text=+
CHILD: Class=Button Text=D
CHILD: Class=Button Text=Mod
CHILD: Class=Button Text=OR
CHILD: Class=Button Text=Lsh
CHILD: Class=Button Text==
CHILD: Class=Button Text=E
CHILD: Class=Button Text=And
CHILD: Class=Button Text=Xor
CHILD: Class=Button Text=Not
CHILD: Class=Button Text=Int
CHILD: Class=Button Text=F
CHILD: Class=Button Text=Backspace
CHILD: Class=Button Text=CE
CHILD: Class=Button Text=C
CHILD: Class=Static Text=
CHILD: Class=Static Text=
CHILD: Class=Static Text=
"About Calculator" window:
Code: Select all
CHILD: Class=Static Text=
CHILD: Class=Static Text=Microsoft r Calculator
CHILD: Class=Static Text=-snipped-
CHILD: Class=Static Text=Copyright c 2007 Microsoft Corporation
CHILD: Class=Static Text=
CHILD: Class=SysLink Text=This product is licensed under the terms of the <A>End-User License Agreement</A> to:
CHILD: Class=Static Text=-snipped-
CHILD: Class=Static Text=
CHILD: Class=Static Text=
CHILD: Class=Static Text=Physical memory available to Windows:
CHILD: Class=Static Text=-snipped-KB
CHILD: Class=Button Text=OK
Re: Child gadget enumeration (Windows)
Posted: Mon Feb 06, 2017 8:44 am
by netmaestro
I'm not sure why but the keya code isn't producing any text here at all except the 0 from the static control. Windows 7 Pro, PB 5.60b2. It's obviously working for you keya. That's a head scratcher.
Re: Child gadget enumeration (Windows)
Posted: Mon Feb 06, 2017 8:54 am
by Keya
is very weird. Surely it wouldnt be an admin thing either, pretty sure any process can look at others windows ... or has that changed for security reasons? It would be annoying and not very practical to have to inject a DLL into each process to do the enum. i'll see if i can take a look at it on my Win7 VM a bit later and follow along in a debugger
btw there's also the EnumChildWindows api which i wasnt using, msdn for GetWindow says its better to use that than the GetWindow(#GW_HWNDNEXT) loop i was using, but i think that's just for efficiency as it allows for a callback, whereas im guessing if you use #GW_HWNDNEXT it has to enumerate the entire list (until specified hwnd) each time. But if it's just an efficiency thing it might not be the solution we're after.
It's supposed to be something along the lines of this, but not working yet for me:
Code: Select all
Procedure.i cbEnumChildren (hWnd.i, lParam.i)
Protected szClass.s{1024}, szText.s{1024}
GetClassName_(hWnd, szClass, SizeOf(szClass))
GetWindowText_(hWnd, szText, SizeOf(szText))
Debug " CHILD: Class=" + szClass + " " + "Text=" + szText
ProcedureReturn EnumChildWindows_(hWnd, @cbEnumChildren(), lParam)
EndProcedure
RunProgram("calc.exe")
Delay(500) ;wait for window to load
hWnd = FindWindow_(0, "Calculator")
Debug "hWnd="+ Hex(hWnd)
EnumChildWindows_(hWnd, @cbEnumChildren(), 0)
Re: Child gadget enumeration (Windows)
Posted: Mon Feb 06, 2017 9:11 am
by netmaestro
MSDN says that when working with non-owned windows, you shouldn't use GetWindowText, which composes and sends WM_GETTEXT for you because it won't work - you need to send WM_GETTEXT explicitly yourself. Yet this doesn't work for me either.
Re: Child gadget enumeration (Windows)
Posted: Mon Feb 06, 2017 9:30 am
by Keya
I just tried
Inspect.exe on Windows 7, which confirms that yes it's still possible (seemingly no security/permission issues). So at least we're not on a wild goose chase!

165kb exe though but i'll try and break on EnumChildWindows etc and see what its up to
Re: Child gadget enumeration (Windows)
Posted: Mon Feb 06, 2017 9:37 am
by netmaestro
I did EnumChildWindows with no joy. Some kind of permission thing I'm sure.
Re: Child gadget enumeration (Windows)
Posted: Mon Feb 06, 2017 9:39 am
by Keya
im still thinking injecting dll may be required ... Microsoft's Spy++ comes with spyhk55.dll "Spy++ Hook". But i think that's just for intercepting WM_ messages etc, not window enum. Trying to test that theory now
Re: Child gadget enumeration (Windows)
Posted: Mon Feb 06, 2017 9:43 am
by Keya
actually my previous demo is working fine enumerating Calculator on my Win7-64, logged in as admin. NOT working when logged in as Guest (only seeing like one of the gadgets return a "0" and pretty much nothing for the others, echoing what Dude said/saw)
Re: Child gadget enumeration (Windows)
Posted: Mon Feb 06, 2017 9:46 am
by netmaestro
I'm always logged in as admin and in compiler options I tried request admin mode - nothing.