PowerBASIC Forums
  Source Code
  EnumWindows and EnumChildWindows

Post New Topic  Post A Reply
profile | register | preferences | faq | search

UBBFriend: Email This Page to Someone! next newest topic | next oldest topic
Author Topic:   EnumWindows and EnumChildWindows
Pierre Bellisle
Member
posted December 15, 2002 09:20 AM     Click Here to See the Profile for Pierre Bellisle     Edit/Delete Message   Reply w/Quote
This is an attempt to demonstrate how EnumWindows and EnumChildWindows works
and how to get/change text in an other window not belonging to us.
We will try to get and change the text in PB/Win 7 - PB/CC 3
PowerBASIC COM Browser Interface Prefix textbox.

Have fun...

The starting point of this was http://www.powerbasic.com/support/forums/Forum4/HTML/004169.html

'Compiler: PB/Win 7.00
'WinApi: 2002/12/03

#COMPILE EXE
#DIM ALL
#INCLUDE "Win32Api.Inc"


'We will use this home brewed TYPE to send and extract info
'from both EnumWindowProc and EnumControl, since we can
'only send one LONG, we are going to use a pointer to a
'variable of this type.
TYPE EnumType
hndl AS DWORD
zClass AS ASCIIZ * %Max_Path
zCaption AS ASCIIZ * %Max_Path
id AS DWORD
hParent AS DWORD
count AS DWORD
END TYPE
'______________________________________________________________________________

'Retreive windows controls via class
FUNCTION EnumControl(BYVAL hWindowProc AS LONG, BYVAL lParam AS LONG) AS LONG
'---------------------------------------------------------------------------
'This function is called via the code line...
' EnumChildWindows EnumTry1.hndl, CODEPTR(EnumControl), Varptr(EnumTry2)
' EnumTry1.hndl refer to the parent window
' EnumTry2 is our variable to get/set info we need.
'The way it work is that Windows will do a kind of DO-LOOP with us,
'so this function will be executed many times by Windows,
'each time putting a new child (control) handle in the hWindowProc variable,
'the loop will continue until every child (control) handle
'are enumerated if the function return %True.
'If the function return %False then the enumeration
'is stopped, it's our job to set the Function to return
'%False when we have what we where searching for.

'The code in this function depend of what you want to achieve,
'usually it's retrieving handle, caption text, class, control id...
'---------------------------------------------------------------------------

LOCAL LenClass AS LONG
LOCAL LenCaption AS LONG
LOCAL zClass AS ASCIIZ * %Max_Path
LOCAL zCaption AS ASCIIZ * %Max_Path
LOCAL EnumTryPtr AS EnumType POINTER
STATIC Counter AS LONG

'Retreive the pointer of EnumTry2 so we can read and change it
EnumTryPtr = lParam

'Get the class of the control
LenClass = GetClassName(hWindowProc, zClass, %MAX_PATH)

'Get the text of the control
SendMessage hWindowProc, %WM_GETTEXT, %Max_Path, VARPTR(zCaption)

'Did we found our control class?
IF UCASE$(zClass) = UCASE$(@EnumTryPtr.zClass) THEN
INCR Counter 'We want the third Edit control
IF Counter = @EnumTryPtr.Count THEN 'Found the "Interface Prefix" text box
@EnumTryPtr.hndl = hWindowProc 'Put handle in EnumTry2
@EnumTryPtr.zCaption = zCaption 'Put caption in EnumTry2
@EnumTryPtr.zClass = zClass 'Put class in EnumTry2
@EnumTryPtr.id = GetDlgCtrlID(hWindowProc) 'Get the control id and put it EnumTry2
FUNCTION = %False : EXIT FUNCTION 'Stop enumeration and exit
END IF
END IF

FUNCTION = %True 'True, so Function will recall itself until last window found

END FUNCTION
'______________________________________________________________________________

'Retreive windows handle via caption
FUNCTION EnumWindowProc(BYVAL hWindowProc AS LONG, BYVAL lParam AS LONG) AS LONG
'---------------------------------------------------------------------------
'This function is called via the code line...
' EnumWindows CODEPTR(EnumWindowProc), Varptr(EnumTry1)
' EnumTry1 is our variable to get/set info we need.
'The way it work is that Windows will do a kind of DO-LOOP with us,
'so this function will be executed many times by Windows,
'each time putting a new window handle in the hWindowProc variable,
'The loop will continue until every window handle
'are enumerated if the function return %True.
'If the function return %False then the enumeration
'is stopped, it's our job to set the Function to return
'%False when we have what we where searching for.

'The code in this function depend of what you want to achieve,
'usually it's retrieving a window handle by it's caption text or class name.
'---------------------------------------------------------------------------
LOCAL zCaption AS ASCIIZ * %Max_Path
LOCAL zClass AS ASCIIZ * %Max_Path
LOCAL EnumTryPtr AS EnumType POINTER
LOCAL LenClass AS LONG
LOCAL LenCaption AS LONG

'Retreive the pointer of EnumTry1 so we can read and change it
EnumTryPtr = lParam

IF IsWindowVisible(hWindowProc) THEN 'Get only visible windows
IF GetParent(hWindowProc) = @EnumTryPtr.hParent THEN 'Under desktop if 0 or under parent
IF IsWindowEnabled(hWindowProc) THEN 'Get only enabled windows
LenClass = GetClassName (hWindowProc, zClass, %MAX_PATH) 'Get the class of the dialog
LenCaption = GetWindowText(hWindowProc, zCaption, %MAX_PATH) 'Get the caption of the dialog

'Did we found a dialog with our text?
IF UCASE$(zCaption) = UCASE$(@EnumTryPtr.zCaption) THEN
@EnumTryPtr.hndl = hWindowProc 'Put handle in EnumTry1
@EnumTryPtr.zCaption = zCaption 'Put caption in EnumTry1
@EnumTryPtr.zClass = zClass 'Put class in EnumTry1
FUNCTION = %False : EXIT FUNCTION 'Stop enumeration and exit
END IF
END IF
END IF
END IF

FUNCTION = %True 'True, so Function will recall itself until last window found

END FUNCTION
'______________________________________________________________________________

FUNCTION PBMAIN
LOCAL SomeText AS ASCIIZ * 50
LOCAL EnumTry1 AS EnumType
LOCAL EnumTry2 AS EnumType

'The dialog title that we want to find
EnumTry1.zCaption = "PowerBASIC COM Browser"

'Zero mean that we want a window under the desktop
EnumTry1.hParent = 0

'If window exist EnumTry will be filled with window handle
EnumWindows CODEPTR(EnumWindowProc), VARPTR(EnumTry1)

'EnumTry1.hndl <- Window handle
'EnumTry1.zCaption <- Window caption
'EnumTry1.zClass <- Window class

'Maybe we now have the window handle
IF EnumTry1.hndl THEN 'Not zero, so we found it

'We want a control with a "Edit" class
EnumTry2.zClass = "Edit"

'We want the third control with a "Edit" class
EnumTry2.count = 3 'Try it with one or two for other Edit control

'Start the search for controls
EnumChildWindows EnumTry1.hndl, CODEPTR(EnumControl), VARPTR(EnumTry2)

'Did we find it ?
IF EnumTry2.hndl THEN 'Not zero, so we found it
'EnumTry2.id <- Control ID
'EnumTry2.hndl <- Control handle
'EnumTry2.zClass <- Class name
'EnumTry2.zCaption <- Caption text

'Write text to this control
SomeText = "Play it again Sam... At " & TIME$
SendMessage EnumTry2.hndl, %WM_SETTEXT, 0 ,VARPTR(SomeText)

MSGBOX "Done!" & $CRLF & _
"The text was: " & $TAB & EnumTry2.zCaption & $CRLF & _
"The new text is: " & $TAB & SomeText & $CRLF & _
"Control handle is: " & $TAB & HEX$(EnumTry2.hndl) & " hex" & $CRLF & _
"Control id is: " & $TAB & FORMAT$(EnumTry2.id) & " dec" & $CRLF & _
"Control class is: " & $TAB & EnumTry2.zClass & $CRLF & _
"Window handle is: " & $TAB & HEX$(EnumTry1.hndl) & " hex" & $CRLF & _
"Window caption is: " & $TAB & EnumTry1.zCaption & $CRLF & _
"Window class is: " & $TAB & EnumTry1.zClass _
, %MB_ICONINFORMATION OR %MB_OK OR %MB_TOPMOST, SomeText
ELSE
MSGBOX "Sorry, edit control handle not found!" _
,%MB_ICONEXCLAMATION OR %MB_OK OR %MB_TOPMOST, "We have a problem !"
END IF
ELSE
MSGBOX "Did you started the ""PowerBASIC COM Browser"" ?" & $CRLF & _
"(In PB ide, Tool, PowerBASIC COM Browser)" _
, %MB_ICONQUESTION OR %MB_OK OR %MB_TOPMOST, "Handle not found!"
END IF

END FUNCTION
'______________________________________________________________________________

------------------
Pierre Bellisle

[This message has been edited by Pierre Bellisle (edited February 27, 2004).]

IP: Logged

Gösta H. Lovgren-2
Member
posted December 17, 2002 08:58 AM     Click Here to See the Profile for Gösta H. Lovgren-2     Edit/Delete Message   Reply w/Quote

'** I have added more comments to Pierre's very very good code to hopefully
' better understand it for myself. My comments will be preceded by '**
' so as to differentiate them. Note also I have moved PBMAIN to the top
' of the code. Just makes more sense to me at this point as it is executed first
' and I'm still stuck in "Linear' mode in my thinking.
' Gösta H. Lovgren

#Compile Exe
#Dim All
#Include "c:\Win32Api.Inc"


'We need this TYPE to send and extract info from EnumWindowProc
'and EnumControl callback since we can only send one LONG
'** There is some confusion here for me by the term "callback". As I understand
'it, a "Callback" is roughly equivalent to an Input routine in BASIC.
'In this case EnumControl is the equivalent of a "procedure" and not a Callback.

'We are going to use a pointer to a variable of this type.
Type EnumType
hndl AS Dword
zClass AS Asciiz * %Max_Path
zCaption AS Asciiz * %Max_Path
id AS Dword
hParent AS Dword
count AS Dword
End Type
'______________________________________________________________________________

Function PBMAIN
Local hProc AS LONG
Local hControl AS LONG
Local idControl AS LONG
Local SomeText AS Asciiz * %Max_Path '** Pierre had it set at 50
Local EnumTry1 AS EnumType 'I changed it for "playing" purposes
Local EnumTry2 AS EnumType

SomeText = "Play it again Sam... " & Time$ +_
" 2 Play it again Sam... " & Time$ +_ '** I added the extras
" 3 Play it again Sam... " & Time$ +_
" 4 Play it again Sam... " & Time$ +_
" 5 Play it again Sam... " & Time$ +_
" 6 Play it again Sam... " & Time$ +_
" 7 Play it again Sam... " & Time$ +_
" 8 Play it again Sam... " & Time$

'The dialog title that we want to find
EnumTry1.zCaption = "PowerBASIC COM Browser"

'Zero mean that we want a window under the desktop
EnumTry1.hParent = 0
'** I'm not sure what "under the desktop" means. Presumably it means "minimized"
'or not showing

'If window exist EnumTry will be filled with window handle
EnumWindows CodePtr(EnumWindowProc), VarPtr(EnumTry1)
'**EnumWindows is a an API Function that uses two LONG variables
' A pointer to the code for EnumWindows to use
' A pointer to where to [put the results
'** Note "API" functions are DELARED in WinAPI32.Inc
'**EnumWindowProc is code (a Function) designed by Pierre to be used by EnumWindows
'** (EnumTry1) is an UDT designed by Pierre that will be filled and he is pointing
' EnumWindows to it using VarPtr


'Maybe we now have the window handle
If EnumTry1.hndl Then
hProc = EnumTry1.hndl
'** EnumWindows has filled the UDT (a hit, it found a window with the EnumTry1 UDT value
' Of .zCaption in it)and now Pierre is putting the window handle it found into hProc

'We want a control with a "Edit" class
EnumTry2.zClass = "Edit"
'** How did Pierre know there was a class named "Edit"?
' what other class names are there and where can they be found?
' Not in Petzold, or at least not easily, I looked.
'I wonder what class the other two controls (Interfaces & Methods/Properties)
' are in are called.

'We want the third control with a "Edit" class
EnumTry2.count = 1 'Try it with one or two for other Edit control
'** Note - there seems to be 4 Edit Controls in the hProc Window. (PB Com)
'Pretty cool. Duuno why just yet but is still neat.

'Start the search for controls
EnumChildWindows hProc, CodePtr(EnumControl), VarPtr(EnumTry2)
'** EnumChildWindows is an API Function defined in WinAPI32.Inc
' hProc is the window handle (of PB Com) found by EnumWindows above
' EnumControl is a function designed by Pierre
' EnumTry2 is the UDT that hold the info returned.

'Did we find it ?
If EnumTry2.hndl Then
idControl = EnumTry2.id '<- Control ID
hControl = EnumTry2.hndl '<- Handle to the control
'** I presume idControl is the Id assigned by the programmer or more likely
' is the ID assigned by Windows as it is used by the program.
' and that hControl is the internal value Windows uses to "work" the control

'Write text to this control
SendMessage hControl, %WM_SETTEXT, 0 ,VarPtr(SomeText)
'** SendMessage is an API function:
'(BYVAL hWnd AS DWORD, _ ' is the handle to be acted on
' ByVal dwMsg AS Dword, _ 'is what to do with the handle
' ByVal wParam AS Dword, _ 'in this case nothing is needed
' ByVal lParam AS LONG) ' point to the text to be printed in the control
MsgBox "Done!"
Else
MsgBox "Edit control handle not found!"
'** what you will get if you try an EnumTry2.count greater than 4
' only 4 Edit controls
End If
Else
MsgBox "PowerBASIC COM Browser handle not found!"
'** what you get if you don't run the PB tool, which I never had
'before and really didn't even know existed until today (I don't use
'the PB Editor. Jellyfish is just so much better/easier for me.
End If

End Function
'______________________________________________________________________________


'Retreive windows controls via class
Function EnumControl(ByVal hWindowProc AS LONG, ByVal lParam AS LONG) AS LONG
Local LenClass AS LONG
Local LenCaption AS LONG
Local zClass AS Asciiz * %Max_Path
Local zCaption AS Asciiz * %Max_Path
Local EnumTryPtr AS EnumType Pointer
Static Counter AS LONG

'Retreive a pointer to EnumTry2 so we can read and change it
EnumTryPtr = lParam

'Get the class of the control
LenClass = GetClassName(hWindowProc, zClass, %MAX_PATH)
'** GetClassName is an API function
'hWindowProc has been determined by the call to ...
'.. well I don't know where it has been assigned unless it was with the
'call to EnumChildWindows above
'zClass must be returned by GetClassName
'%Max_Path is a constant of 256, presumably tells GetClassName not to search
'more than is necessary?

'Get the text of the control
SendMessage hWindowProc, %WM_GETTEXT, %Max_Path, VarPtr(zCaption)
'** SendMessage is an API call
'** %Wm_GetText is telling SendMessage what to do.
'** %Max_Path is how many bytes to do it for
'** VarPtr is telling SendMessage where to put the text found
' so it can be read in zCaption

'Did we found our control class?
If UCase$(zClass) = UCase$(@EnumTryPtr.zClass) Then
Incr Counter 'We want the third Edit control
If Counter = @EnumTryPtr.Count Then 'Found the "Interface Prefix" text box
@EnumTryPtr.hndl = hWindowProc 'Put handle in EnumTry2
@EnumTryPtr.zCaption = zCaption 'Put caption in EnumTry2
@EnumTryPtr.zClass = zClass 'Put class in EnumTry2
@EnumTryPtr.id = GetDlgCtrlID(hWindowProc) 'Get the control id and put it EnumTry2
Function = 0 : Exit Function 'Stop enumeration and exit
End If
End If

Function = 1 'True, so Function will recall itself until last window found
'** Now this is new to me. I was unaware a
'"Function = 1 (%True)" would cause recursion
' And presumably a "Function = 0 (%false)" would cause an exit
' I had seen the Function = 0 in lots of code but until
' now didn't know why.

End Function
'______________________________________________________________________________

'Retreive windows handle via caption
Function EnumWindowProc(ByVal hWindowProc AS LONG, ByVal lParam AS LONG) AS LONG
Local zCaption AS Asciiz * %Max_Path
Local zClass AS Asciiz * %Max_Path
Local EnumTryPtr AS EnumType Pointer
Local LenClass AS LONG
Local LenCaption AS LONG

'Retrive a pointer to EnumTry so we can read and change it
EnumTryPtr = lParam

If IsWindowVisible(hWindowProc) Then 'Get only visible windows
If GetParent(hWindowProc) = @EnumTryPtr.hParent Then 'Under desktop if 0 or under parent
If IsWindowEnabled(hWindowProc) Then 'Get only enabled windows
LenClass = GetClassName (hWindowProc, zClass, %MAX_PATH) 'Get the class of the dialog
LenCaption = GetWindowText(hWindowProc, zCaption, %MAX_PATH) 'Get the caption of the dialog

'Did we found a dialog with our text?
If UCase$(zCaption) = UCase$(@EnumTryPtr.zCaption) Then
@EnumTryPtr.hndl = hWindowProc 'Put handle in EnumTry1
@EnumTryPtr.zCaption = zCaption 'Put caption in EnumTry1
@EnumTryPtr.zClass = zClass 'Put class in EnumTry1
Function = 0 : Exit Function 'Stop enumeration and exit
End If

End If
End If
End If

Function = 1 'True, so Function will recall itself until last window found

End Function
'______________________________________________________________________________


'
'** I hope no one (especially Pierre) sees anything critical in my "notes"
'I only made them to help myself better understand how things work. If anyone
'sees anything wrong with my interpretations I hopw he with correct it/me.
'Gösta H. Lovgren
'gosta@SwedesDock.com

------------------
Thx............Gösta
Gosta@SwedesDock.com
http://www.SwedesDock.com
http://www.PondersBible.com

[This message has been edited by Gösta H. Lovgren-2 (edited December 17, 2002).]

IP: Logged

All times are EasternTime (US)

next newest topic | next oldest topic

Administrative Options: Close Topic | Archive/Move | Delete Topic
Post New Topic  Post A Reply
Hop to:

Contact Us | PowerBASIC BASIC Compilers

Copyright © 1999-2005 PowerBASIC, Inc. All Rights Reserved.


Ultimate Bulletin Board 5.45c