Working with Win32 Styles
If CLASS and CAPTION are not sufficient to identify a control callout, you will need to use STYLE and possibly EXTENDED STYLE to identify it. In a real Win32 application (as opposed to .NET or Java or HTML), this is easy, as these latter values uniquely identify the type of control.
You will notice once you select "If <Style>" instead of "Any Style" for the match criteria that
AND mask [ ] = [ ]
become enabled to the right of it.
What this means is that the contents of the "mask" textbox is used to isolate certain bits in the 32-bit STYLE integer, and if the resulting number matches the value in the "=" textbox, then the rule will match the object. If you don't know what this means, then I invite you to examine binary arithmetic and "bit" operations available in most programming languages. It's not difficult to learn.
Let's take a BUTTON class object, since that is a great example to see "under the covers" of how STYLE is required to identify certain types of controls. The reason for this is that in the Windows operating system, the BUTTON class governs all types of controls that assume a state or trigger an action when you click them with the mouse. These include:
Push Buttons,
Checkboxes,
Radio Buttons,
Group Boxes,
and three others less often used.
The behaviors that these types of control share are all "classified" under the class "BUTTON". So matching the BUTTON class is not enough to fully identify these controls.
Taking BUTTON as an example, the STYLE portion of the Win32 screen-capture rule uses takes the STYLE integer and does a bit-wise AND operation with the value in the "mask" textbox. You can use decimal integers or symbols from the
C:\Program Files\Microsoft SDKs\Windows\v7.0A\Include\WinUser.h
file, which was installed on your system if you installed the Windows SDK from Microsoft.
The symbols of interest in my WinUser.h file start on line 9444. The section looks like this:
/*
* Button Control Styles
*/
#define BS_PUSHBUTTON 0x00000000L
#define BS_DEFPUSHBUTTON 0x00000001L
#define BS_CHECKBOX 0x00000002L
#define BS_AUTOCHECKBOX 0x00000003L
#define BS_RADIOBUTTON 0x00000004L
#define BS_3STATE 0x00000005L
#define BS_AUTO3STATE 0x00000006L
#define BS_GROUPBOX 0x00000007L
#define BS_USERBUTTON 0x00000008L
#define BS_AUTORADIOBUTTON 0x00000009L
#define BS_PUSHBOX 0x0000000AL
#define BS_OWNERDRAW 0x0000000BL
#define BS_TYPEMASK 0x0000000FL
So your STYLE match criteria would look like this if you copy/paste the above symbols into the text boxes (you have to paste them, you can't type them directly):
[If <Style>] AND mask [BS_TYPEMASK ] = [BS_CHECKBOX ]
or alternately like this:
AND mask [15 ] = [2 ]
(If you're not familiar with the hexadecimal number system, BS_TYPEMASK = 0xF = 15.)
Either way, they perform the match in exactly the same way.
For those of you who don't work with binary arithmetic every day, what this does internally is take the STYLE integer, which might be a value like this:
Hex: 0x50010002 <-- I got this number from a real checkbox example with Spy++
Decimal: 1342242818 (I know -- it's easier to interpret in Hexadecimal)
and does a bit-wise AND with the value 15 (hex 0x0000000F), which looks like this in binary:
Binary: 0101 0000 0000 0001 0000 0000 0000 0010 <- style integer
Binary: 0000 0000 0000 0000 0000 0000 0000 1111 <- value 15
---(AND)-----------------------------------------
Binary: 0000 0000 0000 0000 0000 0000 0000 0010 <- result = 2
In English, it says "what is the value contained in only the last 4 bits on the right"? Answer: 2, which you can clearly see in the hexadecimal representation of the STYLE value above (the last digit of 0x50010002).
As an experiment, I set up my own custom set of BUTTON rules as follows (all rules match class in a non-case-sensitive match, "Any Caption" and "Any ExStyle"):
If <Style> AND
----------------------------------
Class Mask Value Control Title
-------------- ----------- ------------------ ----------------------
= "BUTTON" BS_TYPEMASK BS_PUSHBUTTON {Caption} Push Button
= "BUTTON" BS_TYPEMASK BS_DEFPUSHBUTTON {Caption} Push Button (Default)
= "BUTTON" BS_TYPEMASK BS_CHECKBOX {Caption} Checkbox
= "BUTTON" BS_TYPEMASK BS_AUTOCHECKBOX {Caption} Checkbox
= "BUTTON" BS_TYPEMASK BS_RADIOBUTTON {Caption} Option
= "BUTTON" BS_TYPEMASK BS_3STATE {Caption} 3-State Checkbox
= "BUTTON" BS_TYPEMASK BS_AUTO3STATE {Caption} 3-State Checkbox
= "BUTTON" BS_TYPEMASK BS_GROUPBOX {Caption} Group
= "BUTTON" BS_TYPEMASK BS_USERBUTTON {Caption} User Button
= "BUTTON" BS_TYPEMASK BS_AUTORADIOBUTTON {Caption} Option
= "BUTTON" BS_TYPEMASK BS_PUSHBOX {Caption} Push Box
= "BUTTON" BS_TYPEMASK BS_OWNERDRAW {Caption} Owner-Draw Button
contains "WindowsForms10.BUTTON" any style .NET Button
contains "BUTTON" any style {Caption} Button
(The last one is a "catch-all" rule.)
This is the results applied to the Spy++ Window Search dialog:
Analysis of Spy++ Window Search Dialog Using Customized Win32 Analysis Rules
Not bad, eh?
If you are wondering what the "&" are doing in there (e.g. "&Help Push Button"), part of the the Win32 user interface library uses this symbol to identify a hot key. In this example, the keystroke Alt-H would "click" the Help button without using the mouse.
In all fairness to the Dr.Explain team, I think the Accessible Objects approach ACTUALLY does a better job with this same screen for purposes of producing software documention:
Analysis of Spy++ Window Search Dialog Using Dr.Explain's Default
Accessible Objects Analysis Filters -- A Better Result for the Purpose of Documenting Software
What just LEAPS OUT at me here is the fact that using the Accessible Objects approach is going to save me a lot of time in control names I don't have to re-type!
However, on the other side of the coin, when I documented the "HM GP Shifter Configuration Tool" application (see
Creating an HTML Help File with Dr.Explain), I often found myself wanting to document the group box, and the Win32 example above does produce a callout for the group box, whereas the Accessible Objects example does not. I'll bet that if I learned more about Accessible Objects screen capture configuration I could make that happen with the Accessible Objects Filters as well.