WinBatch Tech Support Home

Database Search

If you can't find the information using the categories below, post a question over in our WinBatch Tech Support Forum.

TechHome

Control Manager
plus
plus

Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.

AnalysisEx


; ****************************************************************************************
;
;                                REQUIRES WinBatch 2003
;  
; ****************************************************************************************

goto Main
;------------------------------------------------------------------------------------------

These comments are from the original Analysis script which is distributed with WinBatch:
   "This script creates a report on the windows visible at the time the report is run.  
   Run the script.  Choose a top-level window of interest, and it will show pertinent 
   information that may be necessary to use the Control Manager extender."

In modifying the original script I had a twofold goal:
   1) A personal project hit a bottleneck when it had to access a non-standard List-view 
      control.  The only way to perhaps overcome the bottleneck in my project was to have 
      a better understanding of the information returned by the Analysis script.
   
   2) Beyond the challenge to my understanding I found the presentation of the 
      information in the Analysis script left something to be desired hence AnalysisEx.


This script contains a UDF, udfGetHWnd, which is meant to augment the functionality of 
RoboScripter, not replace it.  I wanted a way to test methods of drilling down to a 
control and wound up with a tool that let me master the EvilApp as a result.

Perhaps, your EvilApp has a non-standard Treeview.  Or you want avoid the time delay in 
some of Control Manager's window functions while your code tests different methods of 
getting to the target control.

Using AnalysisEx and testing various criteria with Interactive Drilldown may provide the 
handle your code needs.

I think the interface is fairly obvious but just in case:  
   The "+/-" button is to reset the Tree expansion to the value shown in the 
   UpDown control.  It seems to work most of the time ;-)

   "Refresh" just updates the visible windows column if you change something in the target.

   The first column in the ListView is a session handle for the controls and is useful 
   for verifying the results of queries.

   The Window column serves no useful purpose now that I've finished the project but...  It 
   shows the order in which the controls were found and the number found.

   "Show Controls" could probably use some work but I like it nonetheless.  Whenever I 
   use RoboScripter, I always find myself wondering about all these windows that the code 
   is drilling down thru.  Select any control(s) in the ListView and click the button and 
   to see where they are or at least where they're hiding.  Open a few files in Studio 
   maximize one of them and run AnalysisEx to see what I mean.

A final note.  AnalysisEx finds more controls than the original script but I doubt that 
they're of any use.  I haven't bothered to track down exactly which controls are missed 
by Analysis.wbt.


Version History:
   Ver 1.0.0   Presents essentially the same information as the original script using a 
               Tree-view and List-view controls with the option to save the results in a 
               "report" which provides the same information as the original script.

   Ver 1.0.1   Added a show controls action.
               
               Fixed.  Script would crash if you set UD to 0, prior to selecting either 
               the Tvw or Lvw.
               
               Fixed.  Changing levels was not ensuring that the current Tvw item was 
               visible.
   
   
   Ver 1.0.2   Adds the ability to expand/collapse the tree to any level.
               
               Fixed. There was no "if Tests then return WorkWnd" after first "gosub 
               Eval" before the code enters the while loop in udfGetHWnd.
   
   
   Ver 1.0.3   Added Drilldown Interactive using using udfGetHWnd
               
               Added an initial listing of all the WrkWnd handles to 
               provide the user with check values for Interactive sessions.
               
               Inserted commentted line "if dllcall(user32, long:"GetFocus")==hEd", in 
               the Main loop, as there may be a problem with earlier versions of Control 
               Manager.

   
   Ver 1.0.4 - Modified the interactive interface.
               
               Changed ddFldList to a DropDown list, FldCbx.  Clicking its buddy
               button appends the variable to the current query. Added a DropDown list for 
               classes found with the same functionality as FldCbx.
   
   
   Ver 1.0.5   Forgot to run Gather on ver 1.0.4 changes and udfGetHwnd was not added to the 
               LoadStuff code.  
               
               Added code to skip hidden and iconized windows in the AskItemList() box.

   
   Ver 1.0.5b  Made the skipping of hidden and iconized windows optional.
   
               Changed the massaging of the windows list to remove duplicates if user 
               chooses to skip hidden and iconized windows.
               
               Fixed.  Logic in Next/Previous control was wrong and the script would 
               crash if the user initially tried to goto the previous control.

;------------------------------------------------------------------------------------------
:UpdateViews
   if !isdefined(aryVis)
      aryVis = arrdimension(300, 0, 0, 0, 0)
      arrinitialize(aryVis, 0)
   endif
   Swap = @false
   if hLvw==Lvw1
      hNext = Lvw2
   else 
      hNext = Lvw1
   endif
   csendmessage(hNext, 4105, 0, 0)                     ; LVM_DELETEALLITEMS

   lvNext = -1
   visList = ''
   for winCnt = 0 to winCnts
      tvItem = Ary[winCnt, 1]
      binarypoke4(Rect, 0, tvItem)
      if csendmessage(hTvw, 4356, 0, pRect)
         aryVis[winCnt] = 1
         visList = iteminsert(tvItem, -1, visList, tab)
         lvNext = lvNext+1
      else
         aryVis[winCnt] = 0
         tvItem = 0                                    ; TVM_GETITEMRECT returns false for unexpanded items.
      endif
      lvItem = aryLv[lvNext, 1]
      if tvItem==lvItem                                ; Just writting visible items to hNext, doesn't affect Swap flag.
         if winCnt==0
            lvCnt = -1
         endif
         Cnt = udfTvGetParam(hTvw, Tvi, tvItem)
         newNode = tvItem
         gosub LvInsertItem
         continue
      endif
      if tvItem                                                ; Tree has expanded add new nodes and set Swap.
         Swap = @true
         Cnt = udfTvGetParam(hTvw, Tvi, tvItem)
         newNode = tvItem
         gosub LvInsertItem
      endif
   next

   f00 = csendmessage(hLvw, 4100, 0, 0)-1                      ; LVM_GETITEMCOUNT
   Lim = lvNext+1 
   if f00>Lim                                                  ; Tree has collapsed remove appropriate lvItems and set Swap.
      Swap = @true
      while f00>Lim
         aryLv[f00-1, 0] = ''
         aryLv[f00-1, 1] = ''
         lvCnt = lvCnt-1
         csendmessage(hNext, 4104, f00-1, 0)                   ; LVM_DELETEITEM
         f00 = f00-1
      endwhile
   endif
   if Swap then gosub Swap

   if cgetfocus()==hTvw
      tvSel = csendmessage(hTvw, 4362, 9, Ary[0, 1])           ; TVM_GETNEXTITEM=4362, TVGN_CARET=9
      tvSelNdx = udfTvGetParam(hTvw, Tvi, tvSel)
      lvSelected = udfLvGetSel(hLvw, 1)
      if lvSelected!=-1
         if aryLv[lvSelected, 0]==tvSelNdx then return
      endif
      binarypoke4(Lvi, ilviStateMask, 2)
      binarypoke4(Lvi, ilviState, 0)                           ; LVIS_SELECTED
      for tsc = 0 to lvCnt
         csendmessage(hLvw, 4139, tsc, pLvi)                   ; LVM_SETITEMSTATE
         if aryLv[tsc, 0]==tvSelNdx then lvCurSel = tsc
      next   
      binarypoke4(Lvi, ilviState, 2) 
      csendmessage(hLvw, 4139, lvCurSel, pLvi)
      csendmessage(hLvw, 4115, lvCurSel, 0)                    ; LVM_ENSUREVISIBLE
   endif   

   if cgetfocus()==hLvw
      tvNode = csendmessage(hTvw, 4362, 9, Ary[0, 1])          ; TVM_GETNEXTITEM=4362, TVGN_CARET=9
      lvSelected = udfLvGetSel(hLvw, 1)
      if lvSelected==-1 then return
      chkNode = aryLv[lvSelected, 1]
      if tvNode==chkNode then return
      csendmessage(hTvw, 4363, 9, chkNode)                     ; TVM_SELECTITEM=4363 , TVGN_CARET=9
   endif   


   return


;------------------------------------------------------------------------------------------
:Swap
   if hLvw==Lvw1
      hLvw = Lvw2
      hHide = Lvw1
   else 
      hLvw = Lvw1
      hHide = Lvw2
   endif
   udfHideCtl(hHide, 1)
   udfHideCtl(hLvw, 0)

   dllcall(user32, long:"SetFocus", long:hTvw)
      
   return

;------------------------------------------------------------------------------------------
:InsertNode
   if pNode
      for pNdx = 0 to Cnt
         if Ary[pNdx, 1]==pNode then break
      next
      Ary[pNdx, 6] = Ary[pNdx, 6] + 1   
      Mask = 74                                                ; TVIF_CHILDREN|TVIF_HANDLE
      binarypoke4(Tvi, iMask, Mask)      
      binarypoke4(Tvi, iTreeItem, pNode)      
      binarypoke4(Tvi, iChildren, 1)      
;       f00 = dllcall(user32, long:"SendMessageA", long:hTvw, long:4365, long:0, lpbinary:Tvi)   ; TVM_SETITEM=4365
      dllcall(user32, long:"SendMessageA", long:hTvw, long:4365, long:0, lpbinary:Tvi)   ; TVM_SETITEM=4365
      binarypoke4(Tvi, iTreeItem, 0)      
      binarypoke4(Tvi, iChildren, 0)      
   endif
   
   Ary[Cnt, 0] = Level
   Ary[Cnt, 2] = pNode
   Ary[Cnt, 3] = WorkWnd
   Ary[Cnt, 4] = FirstChild
   Ary[Cnt, 5] = NextSibling

   ; Insert the new node.
   binarypoke4(Tvins, iParent, pNode)
   binarypoke4(Tvins, iInsertAfter, 65534)                     ;TVI_LAST
   binarycopy(Tvins, iTvi, Tvi, 0, 40)
   newNode = dllcall(user32, long:"SendMessageA", long:hTvw, long:4352, long:0, lpbinary:Tvins) ;TVM_INSERTITEM
   ; Expand Root to show Level1 nodes.
   if Level==1 then Rslt = dllcall(user32, long:"SendMessageA", long:hTvw, long:4354, long:2, long:pNode) ;TVM_EXPAND=4354, TVE_EXPAND=2

   ; Update/set the title of the new node.
   Mask = 5                                                    ;TVIF_TEXT|TVIF_PARAM
   binarypoke4(Tvi, iMask, Mask)      
   binarypoke4(Tvi, iTreeItem, newNode)
   binarypoke4(Tvi, iParam, Cnt)      
   Ary[Cnt, 1] = newNode
   Label = 'L%Level%: C'
   TextLen = binarypokestr(TextBuf, 0, Label)
   if TextLen<MaxText then binarypoke(TextBuf, TextLen, 0)
   Rslt = dllcall(user32, long:"SendMessageA", long:hTvw, long:4365, long:0, lpbinary:Tvi) ;TVM_SETITEM
   if Level<=1 then gosub LvInsertItem
   
   return

;------------------------------------------------------------------------------------------
:UpdateLabels
   binarypoke4(Tvi, iMask, 1)
   for wCnt = 0 to winCnts
      binarypoke4(Tvi, iTreeItem, Ary[wCnt, 1])
      sLen = binarypokestr(TextBuf, 0, strcat('L', Ary[wCnt, 0], ': C', Ary[wCnt, 6]))
      binarypoke(TextBuf, sLen, 0)
      csendmessage(hTvw, 4365, 0, pTvi)                        ; TVM_SETITEM
   next
   return

;------------------------------------------------------------------------------------------
:GetAttributes
   maxLevel = 0
   GetAttributes = @true
   WorkWnd = hWnd
   pNode  = 0
   Cnt = 0
   Level = 0
   Siblings = ''
   gosub GetWndInfo
   gosub InsertNode
   if !FirstChild then return
   while FirstChild || itemcount(Siblings, Sep)
      while FirstChild
         Cnt = Cnt+1 
         Level = Level+1
         pNode = newNode
         WorkWnd = FirstChild
         gosub GetWndInfo
         gosub InsertNode
         if NextSibling then Siblings = iteminsert(Cnt, -1, Siblings, Sep)
      endwhile ; FirstChild
      if Level>maxLevel then maxLevel = Level
      
      sibCnt = itemcount(Siblings, Sep)
      if sibCnt
         Sib = itemextract(sibCnt, Siblings, Sep)
         Siblings = itemremove(sibCnt, Siblings, Sep)
         Cnt = Cnt+1 
         pNode = Ary[Sib, 2]
         WorkWnd = Ary[Sib, 5]
         Level = Ary[Sib, 0]
         gosub GetWndInfo
         if NextSibling then Siblings = iteminsert(Cnt, -1, Siblings, Sep)
         gosub InsertNode
      endif
   endwhile ; FirstChild || itemcount(Siblings, Sep)
   
   winCnts = Cnt
   
   csendmessage(hUd, 1125, 0, maxLevel<<32)     ; UDM_SETRANGE
   csetedittext(hEd, '1')
   
   Classes = itemsort(Classes, @tab)
   gosub UpdateLabels
   
   return 

;------------------------------------------------------------------------------------------
:Main
   gosub Init

   GetAttributes = 0
   gosub GetAttributes

   winCnts = Cnt

   binarypoke4(Rect, 0, 2)                                                   ;LVIR_LABEL=2
   csendmessage(hLvw, 4110, 0, pRect)                                        ;LVM_GETITEMRECT=4110
   csendmessage(hTvw, 4379, binarypeek4(Rect, 12) - binarypeek4(Rect, 4), 0) ;TVM_SETITEMHEIGHT=4
   udfHideCtl(hTvw, 0)
   udfHideCtl(hLvw, 0)
   
   tvLevel      = 1
   SaveAnalysis = 1
   ShowControls = 2
   Refresh      = 3
   Close        = 4
   ExpandTree   = 5
   LReset       = 5
   DrillDown    = 6

   :Loop
   while 1 
      Action = 0
      for cnt = 1 to zlgMaxButton                            
         if boxbuttonstat(1, Cnt)
            Action = Cnt
            break
         endif
      next

      ; if dllcall(user32, long:"GetFocus")==hEd
      if cgetfocus()==hEd
         chkLevel = cgetedittext(hEd)
         if chkLevel!=tvLevel
            tvLevel = chkLevel 
            Action = ExpandTree
         endif
      endif
      
      gosub UpdateViews

      select Action
         case SaveAnalysis
            gosub WriteToFile
            break

         case ShowControls
            gosub ShowControls
            break   
            
         case Refresh
            csendmessage(Lvw1, 4105, 0, 0)                  ; LVM_DELETEALLITEMS
            csendmessage(Lvw2, 4105, 0, 0)                  ; LVM_DELETEALLITEMS
            csendmessage(hTvw, 4353, 0, Ary[0, 1])          ; TVM_DELETEITEM=4353, TVI_ROOT=65536
            
            arrinitialize(Ary, 0)
            arrinitialize(aryNfo, '')
            arrinitialize(aryLv, '')
            
            LvCnt = -1
            hLvw = Lvw1
            hNext = hLvw
            
            udfHideCtl(Lvw1, 1)
            udfHideCtl(Lvw2, 1)
            
            gosub GetAttributes
            
            udfHideCtl(hLvw, 0)
            break
         
         case Close
            goto Cancel
            break
         
         case ExpandTree
            for wCnt = 0 to winCnts
               Level = Ary[wCnt, 0]
               if Level>=tvLevel
                  etFlag = 1                                      ; TVE_COLLAPSE
               else
                  etFlag = 2                                      ; TVE_EXPAND
               endif
               csendmessage(hTvw, 4354, etFlag, Ary[wCnt, 1])     ; TVM_EXPAND
            next
            break
         case DrillDown   
            gosub DrillDown
            break
      endselect
   endwhile

; Fall thru -------------------------------------------------------------------------------
:Cancel   
   if isdefined(Tvi) then binaryfree(Tvi)
   if isdefined(TextBuf) then binaryfree(TextBuf)
   if isdefined(Tvins) then binaryfree(Tvins)
   if isdefined(lvhTextBuf) then binaryfree(lvhTextBuf)
   if isdefined(Lvi) then binaryfree(Lvi)
   if isdefined(lviTextBuf) then binaryfree(lviTextBuf)
   if isdefined(Lvcol) then binaryfree(Lvcol)
   if isdefined(Rect) then binaryfree(Rect)
   if isdefined(wFile) then fileclose(wFile)
   if isdefined(tempF) then fileclose(tempF)
   if fileexist(tmpWbt) then filedelete(tmpWbt)
   exit

;------------------------------------------------------------------------------------------
:WBERRORHANDLER
   wErrFile = thisVer
   wError=LastError()
   wErrStr = IntControl(34,wError,0,0,0)
   wErrLine = wberrorhandlerline
   wErrOffset = wberrorhandleroffset
   wErrAssign  = wberrorhandlerassignment
   wErrRptFile = strcat(wbtDir, 'Error.txt')
   wErrMessage = 'Please email this file:%@CRLF%%@tab%"%wErrRptFile%"%@CRLF%to gvag@shaw.ca with the Subject line "AnalysisEx Error"'
   wErrTxt = strCat(`wErrFile = `, wErrFile, @CRLF, `wError = `, wError, @CRLF, `wErrStr = `, wErrStr, @CRLF, `wErrLine = `, wErrLine, @CRLF, `wErrOffset = `, wErrOffset, @CRLF, `wErrAssign = `, wErrAssign, @CRLF, @CRLF, wErrMessage)   
   fw = fileopen(wErrRptFile, 'WRITE')
   filewrite(fw, wErrTxt)
   fileclose(fw)
   run('NotePad.exe', wErrRptFile)
   clipput(wErrTxt)
   goto Cancel

;------------------------------------------------------------------------------------------
:DrillDown   
   ddCrit = 'Class==""Edit""'
   ddStatic = 'Enter the Eval parameter: udfGetHWnd(hApp, Eval)'
   zlgFormat=`WWWDLGED,6.1`
   
   zlgCaption     = `Interactive Drilldown`
   zlgX           = 049
   zlgY           = 170
   zlgWidth       = 406
   zlgHeight      = 168
   zlgNumControls = 011
   zlgProcedure   = `zlg`
   zlgFont        = `Tahoma|6656|40|34`
   zlgTextColor   = `0|0|0`
   zlgBackground  = `DEFAULT,251|251|222`
   zlgConfig      = 0
   
  ;varnnn = ` x , y, cx, cy,  Control type, Variable,   Title/Pre,      RetVal,  Tab, Style, , "Family|Size|St|PF", "FgColor",  BgColor`                           
   zlg001 = `089,149,036,012, PUSHBUTTON,   DEFAULT,   "Continue",        1,       4, DEFAULT, "Tahoma|6656|40|34", "0|128|0",  DEFAULT`
   zlg002 = `275,149,036,012, PUSHBUTTON,   DEFAULT,   "Quit",            2,       6, DEFAULT, "Tahoma|6656|40|34", "255|0|0",  DEFAULT`
   zlg003 = `089,006,222,048, MULTILINEBOX, ddMsg,     "%hWnd%",          DEFAULT, 0, DEFAULT, DEFAULT,             DEFAULT,    DEFAULT`
   zlg004 = `089,062,222,008, VARYTEXT,     ddCritTxt, "%ddStatic%",      DEFAULT, 0, DEFAULT, DEFAULT,             DEFAULT,    DEFAULT`
   zlg005 = `089,072,222,042, DROPLISTBOX,  ddCrit,    "%ddCrit%",        DEFAULT, 1, DEFAULT, DEFAULT,             DEFAULT,    DEFAULT`
   zlg006 = `089,104,086,062, DROPLISTBOX,  ddFldList, "",                DEFAULT, 2, 4,       "Tahoma|6144|50|34", "0|0|0",    DEFAULT`
   zlg007 = `174,103,16,012,  PUSHBUTTON,   DEFAULT,   "Add",             3,       5, DEFAULT, "Tahoma|6656|40|34", "0|0|255",  DEFAULT`
   zlg008 = `195,104,100,062, DROPLISTBOX,  Classes,   "",                DEFAULT, 3, 4,       "Tahoma|6144|50|34", "0|0|0",    DEFAULT`
   zlg009 = `294,103,16,012,  PUSHBUTTON,   DEFAULT,   "Add",             4,       5, DEFAULT, "Tahoma|6656|40|34", "0|0|255",  DEFAULT`
   zlg010 = `089,094,100,012, STATICTEXT,   DEFAULT,   "Insert a field:", DEFAULT, 0, DEFAULT, "Tahoma|6144|50|34", "0|0|0",    DEFAULT`
   zlg011 = `195,094,100,012, STATICTEXT,   DEFAULT,   "Insert a Class:", DEFAULT, 0, DEFAULT, "Tahoma|6144|50|34", "0|0|0",    DEFAULT`
   
   zlgBtn=Dialog("zlg")
   return

;------------------------------------------------------------------------------------------
:WriteToFile
   verx=cGetInfo(0)
   Pad = 6+(maxLevel-1)*4
   wFile=FileOpen(fname,"WRITE")
            
   filewrite(wFile, "Control Manager version %verx%")
   filewrite(wFile, '')
   filewrite(wFile, '')
   filewrite(wFile, strcat(strfill(' ', Pad), '   ', strfix("Class"," ",26), ' ', strfix("ID"," ",7), ' ', strfix("TITLE", ' ', 45)))
   filewrite(wFile, strfill("-", Pad+83))
   
   binarypoke4(Tvi, iMask, 1)
   for wCnt = 0 to winCnts
      Level = Ary[wCnt, 0]
      if Level==1 then filewrite(wFile, '')
      binarypoke4(Tvi, iTreeItem, Ary[wCnt, 1])
      csendmessage(hTvw, 4364, 0, pTvi)  ; TVM_GETITEM
      sLen = binarypokestr(TextBuf, 0, strcat('L', Ary[wCnt, 0], ': C', Ary[wCnt, 6]))
      filewrite(wFile, strcat(strfix(strcat(strfill(' ', Level*4), binarypeekstr(TextBuf, 0, sLen)), ' ', Pad), '   ',  strfix(aryNfo[wCnt, 3], ' ', 26), ' ', strfix(aryNfo[wCnt, 2], ' ', 7), ' ', strfix(aryNfo[wCnt, 1], ' ', 45)))
   next
   fileclose(wFile)
   drop(wFile)
   
   if isdefined(Editor)
      clipput(fname)
      sendmenusto(Editor, 'File Open')
      sendkey('^v{ENTER}')
   else      
      run('Notepad.exe', fname)
   endif
   
   return

;------------------------------------------------------------------------------------------
:ShowControls
   Selected = udfLvGetSel(hLvw, @false)        ; Get a list of selected items.
   if Selected==-1 then return

   binarypoke4(Lvi, ilviSubItem, 7)            ; This sub-item is the index (window #) into aryNfo.
   sCnts = itemcount(Selected, tab)
   Nfo = ''
   sItem = -1
   for sCnt = 1 to sCnts
      sLen = csendmessage(hLvw, 4141, itemextract(sCnt, Selected, tab), pLvi) ; LVM_GETITEMTEXT
      Nfo = iteminsert(binarypeekstr(lviTextBuf, 0, sLen), -1, Nfo, tab)
   next
   
   winplace(0, -4, 1000, 20, thisTitle)
   f00 = 'Down: Next    Up: Previous    Escape: EXIT'
   boxcaption(1, f00)
   wfk = waitforkey('{DOWN}', '{UP}', '{ESC}', '', '')
   run(tmpWbt, '')
   while !winexist('ShowControl')
      yield
   endwhile
   hTmp = dllhwnd('ShowControl')   
   winactivate(f00)
   
   sCnt = 0
   while wfk!=3
      if wfk==1 then sCnt = sCnt+1
         else sCnt = sCnt-1
      if sCnt>sCnts then sCnt = 1
;       if sCnt==0 then sCnt = sCnts
      if sCnt<=0 then sCnt = sCnts
      Ndx = itemextract(sCnt, Nfo, tab)
      boxcaption(1, strcat('Class: ', aryNfo[Ndx, 3], '   ID: ', aryNfo[Ndx, 2], '   Title: ', aryNfo[Ndx, 1], '   X: ',aryNfo[Ndx, 9],'   width: ', aryNfo[Ndx, 11], '   Y: ', aryNfo[Ndx, 10], '   height: ', aryNfo[Ndx, 12]))
      DllCall(User32, long:"SetWindowPos", long:hTmp, long:0, long:aryNfo[Ndx, 9], long:aryNfo[Ndx,10], long:aryNfo[Ndx, 11], long:aryNfo[Ndx, 12], long:16)
      DllCall(User32, long:"SetCursorPos", long:aryNfo[Ndx, 9]+5, long:aryNfo[Ndx,10]+5)
      wfk = waitforkey('{DOWN}', '{UP}', '{ESC}', '', '')
   endwhile
   
   boxcaption(1, thisTitle)
   winplace(0, 0, 1000, 448, thisTitle)
   
   Sel = udfLvGetSel(hLvw, @true)
   binarypoke4(Lvi, ilviStateMask, 2)                          ; LVIS_SELECTED
   binarypoke4(Lvi, ilviState, 0)                              
   csendmessage(hLvw, 4139, Sel, pLvi)                         ; LVM_SETITEMSTATE
   binarypoke4(Lvi, ilviState, 2)                              
   for sCnt = 1 to sCnts
      csendmessage(hLvw, 4139, itemextract(sCnt, Selected, tab), pLvi)
      csendmessage(hLvw, 4139, itemextract(sCnt, Selected, tab), pLvi)
   next
   
   return

;------------------------------------------------------------------------------------------
:Init
   thisVer = 'AnalysisEx 1.0.5b'
   thisTitle = 'Window AnalysisEx'
   if winexist(thisTitle)
      winactivate(thisTitle)
      exit
   endif   

   :InitExtenders
   exclusive(@on)
   addextender("wwctl34i.dll")
   intcontrol(73,1,0,0,0)                    ; Use Goto ErrorHndlr
   gosub LoadStuff                           ; Load UDFs & message strings
   
   if winexist('WinEdit')
      Editor = '~WinEdit'
   else
      if winexist('WinBatch Studio') then Editor = '~WinBatch Studio'
   endif

   if winexist(Editor) then winiconize(Editor)
   WbtDir = filepath(IntControl(1004, 0, 0, 0, 0))
   dirchange(WbtDir)
   
   tmp = StrCat(`IntControl (12, 4, '', 0, 0)`, @CRLF)
   tmp = StrCat(tmp, `hWnd       = DllHwnd('')`, @CRLF)
   tmp = StrCat(tmp, `User32 = StrCat(DirWindows(1),"User32.dll")`, @CRLF)
   tmp = StrCat(tmp, `OldStyle   = DllCall(User32, long:"GetWindowLongA", long:hWnd, long:-16) ; GWL_STYLE=-16`, @CRLF)
   tmp = StrCat(tmp, `NewStyle = OldStyle & ~12582912  ; WS_CAPTION`, @CRLF)
   tmp = StrCat(tmp, `DllCall(User32, long:"SetWindowLongA", long:hWnd, long:-16, long:NewStyle) `, @CRLF)
   tmp = StrCat(tmp, ``, @CRLF)
   tmp = StrCat(tmp, `BoxesUp('250,490,500,510', @normal) `, @CRLF)
   tmp = StrCat(tmp, `BoxCaption(1, 'ShowControl')`, @CRLF)
   tmp = StrCat(tmp, `BoxColor(1, '255,0,0', 0)`, @CRLF)
   tmp = StrCat(tmp, `BoxDrawText(1, '0,0,1000,1000', ' ', @true, 5)`, @CRLF)
   tmp = StrCat(tmp, `while 1`, @CRLF)
   tmp = StrCat(tmp, `   yield`, @CRLF)
   tmp = StrCat(tmp, `   if winexist('%thisTitle%') then break`, @CRLF)
   tmp = StrCat(tmp, `endwhile   `, @CRLF)
   tmpWbt = 'tmp.wbt'
   tempF = fileopen(tmpWbt, 'WRITE')
   filewrite(tempF, tmp)
   fileclose(tempF)
   drop(tempF)
   
   Wins = WinItemize()
   if askyesno('Ok to Ignore', 'Duplicate, hidden and iconized windows will be removed from the list')==@yes
      AskMsg = 'Duplicate, hidden and iconized windows are not shown.'
      AskList = ''
      aCnts = itemcount(Wins, @tab)
      for aCnt = 1 to aCnts
         Win = itemextract(aCnt, Wins, @tab)
;          if (winstate(Win)!=-1 && winstate(Win)!=1) then AskList = iteminsert(Win, -1, AskList, @tab)
         if (winstate(Win)!=-1 && winstate(Win)!=1)
            if !itemlocate(Win, AskList, @tab) then AskList = iteminsert(Win, -1, AskList, @tab)
         endif
      next
   else
      AskMsg = 'Showing all windows.'
      Asklist = Wins
   endif
;    trgWnd = AskItemList("Choose a Window", a, @tab, @unsorted, @single)
   trgWnd = AskItemList(AskMsg, AskList, @tab, @sorted, @single)
   fname="%WbtDir%trash.txt"
   hWnd=DllHwnd(trgWnd)

   ; Some error checking from the help file to make sure we have a valid handle to the 
   ; target window.
   hwndChk = DLLhwnd(trgWnd)            
   Spec    = cWndGetWndSpec(hwndChk)         ; Get the window specification.
   hWnd    = cWndByWndSpec(%Spec%)           ; Get the handle by the window specification.
   if hWnd!=hwndChk                          ; Make sure the result matches the original handle 
      pause('ERROR!', "Could not get valid handle for %trgWnd% window.%@crlf%Exiting program.")
      clipput(Spec)
      goto Cancel
   endif  
   
   bHeight      = 72
   zlgBtn1      = 'Save Analysis'
   zlgBtn2      = 'Show Controls'
   zlgBtn3      = 'Refresh'
   zlgBtn4      = 'Close'
   zlgBtn5      = '+ / -'
   zlgBtn6      = 'Query'
   zlgMaxButton = 6
   Caption      = ''
   hMenu        = 0
   Pad          = 7
   CtlEntry     = strcat("long:", '"CreateWindowExA"')
   hInst        = dllhinst('')
   bTop         = 1000-Pad-bHeight
   
   Sep     = ','
   Sep2    = '|'
   Tab     = @tab
   User32  = strcat(dirwindows(1), "User32.DLL")
   Classes = ''

   :InitParent
   boxesup     ('0,0,1000,448', @NORMAL)
   boxtextcolor(1, '0,0,0')
   boxcaption  (1, thisTitle)
   BoxColor    (1, '192,192,192', 0)
   boxdrawrect (1, '0,0,1000,1000', 2)   

   BoxButtonDraw(1, 1, zlgBtn1, udfMakeRect(Pad,bTop,163,bHeight,0))
   BoxButtonDraw(1, 2, zlgBtn2, udfMakeRect(Pad+164,bTop,163,bHeight,0))
   BoxButtonDraw(1, 3, zlgBtn3, udfMakeRect(Pad+328,bTop,163,bHeight,0))
   BoxButtonDraw(1, 4, zlgBtn4, udfMakeRect(1000-2*Pad-72,bTop,72,bHeight,0))
   BoxButtonDraw(1, 5, zlgBtn5, udfMakeRect(Pad+592,bTop,60,bHeight,0))
   BoxButtonDraw(1, 6, zlgBtn6, udfMakeRect(Pad+700,bTop,100,bHeight,0))
   
   :InitBuffers
   ; Treeview structures and text buffers.
   Tvi      = binaryalloc(40)
   pTvi     = IntControl(42, Tvi, 0, 0, 0)
   MaxText  = 128
   TextBuf  = binaryalloc(MaxText)
   pTextBuf = IntControl(42, TextBuf, 0, 0, 0)    ; Get a pointer to the buffer.
   Tvins    = binaryalloc(48)
   pTvins   = IntControl(42, Tvins, 0, 0, 0)

   ; Listview structures and text buffers.
   Lvi         = binaryalloc(36)
   pLvi        = IntControl(42, Lvi, 0, 0, 0)
   lviMaxText  = 128
   lviTextBuf  = binaryalloc(lviMaxText)
   plviTextBuf = IntControl(42, lviTextBuf, 0, 0, 0)     ; Get a pointer to the text buffer.
   ; Listview columns
   lvhTextMax  = 64
   lvhTextBuf  = binaryalloc(lvhTextMax)
   plvhTextBuf = IntControl(42, lvhTextBuf, 0, 0, 0)     ; Get ptr to binary buffer.
   Lvcol       = binaryalloc(24)
   pLvcol      = IntControl(42, Lvcol, 0, 0, 0)
      
   Rect = binaryalloc(16)
   pRect = IntControl(42, Rect, 0, 0, 0)

   ; Offsets for TV_ITEM
   iMask          = 0
   iTreeItem      = 4
   iState         = 8
   iStateMask     = 12
   ipTextBuf      = 16
   iMaxText       = 20
   iImage         = 24
   iSelectedImage = 28
   iChildren      = 32
   iParam         = 36

   ; Offsets for TV_INSERTSTRUCT
   iParent      = 0
   iInsertAfter = 4
   iTvi         = 8                    ; TV_INSERTSTRUCT contains a copy of TV_ITEM

   ; Offsets for LV_ITEM
   iMask         = 0      
   ilviItem      = 4     
   ilviSubItem   = 8  
   ilviState     = 12  
   ilviStateMask = 16
   iplviTextBuf  = 20
   ilviTextMax   = 24
   ilviImage     = 28 
   ilviParam     = 32 

   binarypoke4(Tvi, ipTextBuf, pTextBuf)      
   binarypoke4(Tvi, iMaxText, MaxText)      
   
   ; Default values for LvInsertItem
   binarypoke4(Lvi, iMask, 15)         ; LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM|LVIF_STATE
   binarypoke4(Lvi, ilviItem, 0)      
   binarypoke4(Lvi, ilviSubItem, 0)      
   binarypoke4(Lvi, ilviState, 0)      
   binarypoke4(Lvi, ilviStateMask, 0)      
   binarypoke4(Lvi, iplviTextBuf, plviTextBuf)      
   binarypoke4(Lvi, ilviTextMax, lviMaxText)      
   binarypoke4(Lvi, ilviImage, 0)      
   binarypoke4(Lvi, ilviParam, 0)      

   :InitControls
   xSpec = udfGetSpec('', 0)
   ySpec = udfGetSpec('', 1)
   
   hParent   = DllHwnd('')
   dwExStyle = 512                     ; WS_EX_CLIENTEDGE
   dwStyle   = 1073938471              ; WS_CHILD|WS_GROUP|WS_TABSTOP|TVS_HASBUTTONS|TVS_HASLINES|TVS_LINESATROOT|TVS_SHOWSELALWAYS
   CtlClass  = 'SysTreeView32'
   xP        = int(Pad*xSpec)     
   cxP       = int(150*xSpec) 
   yP        = int((Pad+58)*ySpec)     
   cyP       = int((1000-bHeight-4*Pad-58)*ySpec) 
   hCtl      = 'hTvw'
   gosub CtlSet

   dwStyle   = 1073938441              ; WS_CHILD|WS_GROUP|WS_TABSTOP|LVS_REPORT|LVS_SHOWSELALWAYS
   CtlClass  = 'SysListView32'
   xP        = int((Pad+150)*xSpec)     
   cxP       = int((1000-3*Pad-150)*xSpec) 
   yP        = int(Pad*ySpec)     
   cyP       = int((1000-bHeight-4*Pad)*ySpec) 
   hCtl      = 'Lvw1'
   gosub CtlSet
   hLvw = Lvw1
   gosub InsertColumnHeader      
   csendmessage(hLvw, 4150, 0, csendmessage(hLvw, 4151, 0, 0)|16416) ; LVS_EX_FULLROWSELECT|LVS_EX_LABELTIP=16416

   hCtl      = 'Lvw2'
   gosub CtlSet
   hLvw = Lvw2
   gosub InsertColumnHeader      
   csendmessage(hLvw, 4150, 0, csendmessage(hLvw, 4151, 0, 0)|16416) ; LVS_EX_FULLROWSELECT|LVS_EX_LABELTIP=16416

   wsDefault = 1342373888     ; WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_GROUP    
   dwStyle   = 1342382080     ; wsDefault|ES_NUMBER
   CtlClass  = 'Edit'
   xP = int((Pad+655)*xSpec)     
   cxP = int(40*xSpec) 
   yP = int((1000-pad-bHeight)*ySpec)
   cyP = int(bHeight*ySpec)
   hCtl      = 'hEd'
   gosub CtlSet

   udsDefault = 167  ; UDS_ALIGNRIGHT|UDS_ARROWKEYS|UDS_NOTHOUSANDS|UDS_SETBUDDYINT|UDS_WRAP
   dwExStyle  = 0
   dwStyle    = 1342308519    ; wsDefault|udsDefault&~WS_TABSTOP
   CtlClass   = "msctls_updown32"
   xP         = 0   
   hCtl       = 'hUd'
   gosub CtlSet
   csendmessage(hUd, 1129, hEd, 0)   ; UDS_SETBUDDY

   :InitArrays
;    Ary  = arrdimension(300, 7, 0, 0, 0)
   Ary  = arrdimension(600, 7, 0, 0, 0)
   ArrInitialize(Ary, 0)
   aryNfo = arrdimension(600, 13, 0, 0, 0)   

   aryLv  = arrdimension(600, 2, 0, 0, 0)
   arrinitialize(aryLv, '')
   LvCnt = -1
   
   drop(a, Args, bHeight)
   drop(bTop, Caption, Close, CtlEntry, hInst, hMenu)
   drop(lParam, Pad, hwndChk, Spec)
   drop(CtlClass, cxP, cyP, dwExStyle, dwStyle, hCtl)
   drop(xP, xSpec, yP, ySpec)

   hLvw = Lvw1          ; Makes Lvw1 the displayed listview.
   hNext = hLvw         ; One time only setting.

   return

;------------------------------------------------------------------------------------------
:InsertColumnHeader
   binarypoke4(Lvcol,  0, 15)             ; Flags valid attributes to: LVCF_FMT|LVCF_SUBITEM|LVCF_TEXT|LVCF_WIDTH  
   binarypoke4(Lvcol,  4, 0)              ; LVCFMT_LEFT                                
   binarypoke4(Lvcol, 12, plvhTextBuf)
   binarypoke4(Lvcol, 16, 64)

;    Headers = 'Title,200|ID,%lvhTextMax%|Class,%lvhTextMax%|WndStyle,%lvhTextMax%|WndStyleEx,%lvhTextMax%|ClassStyle,%lvhTextMax%|Window,%lvhTextMax%|Visible,%lvhTextMax%'
   Headers = 'sessHndl,%lvhTextMax%|Title,200|ID,%lvhTextMax%|Class,%lvhTextMax%|WndStyle,%lvhTextMax%|WndStyleEx,%lvhTextMax%|ClassStyle,%lvhTextMax%|Window,%lvhTextMax%|Visible,%lvhTextMax%'
   hCnts = itemcount(Headers, '|')-1
   for ichSubItem = 0 to hCnts
      Header = itemextract(ichSubItem+1, Headers, '|')
      ichLabel = itemextract(1, Header, ',')
      binarypokestr(lvhTextBuf, 0, ichLabel)
      LblLen = strlen(ichLabel)
      if LblLen<lvhTextMax then binarypoke(lvhTextBuf, LblLen, 0)
      binarypoke4(Lvcol,  8, itemextract(2, Header, ','))
      binarypoke4(Lvcol, 20, ichSubItem)
      cSendMessage(hLvw, 4123, ichSubItem, pLvcol)    ; LVM_INSERTCOLUMN=4123
   next   
  
   return


;------------------------------------------------------------------------------------------
:LvInsertItem
   LvCnt = LvCnt+1   
   aryLv[LvCnt, 0] = Cnt
   aryLv[LvCnt, 1] = newNode
   
   ; Zero based indexing has its advantages, twit, the item count is the index of the new item.
   binarypoke4(Lvi, iMask, 5)                                              ;LVIF_TEXT|LVIF_PARAM
   binarypoke4(Lvi, ilviParam, Cnt) 
   binarypoke4(Lvi, ilviItem, cSendMessage(hNext, 4100, 0, 0))             ;LVM_GETITEMCOUNT=4100
   insCnt = arrinfo(aryNfo, 2)-1
   for ins = 0 to insCnt
      if strlen(aryNfo[Cnt, ins])>=lviMaxText
         insLen = binarypokestr(lviTextBuf, 0, strfix(aryNfo[Cnt, ins], '', lviMaxText-1))
      else
         insLen = binarypokestr(lviTextBuf, 0, aryNfo[Cnt, ins])
      endif
      binarypoke(lviTextBuf, insLen, 0)
      binarypoke4(Lvi, ilviSubItem, ins)      
      if ins==0 then cSendMessage(hNext, 4103, 0, pLvi)                     ;LVM_INSERTITEM=4103
         else cSendMessage(hNext, 4142, binarypeek4(Lvi, ilviItem), pLvi)   ;LVM_SETITEMTEXT=4142
   next
   return

;------------------------------------------------------------------------------------------
:CtlSet
   lpClassName    = "%CtlClass%"
   hMenu          = hMenu+1
   
   Args = "long:dwExStyle"
   Args = StrCat(Args, ", lpstr:lpClassName")
   Args = StrCat(Args, ", lpstr:Caption")          ; Caption
   Args = StrCat(Args, ", long:dwStyle")
   Args = StrCat(Args, ", long:xP")
   Args = StrCat(Args, ", long:yP")
   Args = StrCat(Args, ", long:cxP")               ; Width of control.
   Args = StrCat(Args, ", long:cyP")               ; Height of control.
   Args = StrCat(Args, ", long:hParent")
   Args = StrCat(Args, ", long:hMenu")
   Args = StrCat(Args, ", long:hInst")
   Args = StrCat(Args, ", long:0")

   %hCtl% = DLLCall(User32, %CtlEntry%, %Args%)
   Caption = ''

   return

;------------------------------------------------------------------------------------------
:GetWndInfo
   cTitle           = cWndInfo(WorkWnd, 0)       
   cID              = cWndInfo(WorkWnd, 1)  
   cClass           = cWndInfo(WorkWnd, 2)  
   cParent          = cWndInfo(WorkWnd, 3)  
   cFirstSibling    = cWndInfo(WorkWnd, 4)  
   cPreviousSibling = cWndInfo(WorkWnd, 5)  
   NextSibling      = cWndInfo(WorkWnd, 6)  
   cLastSibling     = cWndInfo(WorkWnd, 7)  
   FirstChild       = cWndInfo(WorkWnd, 8)  
   cOwner           = cWndInfo(WorkWnd, 9)  
   cWndStyle        = cWndInfo(WorkWnd, 20) 
   cWndStyleEx      = cWndInfo(WorkWnd, 21) 
   cClassStyle      = cWndInfo(WorkWnd, 22) 

   if cTitle=='' then cTitle = '   -'
   f00  = dllcall(User32, long:"GetWindowRect", long:WorkWnd, lpbinary:Rect)
   
   aryNfo[Cnt, 0]  = WorkWnd
   aryNfo[Cnt, 1]  = cTitle
   aryNfo[Cnt, 2]  = cID
   aryNfo[Cnt, 3]  = cClass
   aryNfo[Cnt, 4]  = cWndStyle
   aryNfo[Cnt, 5]  = cWndStyleEx
   aryNfo[Cnt, 6]  = cClassStyle
   aryNfo[Cnt, 7]  = Cnt
   aryNfo[Cnt, 8]  = dllcall(User32, long:"IsWindowVisible", long:WorkWnd)
   aryNfo[Cnt, 9]  = binarypeek4(Rect, 0)
   aryNfo[Cnt, 10] = binarypeek4(Rect, 4)
   aryNfo[Cnt, 11] = binarypeek4(Rect, 8)-binarypeek4(Rect, 0)
   aryNfo[Cnt, 12] = binarypeek4(Rect, 12)-binarypeek4(Rect, 4)
   
   if !itemlocate(cClass, Classes, @tab) then Classes = iteminsert(cClass, -1, Classes, @tab)
   return

;------------------------------------------------------------------------------------------
:LoadStuff
; call('udfGetHWnd.udl', '')
:udfGetHWnd
#definefunction udfGetHWnd(hApp, Eval)
   IntControl(73,1,0,0,0)     ; Use gosub ErrorHndlr
   AddExtender("wwctl34i.dll")
   
   if Eval=='' then return 0
   if hApp!=0 && hApp!=''
      WorkWnd = hApp
   else
      return 0
   endif
   
   rTitle           = 0
   rID              = 1
   rClass           = 2
   rParent          = 3
   rFirstSibling    = 4
   rPreviousSibling = 5
   rNextSibling     = 6
   rLastSibling     = 7
   rFirstChild      = 8
   rOwner           = 9
   rWndStyle        = 20
   rWndStyleEx      = 21
   rClassStyle      = 22
   
   Sep = ','
   Siblings = ''
   testCnts = itemcount(Eval, '?')
   
   gosub GetWndInfo
   gosub Eval
   if Tests then return WorkWnd
   if !FirstChild then return 0
   
   while FirstChild || itemcount(Siblings, Sep)
      while FirstChild
         WorkWnd = FirstChild
         gosub GetWndInfo
         gosub Eval
         if Tests then return WorkWnd
         if NextSibling then Siblings = iteminsert(NextSibling, -1, Siblings, Sep)
      endwhile ; FirstChild
      
      Sib = itemcount(Siblings, Sep)
      if Sib
         WorkWnd = itemextract(Sib, Siblings, Sep)
         Siblings = itemremove(Sib, Siblings, Sep)
         gosub GetWndInfo
         gosub Eval
         if Tests then return WorkWnd
         if NextSibling then Siblings = iteminsert(NextSibling, -1, Siblings, Sep)
      endif
   endwhile
   return 0

   ;---------------------------------------------------------------------------------------
   :GetWndInfo
      Title           = cWndInfo(WorkWnd, 0)       
      ID              = cWndInfo(WorkWnd, 1)  
      Class           = cWndInfo(WorkWnd, 2)  
      Parent          = cWndInfo(WorkWnd, 3)  
      FirstSibling    = cWndInfo(WorkWnd, 4)  
      PreviousSibling = cWndInfo(WorkWnd, 5)  
      NextSibling     = cWndInfo(WorkWnd, 6)  
      LastSibling     = cWndInfo(WorkWnd, 7)  
      FirstChild      = cWndInfo(WorkWnd, 8)  
      Owner           = cWndInfo(WorkWnd, 9)  
      WndStyle        = cWndInfo(WorkWnd, 20) 
      WndStyleEx      = cWndInfo(WorkWnd, 21) 
      ClassStyle      = cWndInfo(WorkWnd, 22) 
      return

   ;---------------------------------------------------------------------------------------
   :Eval
   Tests = @false
   ; testCnts = itemcount(Eval, '?') - initialized on entry.
   for testCnt = 1 to testCnts
      Query = itemextract(testCnt, Eval, '?')
      if testCnt==1
         if %Query% then Tests = @true
      else
         qHndl = itemextract(1, Query, '|')
         if %qHndl%==0
            Tests = @false
         else
            Rqst = itemextract(2, Query, '|')
            TestFor = itemextract(3, Query, '|')
            Tests = cwndinfo(%qHndl%, %Rqst%)%TestFor%
         endif
      endif
      if !Tests then break
   next
   return

   ;-------------------------------------------------------------------
   :WBErrorHandler
      WbtDir = filepath(IntControl(1004, 0, 0, 0, 0))
      dirchange(WbtDir)

      wErrFile = 'udfGetHWnd 1.0.1'
      wError=LastError()
      
      if wError==204 then return
      
      wErrStr = IntControl(34,wError,0,0,0)
      wErrLine = wberrorhandlerline
      wErrOffset = wberrorhandleroffset
      wErrAssign  = wberrorhandlerassignment
      wErrRptFile = strcat(wbtDir, 'Error.txt')
      wErrMessage = 'Please email this file:%@CRLF%%@tab%"%wErrRptFile%"%@CRLF%to gvag@shaw.ca with the Subject line "AnalysisEx Error"'
      wErrTxt = strCat(`wErrFile = `, wErrFile, @CRLF, `wError = `, wError, @CRLF, `wErrStr = `, wErrStr, @CRLF, `wErrLine = `, wErrLine, @CRLF, `wErrOffset = `, wErrOffset, @CRLF, `wErrAssign = `, wErrAssign, @CRLF, @CRLF, wErrMessage)   
      
      fw = fileopen(wErrRptFile, 'WRITE')
      filewrite(fw, wErrTxt)
      fileclose(fw)
      run('NotePad.exe', wErrRptFile)
      clipput(wErrTxt)
      return
      
#endfunction

;------------------------------------------------------------------------------------------
:zlg
#definesubroutine zlg(zlgHndl, zlgEvent, zlgControlID, param4, param5)
   IntControl(73,1,0,0,0)   ; Use Goto ErrorHndlr
   InitDialog  = 0
   BtnPush     = 2
   select zlgEvent
      case InitDialog
         winzoom(thisTitle)
         RetVal      = -2
         zlgContinue = 1
         zlgQuit     = 2
         zlgText     = 3
         zlgCrit     = 4
         CritCbx     = 5
         hCritTbx    = udfGetHWnd(zlgHndl, 'ID==1001')
         FldCbx      = 6
         zlgAddFld   = 7
         ClsCbx      = 8 
         zlgAddCls   = 9
         ddCrits     = ''
         
         dialogprocoptions(zlgHndl, BtnPush, 1)   
         dialogcontrolset(zlgHndl, zlgText, 3, ddMsg)
         dialogcontrolset(zlgHndl, FldCbx, 5, ddFlds)
         dialogcontrolset(zlgHndl, FldCbx, 6, itemextract(1, ddFlds, @tab))
         dialogcontrolset(zlgHndl, ClsCbx, 5, Classes)
         dialogcontrolset(zlgHndl, ClsCbx, 6, itemextract(1, Classes, @tab))
         break
      
      case BtnPush
         Btn = zlgControlID
         select Btn
            case zlgContinue     
               ddCrit = cgetedittext(hCritTbx) 
               ddHndl = udfGetHWnd(hWnd, ddCrit)
               ddText = strCat(`Criteria:`, ddCrit, `   Handle returned: `, ddHndl)
               dialogcontrolset(zlgHndl, zlgCrit, 4, ddText)
               ddNdx = itemlocate(strlower(ddCrit), strlower(ddCrits), @tab)
               if !ddNdx
                  ddCrits =iteminsert(ddCrit, 0, ddCrits, @tab)
               else
                  ddCrits = itemremove(ddNdx, ddCrits, @tab)
               endif      
               dialogcontrolset(zlgHndl, CritCbx, 5, ddCrits)
               return -2
               break
            
            case zlgQuit     
               RetVal = -1
               winshow(thisTitle)
               break
            
            case zlgAddFld   
               ddCrit = cgetedittext(hCritTbx) 
               csetedittext(hCritTbx, strcat(ddCrit, dialogcontrolget(zlgHndl, FldCbx, 6)))
               RetVal = -2
               break
            
            case zlgAddCls   
               ddCrit = cgetedittext(hCritTbx) 
               csetedittext(hCritTbx, strcat(ddCrit, '"', dialogcontrolget(zlgHndl, ClsCbx, 6), '"'))
               RetVal = -2
               break
         endselect
         if Btn==3 then break   
   endselect
   return RetVal

   ;------------------------------------------------------------------------------------------
   :WBERRORHANDLER
   wErrFile = 'Query Dialog'
   wError=LastError()
   wErrStr = IntControl(34,wError,0,0,0)
   wErrLine = wberrorhandlerline
   wErrOffset = wberrorhandleroffset
   wErrAssign  = wberrorhandlerassignment
   wErrRptFile = strcat(wbtDir, 'QueryDlg')
   wErrMessage = 'Please email this file:%@CRLF%%@tab%"%wErrRptFile%"%@CRLF%to gvag@shaw.ca with the Subject line "AnalysisEx Error"'
   wErrTxt = strCat(`wErrFile = `, wErrFile, @CRLF, `wError = `, wError, @CRLF, `wErrStr = `, wErrStr, @CRLF, `wErrLine = `, wErrLine, @CRLF, `wErrOffset = `, wErrOffset, @CRLF, `wErrAssign = `, wErrAssign, @CRLF, @CRLF, wErrMessage)   
   fw = fileopen(wErrRptFile, 'WRITE')
   filewrite(fw, wErrTxt)
   fileclose(fw)
   run('NotePad.exe', wErrRptFile)
   return 1

#endsubroutine

;------------------------------------------------------------------------------------------
:udfLvGetSel 
#definefunction udfLvGetSel(hLvw, FirstOnly)
   selCnts = csendmessage(hLvw, 4146, 0, 0) ; LVM_GETSELECTEDCOUNT
   if selCnts==0
      return -1
   endif   
   
   Cnts = csendmessage(hLvw, 4100, 0, 0)-1 ; LVM_GETITEMCOUNT
   if FirstOnly then goto FirstOnly

   Sels = ''
   for Cnt = 0 to Cnts
      if csendmessage(hLvw, 4140, Cnt, 2)==2    ; LVM_GETITEMSTATE=4140, LVNI_SELECTED=2
         Sels = iteminsert(Cnt, -1, Sels, @tab)
      endif
   next
   return Sels
      
   :FirstOnly
   for Cnt = 0 to Cnts
      if csendmessage(hLvw, 4140, Cnt, 2)==2 then return Cnt
   next

#endfunction


;------------------------------------------------------------------------------------------
:udfTvGetParam
#definefunction udfTvGetParam(hTvw, Tvi, hItem)
   binarypoke4(Tvi, 0, 4)
   binarypoke4(Tvi, 4, hItem)
   ; TVM_GETITEM = 4364
   if !dllcall(strcat(dirwindows(1), "User32.DLL"), long:"SendMessageA", long:hTvw, long:4364, long:hItem, lpbinary:Tvi) then return -1
   return binarypeek4(Tvi, 36)
#endfunction

;------------------------------------------------------------------------------------------
:udfHideCtl
#definefunction udfHideCtl(hWnd, Hide)
   if Hide 
      Show = 128
   else   
      Show = 64
   endif
   hZOrder   = 0
   ; if uFlags includes swpNoSize && swpNoMove all positioning info is ignored so...
   uFlags    = Show|3   ; swpNoSize=1 swpNoMove=2
   rtn = udfSetWinPos(hWnd, hZOrder, 0, 0, 0, 0, uFlags) 
   return rtn
#endfunction

;------------------------------------------------------------------------------------------
:udfSetWinPos
#definefunction udfSetWinPos(hWnd, hZOrder, xP, yP, cxP, cyP, uFlags)
   User32   = StrCat(DirWindows(1), "User32.DLL")
   swpEntry = 'word:"SetWindowPos"'
   
   swpArgs = StrCat(`long:hWnd`)
   swpArgs = StrCat(swpArgs, `,long:hZOrder`)
   swpArgs = StrCat(swpArgs, `,word:xP`)
   swpArgs = StrCat(swpArgs, `,word:yP`)
   swpArgs = StrCat(swpArgs, `,word:cxP`)
   swpArgs = StrCat(swpArgs, `,word:cyP`)
   swpArgs = StrCat(swpArgs, `,word:uFlags`)
   
   rtn = dllcall(User32, %swpEntry%, %swpArgs%)
   return rtn
#endfunction

;------------------------------------------------------------------------------------------
:udfGetWinRect
#definefunction udfGetWinRect(WndName, Rqst) ; as Long
   User32 = strcat(DirWindows(1), 'User32.dll')
   select Rqst
      case 0
         Entry = '"GetWindowRect"'
         break
      case 1
         Entry = '"GetClientRect"'
         break
      case Rqst
         return 0
   endselect  
   
   rtn = 0
   Rect = binaryalloc(16)
   hWnd = dllhwnd(WndName)
   if hWnd==0 || hWnd==-1 then goto Free
   
   Rtn = DllCall(User32, long:%Entry%, long:hWnd, lpbinary:Rect)
   binaryeodset(Rect, 16)
   rtn = ''
   for cnt = 0 to 3
      rtn =  iteminsert(binarypeek4(Rect, cnt*4), -1, rtn, ',')
   next
:Free   
   binaryfree(Rect)
   return rtn   
#endfunction

;------------------------------------------------------------------------------------------
:udfGetSpec
#definefunction udfGetSpec(WndName, Rqst)
   ; ***GATHER***    call('Controls.udl', 'udfGetWinRect')
   Rect =  udfGetWinRect(WndName, 1)      ; Get client area.
   ; Client width or height in pixels.
   Spec = itemextract(Rqst+3, Rect, ',') - itemextract(Rqst+1, Rect, ',') + .0
   Spec = Spec/1000
   return Spec
#endfunction

;------------------------------------------------------------------------------------------
:udfMakeRect
#definefunction udfMakeRect(x, y, cx, cy, Nudge)
   ; ***GATHER***    call('Controls.udl', 'udfGetSpec')
   if !Nudge
      cx   = x+cx
      cy   = y+cy
      return '%x%,%y%,%cx%,%cy%'
   endif
   if isint(Nudge)
      hSpec = udfGetSpec('', 0)
      hNudge = hSpec*Nudge
      hNudge = int(hNudge)
      if hNudge then inc = hNudge/abs(hNudge)   ; Divide by zero? no thanks!
      if hNudge mod 2 then hNudge = hNudge+inc
      hNudge = int(hNudge/hSpec)
      if hNudge mod 2 then hNudge = hNudge+inc
    
      vSpec = udfGetSpec('', 1)
      vNudge = hSpec*Nudge
      vNudge = int(vNudge)
      if vNudge then inc = vNudge/abs(vNudge)
      if vNudge mod 2 then vNudge = vNudge+inc
      vNudge = int(vNudge/hSpec)
      if vNudge mod 2 then vNudge = vNudge+inc
      hNudgit = hNudge/2
      vNudgit = vNudge/2
      select 1
         case cx>0
            x = x-hNudgit
            cx = x+cx+hNudge
            continue
         case cy>0
            y = y-vNudgit
            cy = y+cy+vNudge
            continue
         case cx<0
            x = x+hNudgit
            cx = -hNudge+x+cx
            continue
         case cy<0
            y = vNudgit+y
            cy = -vNudge+y+cy
            continue
      endselect      
      return '%x%,%y%,%cx%,%cy%'
   else
      x1 = x-int(cx*Nudge)
      y1 = y-int(cy*Nudge)
      cx1 = x+int(cx*Nudge+cx)
      cy1 = y+int(cy*Nudge+cy)
      return '%x1%,%y1%,%cx1%,%cy1%'
   endif   
#endfunction

; Hide this clutter stuff way down here.
ddMsg=StrCat(`The Fields ListBox contains the fields available for a query.  A '*' prefix indicates a handle to another control.`, @CRLF)
ddMsg=StrCat(ddMsg, `   Title     *FirstSibling      *LastSibling    WndStyle   `, @CRLF)
ddMsg=StrCat(ddMsg, `   ID        *PreviousSibling   *FirstChild     WndStyleEx`, @CRLF)
ddMsg=StrCat(ddMsg, `   Class     *NextSibling       *Owner          ClassStyle`, @CRLF)
ddMsg=StrCat(ddMsg, `  *Parent`, @CRLF)
ddMsg=StrCat(ddMsg, `In addition the Classes ListBox contains all the unique classes found in the application.  Clicking the "Add" button will append the selected item to your query.  Classes will be inserted as quoted strings, e.g. "Edit".`, @CRLF)
ddMsg=StrCat(ddMsg, ``, @CRLF)
ddMsg=StrCat(ddMsg, `These examples use the two Edit controls found in Studio's Output window.  A simple query:`, @CRLF)
ddMsg=StrCat(ddMsg, `      udfGetHWnd( hApp, ``Id==1047``)`, @CRLF)
ddMsg=StrCat(ddMsg, `but what if the EvilApp doesn't have unique control IDs?`, @CRLF)
ddMsg=StrCat(ddMsg, `      udfGetHWnd( hApp, ``Class=="Edit"  && NextSibling!=0``)`, @CRLF)
ddMsg=StrCat(ddMsg, `gets the first Edit control and`, @CRLF)
ddMsg=StrCat(ddMsg, `      udfGetHWnd( hApp, ``Class=="Edit"  && NextSibling==0``)`, @CRLF)
ddMsg=StrCat(ddMsg, `gets the next.`, @CRLF)
ddMsg=StrCat(ddMsg, ``, @CRLF)
ddMsg=StrCat(ddMsg, `Sometimes there is a need to refer to an attribute of a parent or sibling window.  In this case you can create complex queries that eliminate the repeated calls that drilling down sometimes requires:`, @CRLF)
ddMsg=StrCat(ddMsg, `      udfGetHWnd( hApp,``Class=="Edit"?NextSibling|rClass|=="Edit"``)`, @CRLF)
ddMsg=StrCat(ddMsg, `may do the trick.  How it works.`, @CRLF)
ddMsg=StrCat(ddMsg, ``, @CRLF)
ddMsg=StrCat(ddMsg, `Eval may contain additional tests delimited by "?".  If the first test is successful, the three parameters of subsequent items are substituted as follows:`, @CRLF)
ddMsg=StrCat(ddMsg, `      Tests = cWndInfo(%%qHndl%%, %%Rqst%%)%%TestFor%%`, @CRLF)
ddMsg=StrCat(ddMsg, `udfGetHWnd defines variables for each of the request codes supported by cWndInfo, just prepend an "r" to the field name.`, @CRLF)

ddFlds = StrCat('Title', @tab,'FirstSibling', @tab, 'LastSibling', @tab, 'WndStyle', @tab)
ddFlds = StrCat(ddFlds, 'ID', @tab, 'PreviousSibling', @tab, 'FirstChild', @tab, 'WndStyleEx', @tab)
ddFlds = StrCat(ddFlds, 'Class', @tab, 'NextSibling', @tab, 'Owner', @tab, 'ClassStyle', @tab, 'Parent')
ddFlds = itemsort(ddFlds, @tab)

return ; to Init

;------------------------------------------------------------------------------------------
; weuglLabelLines=:UpdateViews:Swap:InsertNode:UpdateLabels:GetAttributes:Main:Loop:Cancel:WBERRORHANDLER:DrillDown:WriteToFile:ShowControls:Init:InitExtenders:InitParent:InitBuffers:InitControls:InitArrays:InsertColumnHeader:LvInsertItem:CtlSet:GetWndInfo:LoadStuff:udfGetHWnd:GetWndInfo:Eval:WBErrorHandler:zlg:WBERRORHANDLER:udfLvGetSel:FirstOnly:udfTvGetParam:udfHideCtl:udfSetWinPos:udfGetWinRect:Free:udfGetSpec:udfMakeRect;***LABEL LIST***

Article ID:   W15829
File Created: 2017:07:28:13:58:24
Last Updated: 2004:03:30:15:41:00