Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

EnumWindows and EnumChildWindows

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • EnumWindows and EnumChildWindows

    Code:
    #COMPILE EXE '#Win 7.00#
    #DIM ALL
    #INCLUDE "win32api.inc" '2002/12/03
     
    '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 Looper     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 Looper  'We want the third edit control
       IF Looper = @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
    '______________________________________________________________________________
     
    FUNCTION EnumwindowProc(BYVAL hWindowProc AS LONG, BYVAL lParam AS LONG) AS LONG
     'Retreive windows handle via caption
     '---------------------------------------------------------------------------
     '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
    '______________________________________________________________________________

  • #2
    Code:
    '** 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
    '[email protected]

    ------------------
    Thx............Gösta
    mailto:[email protected][email protected]</A>
    http://www.SwedesDock.com
    http://www.PondersBible.com

    [This message has been edited by Gösta H. Lovgren-2 (edited December 17, 2002).]
    It's a pretty day. I hope you enjoy it.

    Gösta

    JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
    LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

    Comment


    • #3
      A few small changes and caveats

      Excellent work from both Pierre and Gosta, but the code in its present form presents problems if the "Retrieve windows controls by class" routine is called more than once in an application.

      A fix in the same context as the original post is below.

      Code:
      'Retrieve 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
      
       'Retrieve 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 find 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
           counter = 0        ' The function is successful so reset the static counter
           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
      The loop counter needs to be reset before the routine is called again as it is a static variable, preserved between calls.

      The second change that needs to be made if the routine needs to be called again is as follows.

      1. Reload enumtry1.hndl as it has been destroyed by the enumchildwindows function
      1. Reset (clear all members) the enumtry2 type because if a matching control is not found the previous values are still loaded.
      2. Reload the members of enumtry2 with new data
      3. Call the function again

      If these procedures are followed the above routines can be called in a loop if necessary using the returned value in enumtry2.hndl as an exit strategy.
      If no matching control is found enumtry2.hndl will be set to 0 as detailed in Pierre's and Gosta's examples.

      Regards
      Gary Barnes
      The Control Key

      If you are not part of the solution
      then you are either a gas, solid, plasma or some other form of matter.

      Comment

      Working...
      X