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

Sample code
plus

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

Determining if Check Boxes are Checked LONG ANSWER

Keywords: 	 Determining if Check Boxes are Checked  LONG ANSWER

; This is an example of sending mouse clicks to controls in a dialog box.
; Some message numbers, obtained from the WINDOWS.H header file.
BMGETCHECK    = 1024
BMSETCHECK    = 1025
WMLBUTTONDOWN =  513
WMLBUTTONUP   =  514
Run("notepad.exe", "")
SendMenusTo("Notepad", "Search | Find")
; Get window handle of "Find" dialog.
hWnd = DllHwnd("Find")
If hWnd == 0
  Message("Error", "Parent window not found")
  Goto cancel
Endif
; We will be using several functions from this DLL.
dll = DllLoad("user.exe")
; Allocate a binary buffer.
buffer = BinaryAlloc(80)
; This is just for visual demonstration purposes.  It is not needed.
WinActivate("Find")
; All the Delay's are just so you can see what is happening.  Not needed.
Delay(1)
; This call finds the first child window belonging to the specified parent.
; We won't need the paren't handle anymore, so we'll just re-use the hWnd
; variable.  GetWindow, last parm == 5, means find first child of this parent.
hWnd = DllCall(dll, word:"GetWindow", word:hWnd, word:5)
; We will keep a running sequence.
i = 0
; Keep looping until we run out of children.
While hWnd != 0
  ; We will go through this loop for each child window (control) in the dialog.
  i = i + 1
  ; Get the text associated with this child window (a control of some sort),
  ; and store it in our binary buffer.  The last parameter is the max length.
  len = DllCall(dll, word:"GetWindowText", word:hWnd, lpbinary:buffer, word:80)
  ; Set the BinaryEod to the length of the string we got back.
  BinaryEodSet(buffer, len)
  ; Get the contents of the binary buffer into a string.
  text = BinaryPeekStr(buffer, 0, len)
  ; Remove the '&' from the text.  The programmer puts an '&' in front of
  ; the character he wants underlined, so "Cancel" would look like "&Cancel".
  text = StrReplace(text, "&", "")
  ; Trim off any leading or trailing spaces.
  text = StrTrim(text)
  ; Now we have the name of the control.  If you want, you can use StrLower
  ; to make it lower case, or use StrCmpi to do a case-insensitive comparison,
  ; but in this example we will do a case-sensitive comparison because we know
  ; exactly what we are looking for.  We are looking for 4 different controls
  ; to play with here; if you are just trying to modify a single control, your
  ; If...Else structure will be much less complicated.
  ; Un-comment to display the control's sequence and text, for demo purposes.
  ;Display(1, i, text)
  ; This is a checkbox.
  If text == "Match Case"
    ; We will see if it is checked.  The last 2 parameters of BM_GETCHECK are
    ; both always 0.
    chk=DllCall(dll,long:"SendMessage",word:hWnd,word:BMGETCHECK,word:0,long:0)
    ; And we will toggle the current state.  If all you want to do is
    ; unconditionally check or uncheck it, you do not need the previous
    ; command, and you do not need an If...Else statement here.  Just do it.
    ; You will notice that we are using an IntControl here to send the message
    ; instead of using DllCall.  The only reason we used DllCall to send the
    ; previous BM_GETCHECK message was because we needed to get a return value,
    ; and IntControl(23) doesn't receive a return value.  But when we send the
    ; BM_SETCHECK message, we don't care about the return value, so it is
    ; easier and more efficient to use the IntControl.  The last parameter of
    ; BM_SETCHECK is always 0.
    If chk == @OFF
      IntControl(23, hWnd, BMSETCHECK, @ON, 0)
    Else
      IntControl(23, hWnd, BMSETCHECK, @OFF, 0)
    Endif
    Delay(1)
  Else
    ; This is a set of two radio buttons, and is a little more complicated,
    ; because if you check one, you should uncheck the other(s) in the set.
    ; When you do it with the mouse or keyboard, this happens automatically,
    ; but we will have to do it manually.  We want to check the "Up" button.
    If text == "Up"
      IntControl(23, hWnd, BMSETCHECK, @ON, 0)
      Delay(1)
    Else
      ; Actually, you really don't need to uncheck the "Down" button, because
      ; internally it has been de-selected, but it looks kind of funny to have
      ; them both checked on the screen.  It's your choice.  We'll uncheck it.
      If text == "Down"
        IntControl(23, hWnd, BMSETCHECK, @OFF, 0)
        Delay(1)
      Else
        ; Now let's press the Cancel button.
        If text == "Cancel"
          ; The first parameter for WM_LBUTTONDOWN is the state of the shift
          ; and control keys and the middle and right mouse buttons, in this
          ; case none of them are down.  The second parameter is the cursor
          ; coordinates in the child window (ie, in the button).  These
          ; coordinates are actually somewhat complicated to figure out, but
          ; fortunately we don't need to, since pressing the mouse anywhere on
          ; the button gets the job done.  If you un-commented the Display
          ; line above, this command may not actually close the Find dialog.
          IntControl(23, hWnd, WMLBUTTONDOWN, 0, 0)
          Delay(1)
          ; Now we send a message saying that we released the button.  Not
          ; strictly necessary, but good practice.  Same parameters as before.
          IntControl(23, hWnd, WMLBUTTONUP, 0, 0)
          Delay(1)
        Endif
      Endif
    Endif
  Endif
  ; Okay, we just processed one (more) control.  Now we will get the handle of
  ; the next child, if any (the loop ends when we get a handle of 0), and
  ; again we will just re-use the hWnd variable since it makes life easier.
  ; GetWindow, last parm == 2, means find next sibling of this child window.
  hWnd = DllCall(dll, word:"GetWindow", word:hWnd, word:2)
EndWhile
; At this point, we have seen every child window in the "Find dialog".  You
; may have noticed there were some child windows that had no names; they
; were not significant.  If you need to process a control in a different
; dialog that has no name, you can use its positional sequence number (i).
; You may also have noticed some child windows that you didn't see on the
; screen.  I can't begin to tell you why.  Get a book on Windows programming.
; Clean up.
:cancel
BinaryFree(buffer)
DllFree(dll)
WinClose("Notepad")

One minor correction to my example:

Now we send a message saying that we released the button. Not strictly necessary, but good practice. Same parameters as before.

IntControl(23, hWnd, WMLBUTTONUP, 0, 0)

Actually, for a pushbutton like the "Cancel" button, it *is* necessary to send this message. For some other types of controls and windows, it's not strictly necessary (eg, for a copyright screen which disappears as soon as you send a WM_LBUTTONDOWN -- you don't need to send a WM_LBUTTONUP because the window will be gone anyway), but it's always good practice to do so.



Article ID:   W13743
File Created: 2003:02:20:15:26:42
Last Updated: 2003:02:20:15:26:42