:Start of EnumChildWindows EnumChildWindows.dsc
DragonSphereSoftware

DragonSphere Software Demos


If you are viewing this script in your browser you can save it as a VDS 5.x source file (*.dsc) to run it.




#
# DragonSphere Software's Home Page
#  
# All Source Files for this demo
###############################################################################
#                                                                             #   
# This demo shows how to use GadgetX'es CallBack functions by using the       #
# EnumChildWindows API function                                               # 
#                                                                             #
###############################################################################
 
Option Decimalsep,.
Title Window Info

If @Greater(@Name(@Sysinfo(DSVER)),4)
External gadgetx.dll,@Sysinfo(DSVER)
#DEFINE COMMAND,GADGETX,DEFINE,SET,CALL,FREEDLL,PRINTDIALOG,StopCB,SetCallback
#DEFINE FUNCTION,GADGETX,LOADDLL,GET,ADDROF,SPACE,CALL,GetCallback
Else
 Warn This demo requires VDS 5.x
 Stop
End

Define Variable,Handle,user32 
Set user32,@LoadDLL(user32.dll)
# Define Command
# Syntax: Define Command,,,,,
Define Command,EnumWindows_Done,user32,EnumWindows,EnumWindows,Pointer|lpEnumFunc,DWORD|lParam
Define Command,EnumChildWindows_Done,user32,EnumChildWindows,EnumChildWindows,Handle|hWndParent,Pointer|lpEnumChildFunc,DWORD|lParam
Define Function,Handle,user32,GetParent,GetParent,Handle|hWndParent
Define Variable,String,MyEvent 
Define Variable,Handle,ParentHwnd 
Define Variable,Pointer,EnumWinProc 
Define Variable,Pointer,EnumChildWinProc 
Define Variable,QWORD,LstCount 
Define Variable,BYTE,cnt 
Define Variable,String,CBParams 
Define Variable,String,CBParamsChild 
Define Variable,String,Item 
Define Variable,String,Title 
Define Variable,String,Class 
Define Variable,String,Text 

Rem Describe to Gadget what Parameters are supposed to be passed to our fuction
rem by the external DLL and give Gadget a user defined VDS event name that will
rem be trigered each time the external function calls our Callback function
Define CallBack,0,Integer,EnumWindowsProc,Handle,Integer
Define CallBack,1,Integer,EnumChildWins,Handle,Integer

Rem Get the memory address of 1 of the 5 callback functions inside of Gadget.
rem they are numbered similar to VDS List but the Callback ID's start at 0,1,2,3,4
rem Gadget EnumWinProc,@Gadget(AddrOf,CallBack,0)
Set EnumChildWinProc,@AddrOf(CallBack,1)

Rem Initialize all String variables...
Set MyEvent,@Space(256)
Set CBParams,@Space(256)
Set CBParamsChild,@Space(256)
Set Item,@Space(256)
Set Title,@Space(256)
Set Class,@Space(256)
Set Text,@Space(256)

:Main
  DIALOG CREATE,Test Callback,-1,0,599,266
REM *** Modified by Dialog Designer on 12/4/2003 - 09:20 ***
  DIALOG ADD,TEXT,TEXT1,12,48,,,Click the button to get a list of all child Windows.
  If @Greater(@Name(@Sysinfo(DSVER)),4)
    DIALOG ADD,TABLE,TABLE1,36,24,556,156,Handle|Class|Title/Parent
  Else
    DIALOG ADD,LIST,TABLE1,36,24,556,156
  End
  DIALOG ADD,BUTTON,BUTTON1,208,108,64,24,Get List
  DIALOG ADD,BUTTON,BUTTON2,208,400,64,24,Close
  DIALOG ADD,BUTTON,WinInfo,208,256,64,24,&Info  
  DIALOG ADD,STATUS,STATUS1,Click Get List...
  DIALOG SHOW
  rem %%Stat_hwnd = @winexists(~STATUS1)
  Rem Make a temp list to hold the CallBack parameters.
  List create,1
  List create,2
:evloop
  Rem Ok be warned if you use a Timer event then expect this
  rem to be very slow.
  rem If you need to use a Timer then use FireEvent Timer
  wait event
  Set MyEvent,@Event()
  if @Get(MyEvent)
    goto @Get(MyEvent)
  End
goto evloop
:TIMER
  If @Equal(%%CheckChildEnumWindows,1)
    DIALOG CURSOR,WAIT
  End
goto evloop
:BUTTON1BUTTON
  Gosub QUITCOMMANDS
  %%CheckChildEnumWindows = 1
  Rem Make sure the List box is cleared.
  List Clear,TABLE1
  List Clear,2
  Set LstCount,0
  Rem Kick off the EnumWindows function. Passing it the memory address of our Callback function.
  Rem Note: If you want the function to run Asyncronously then you must call it as a VDS command.
  rem       This is because Gadget calls the function from a seperate thread when called as a VDS
  rem       command.  
  rem I did this so that Gadget's callback functions will work like other languages.
  rem Gadget EnumWindows,EnumWinProc,0
  REM @winexists(Project: mpgadget)
  Call EnumChildWindows,#TfMain,EnumChildWinProc,0
goto evloop
:EnumWindows_Done
  %%CheckEnumWindows = 0
  DIALOG CURSOR
  DIALOG SET,TEXT1,Wow that took a bit of work but I am finished now.
  Dialog Set,STATUS1,There are @Get(LstCount) windows open on your PC dang your busy call ya later...
goto evloop
:EnumChildWindows_Done
  DIALOG CURSOR
  %%CheckChildEnumWindows = 0
  Dialog Set,STATUS1,There are @Get(LstCount) child windows for Test Callback...
goto evloop
:WinInfoBUTTON
  Set Item,@Item(TABLE1)
  If @Null(@Get(Item))
    Set Item,@Item(TABLE1,0)
  End    
  %%OldFsep = @fsep()
  Option FieldSep,@Tab()
  Parse "%%Hwnd;%%Class;%%Titletxt",@Get(Item)
  if @Greater(@Pos(->,%%Hwnd),0)
    Rem This is a child window
    %%Hwnd = @SubStr(%%Hwnd,3,@len(%%Hwnd))
    %%Status = @WinPos(%%Hwnd,S)
    If @Equal(%%Status,1)
      %%Status = Normal
    ElsIf @Equal(%%Status,2)
      %%Status = Iconized
    ElsIf @Equal(%%Status,3)
      %%Status = Maximized
    End
    If @Equal(%%Class,##32770)
      If @Equal(#@WinClass(@Call(GetParent,%%Hwnd)),##32770)
        Rem Use Title text for both child and parent
        Info Handle: %%Hwnd@CR()Title: %%Titletxt@CR()Parent Title: @WinText(@Call(GetParent,%%Hwnd))@CR()Status: %%Status@CR()Top: @WinPos(%%Hwnd,T)@CR()Left: @WinPos(%%Hwnd,L)@CR()Width: @WinPos(%%Hwnd,W)@CR()Height: @WinPos(%%Hwnd,H)
      Else
        Rem Else just use the child's title text
        Info Handle: %%Hwnd@CR()Title: %%Titletxt@CR()Parent: #@WinClass(@Call(GetParent,%%Hwnd))@CR()Status: %%Status@CR()Top: @WinPos(%%Hwnd,T)@CR()Left: @WinPos(%%Hwnd,L)@CR()Width: @WinPos(%%Hwnd,W)@CR()Height: @WinPos(%%Hwnd,H)      
      End
    Else
      If @Equal(#@WinClass(@Call(GetParent,%%Hwnd)),##32770)
        Rem Use Title text for parent
        Info Handle: %%Hwnd@CR()Class: %%Class@CR()Parent Title: @WinText(@Call(GetParent,%%Hwnd))@CR()Status: %%Status@CR()Top: @WinPos(%%Hwnd,T)@CR()Left: @WinPos(%%Hwnd,L)@CR()Width: @WinPos(%%Hwnd,W)@CR()Height: @WinPos(%%Hwnd,H)
      Else
        Rem Else use the child and Parent class
        Info Handle: %%Hwnd@CR()Class: %%Class@CR()Parent: #@WinClass(@Call(GetParent,%%Hwnd))@CR()Status: %%Status@CR()Top: @WinPos(%%Hwnd,T)@CR()Left: @WinPos(%%Hwnd,L)@CR()Width: @WinPos(%%Hwnd,W)@CR()Height: @WinPos(%%Hwnd,H)
      End
    End
  Else
    Rem This is a Top level window
    %%Status = @WinPos(%%Hwnd,S)
    If @Equal(%%Status,1)
      %%Status = Normal
    ElsIf @Equal(%%Status,2)
      %%Status = Iconized
    ElsIf @Equal(%%Status,3)
      %%Status = Maximized
    End
    If @Equal(%%Class,##32770)
      Info Handle: %%Hwnd@CR()Title: %%Titletxt@CR()Status: %%Status@CR()Top: @WinPos(%%Hwnd,T)@CR()Left: @WinPos(%%Hwnd,L)@CR()Width: @WinPos(%%Hwnd,W)@CR()Height: @WinPos(%%Hwnd,H)    
    Else
      Info Handle: %%Hwnd@CR()Class: %%Class@CR()Status: %%Status@CR()Top: @WinPos(%%Hwnd,T)@CR()Left: @WinPos(%%Hwnd,L)@CR()Width: @WinPos(%%Hwnd,W)@CR()Height: @WinPos(%%Hwnd,H)    
    End
  End  
  End
  Option FieldSep,%%OldFsep
goto evloop
:EnumWindowsProc
  Rem This sub-routine is the event that Gadget trigered due to the EnumWindows API
  rem function calling one of Gadget's callback routines.
  Rem Ok here is the strange part of this.  Because Gadget can only emulate
  rem Callback functions due to the fact that
  rem 1) You cannot build functions with VDS source code.
  rem 2) You cannot get the memory address of a VDS sub-routine.
  rem We have to emulate them with some generic functions that I put in Gadget.
  rem In this case EnumWindows requires a return value of '1' to enumerate all the window
  rem handles on the PC.
  Rem @Gadget(GetCallback,) returns all parameters passed to the callback as a VDS List
  rem Gadget will sit and wait until you collect the value with the GetCallback function.
  rem If you never collect the value then when you exit the VDS script it will generate and ERROR.
  rem This is due to the thread that is left open because the callback is waiting for the signal
  rem to set the return value and finish processing.
  Set CBParams,@Get(GetCallback,0)
  rem If @Null(@Gadget(CBParams))
   Rem Just a redundant check to make sure Gadget is returning information
   rem Define CallBack,Return,0,0
   rem Info This should not have been called  @CR()@Item(2,@pred(@count(2))) 
  If @Get(CBParams)
   rem Info @Gadget(CBParams)@CR()
   Rem Clear List 1
   List clear,1
   Rem Assign the Parameters that was passed to Gadget's CallBack function
   rem to list 1.
   List Assign,1,@Get(CBParams)
   REM Info @Text(1)@CR()
   REM Gadget CBParams,NULL
   Rem Place in a loop to get each parameter in turn
   Set cnt,0
   Repeat
     Set Item,@Item(1,@Get(cnt))
	 if @Greater(@Pos(@chr(37),@Get(Item)),0)
       Rem Make sure the Item that we are getting is the Window Handle and not
       rem our second parameter which in this case we don't care about.
       rem Normally the second parameter you would be able to set so you can tell
       rem your CallBack function when to stop but because we are remotely controlling
       rem our CallBack function we don't need this.
       
       Rem Get the Window's Title bar text
       rem Gadget Title,@WinText(@Gadget(Item))
       Set Title,@WinText(@Get(Item))
       Set Class,#@WinClass(@Get(Item))
       Set ParentHwnd,@Get(Item)
       if @Greater(@len(@Get(Title)),0)
         Rem If the Window has a title bar or some kind of text then display the text
	     Set Text,@Get(Item)@Tab()@Get(Class)@Tab()@Get(Title)
       Else
         Rem If the window does not have any text then just display "No Title"
         Set Text,@Get(Item)@Tab()@Get(Class)@Tab()No Title
       End
	 End
   Until @Greater(@Get(cnt,++),@count(1))
   Rem Add the Window info to our list box.
   if @Greater(@Match(2,@Get(Text)),-1)
   Else
     List ADD,2,@Get(Text)
     List ADD,TABLE1,@Get(Text)
     Dialog Set,STATUS1,There are @Get(LstCount,++) windows open on your PC...
   End
   List Seek,2,0     
   Call EnumChildWindows,ParentHwnd,EnumChildWinProc,0
   %%CheckEnumChildWindows = 1   
   rem SetCallBack Return,0,1
  End
    
Goto Evloop
      
:EnumChildWins

  rem %E = @event()
  Rem This sub-routine is the event that Gadget trigered due to the EnumChildWindows API
  rem function calling one of Gadget's callback routines.
  Rem Ok here is the strange part of this.  Because Gadget can only emulate
  rem Callback functions due to the fact that
  rem 1) You cannot build functions with VDS source code.
  rem 2) You cannot get the memory address of a VDS sub-routine.
  rem We have to emulate them with some generic functions that I put in Gadget.
  rem In this case EnumChildWindows requires a return value of '1' to enumerate all the 
  rem child window handles on the current window.
  Rem @Gadget(GetCallback,) returns all parameters passed to the callback as a VDS List
  rem Gadget will sit and wait until you collect the value with the GetCallback function.
  rem If you never collect the value then when you exit the VDS script it will generate and ERROR.
  rem This is due to the thread that is left open because the callback is waiting for the signal
  rem to set the return value and finish processing.
  Set CBParamsChild,@GetCallback(1)
  If @Null(@Get(CBParamsChild))
   Rem Just a redundant check to make sure Gadget is returning information
   rem if there was no return then just return 0 to the child callback
   rem Define CallBack,Return,1,0 
   rem This is here to clear the parent EnumWindows callback
   rem Define CallBack,Return,0,1
   rem Info This could have been called @CR()@Item(2,@pred(@count(2)))
  Else
   Rem Clear List 1
   List clear,1
   Rem Assign the Parameters that was passed to Gadget's CallBack function
   rem to list 1.
   List Assign,1,@Get(CBParamsChild)
   REM Gadget CBParams,NULL
   Rem Place in a loop to get each parameter in turn
   Set cnt,0
   Repeat
     Set Item,@Item(1,@Get(cnt))
	 if @Greater(@Pos(@chr(37),@Get(Item)),0)
       Rem Make sure the parameter that we are getting is the Child Window Handle and not
       rem our second parameter which in this case we don't care about.
       rem Normally the second parameter you would be able to set so you can tell
       rem your CallBack function when to stop but because we are remotely controlling
       rem our CallBack function we don't need this.
       
       Rem Get the Window's Title bar text
       rem Gadget Title,@WinText(@Gadget(Item))
       Set Title,@Call(GetParent,@Get(Item))
       Set Class,#@WinClass(@Get(Item))
       if @Get(Title)
         Rem If the Window has a title bar or some kind of text then display the text
	     Set Text,"->"@Get(Item)@Tab()@Get(Class)@Tab()@Get(Title)
       Else
         Rem If the window does not have any text then just display "No Title"
         Set Text,"->"@Get(Item)@Tab()@Get(Class)@Tab()No Title
       End
	 End
   Until @Greater(@Get(cnt,++),@count(1))
   Rem Add the Window info to our list box.
   if @Greater(@Match(2,@Get(Text)),-1)
   else
     List ADD,TABLE1,@Get(Text)
     List ADD,2,@Get(Text)
     Dialog Set,STATUS1,There are @Get(LstCount,++) windows open on your PC...
     rem Info @Text(2)     
   end
   
   List Seek,2,0
   
   Rem Set the CallBack return value.
  End
  rem Info Wait here for a sec.
  SetCallBack Return,1,1  
Goto Evloop
:QUITCOMMANDS
    if @Equal(%%CheckEnumChildWindows,1)
      %E = 
      SetCallBack Return,1,0  
      repeat
        wait 0.1
        %E = @Event()
        IF @Equal(%E,EnumChildWindows_Done)
          Info EnumChildwindows is done
        End
      Until @Equal(%E,EnumChildWindows_Done)
    End
    REM Info Stoping everything
  Rem Added this to clear the memory addresses and close the callback handles.
  StopCB
  Rem After you stop all CallBacks you have to re-establish their memory addresses
  rem and callback handles.
  rem Gadget EnumWinProc,@Gadget(AddrOf,CallBack,0)
  Set EnumChildWinProc,@AddrOf(CallBack,1)
    
    Exit
:parentwin    
  if @Equal(%%CheckEnumWindows,1)
    SetCallBack Return,0,0    
    repeat
      wait 0.1
      %E = @Event()
      IF @Equal(%E,EnumWindows_Done)
        Info Enumwindows is done
      End
    Until @Equal(%E,EnumWindows_Done)
  End
Exit
:BUTTON2BUTTON
:CLOSE
  DIALOG CURSOR
  Rem Just incase the Callbacks are hung release them...
  Gosub QUITCOMMANDS
  Rem Clear your list...
  List clear,TABLE1
  List clear,1
  List close,1
  List clear,2
  List close,2
  Rem Free user32.dll
  FreeDLL user32
Stop


:End of EnumChildWindows