:Start of EnumWindows EnumWindows.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       #
# EnumWindows and EnumChildWindows API functions to retrieve a list of all    # 
# windows and controls opened on your PC.                                     #
#                                                                             #   
###############################################################################

Option Decimalsep,.
Title Window Info
External @Path(%0)gadgetx.dll,@Sysinfo(DSVER)
If @Greater(@Name(@Sysinfo(DSVER)),4)
#DEFINE COMMAND,GADGETX,DEFINE,SET,CALL,FREEDLL,PRINTDIALOG,StopCB,SetCallback
#DEFINE FUNCTION,GADGETX,LOADDLL,GET,ADDROF,SPACE,CALL,GetCallback
End

Define Variable,Handle,user32
Set user32,@LoadDLL(user32.dll)
Define Function,Handle,user32,GetParent,GetParent,Handle|hWndParent
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 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
Set EnumWinProc,@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,PAINT,RESIZABLE
REM *** Modified by Dialog Designer on 3/18/2004 - 12:51 ***
  DIALOG ADD,STYLE,BK,,,,WHITE,
  DIALOG ADD,TEXT,BACKGROUND,0,0,599,246,,,BK  
  DIALOG ADD,TEXT,TEXT1,12,48,,,Click the button to get a list of all top level Windows.,,BK
  If @Greater(@Name(@Sysinfo(DSVER)),4)
    DIALOG ADD,TABLE,TABLE1,36,0,599,156,Handle[25]|Class[80]|Title/Parent[125]
  Else
    DIALOG ADD,LIST,TABLE1,36,0,599,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 @Greater(@Len(@Get(MyEvent)),0)
    goto @Get(MyEvent)
  End
goto evloop
:TIMER
  If @Equal(%%CheckEnumWindows,1)
    DIALOG CURSOR,WAIT
  End
  If @Equal(%%CheckChildEnumWindows,1)
    DIALOG CURSOR,WAIT
  End
goto evloop
:RESIZE
:PAINT
goto evloop
:BUTTON1BUTTON
  Gosub QUITCOMMANDS
  %%CheckEnumWindows = 1
  rem DIALOG CURSOR,WAIT
  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.

  Call EnumWindows,EnumWinProc,0
  rem Gadget EnumChildWindows,@winexists(#Progman),EnumChildWinProc,0
goto evloop
:EnumWindows_Done
  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...
  %%CheckEnumWindows = 0
goto evloop
:EnumChildWindows_Done
  DIALOG CURSOR
  Rem Since all the Child windows are done we can set the return
  rem for the EnumWindows callback function.
  # SetCallBack Return,0,1
  %%CheckEnumChildWindows = 0  
goto evloop
:WinInfoBUTTONBAD
  DIALOG HIDE,BUTTON1
  DIALOG HIDE,BUTTON2
  DIALOG HIDE,WinInfo
  DIALOG HIDE,STATUS1
  %%bkW = @dlgpos(BACKGROUND,W)  
  %%bkH = @dlgpos(BACKGROUND,H)
  %%tblW = @dlgpos(TABLE1,W)
  %%tblh = @dlgpos(TABLE1,H)     
  WINDOW MAXIMIZE,@winexists(Test Callback) 
  %%Width = @diff(@dlgpos(,W),2)
  %%Height = @diff(@dlgpos(,H),2)
  DIALOG SETPOS,BACKGROUND,,,%%Width,%%Height
  DIALOG SETPOS,TABLE1,,,%%Width,%%Height
  PrintDialog @winexists(Test Callback),"Test doc"
  WINDOW NORMAL,@winexists(Test Callback) 
  DIALOG SETPOS,BACKGROUND,,,%%bkW,%%bkH
  DIALOG SETPOS,TABLE1,,,%%tblW,%%tblH
  DIALOG SHOW,BUTTON1
  DIALOG SHOW,BUTTON2
  DIALOG SHOW,WinInfo
  DIALOG SHOW,STATUS1
  
  If @Ok()
    Info Go check the printer
  End
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 @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,@GetCallback(0)
  If @Get(CBParams)
   # Info @Get(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
       # Info VDS @Get(Item)@CR()
       Set Title,@WinText(@Get(Item))
       Set Class,#@WinClass(@Get(Item))
       Set ParentHwnd,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   
   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 @Get(CBParamsChild)
   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 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
       # Info @Get(Item)@CR()
       Set Title,@Call(GetParent,Item)
       rem Gadget Title,Nothing to see
       Set Class,#@WinClass(@Get(Item))
       rem Gadget Class,#NoClass
       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,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
  
  SetCallBack Return,1,1  
Goto Evloop
:QUITCOMMANDS
  %E = 
  If @Equal(%%CheckEnumChildWindows,1)
    %%CheckEnumChildWindows = 0   
    SetCallBack Return,1,0
    repeat
      wait event,0.1
      %E = @Event()
      IF @Equal(%E,EnumWindows_Done)
        Info EnumChildwindows is done
      End
    Until @Equal(%E,EnumWindows_Done)
  End
  if @Equal(%%CheckEnumWindows,1)    
    %%CheckEnumWindows = 0  
    SetCallBack Return,0,0    
    repeat
      wait event,0.1
      %E = @Event()
      IF @Equal(%E,EnumWindows_Done)
        Info Enumwindows is done
      End
    Until @Equal(%E,EnumWindows_Done)
  End
  WAIT 0.5
  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.
  Set EnumWinProc,@AddrOf(CallBack,0)
  Set EnumChildWinProc,@AddrOf(CallBack,1)
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
  FreeDLL user32
Stop

:End of EnumWindows