MCPcopy Create free account
hub / github.com/AutoHotkey/AutoHotkey / EnumControlFind

Function EnumControlFind

source/window.cpp:926–996  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

924
925
926BOOL CALLBACK EnumControlFind(HWND aWnd, LPARAM lParam)
927{
928 WindowSearch &ws = *(WindowSearch *)lParam; // For performance and convenience.
929 if (*ws.mCriterionClass) // Caller told us to search by class name and number.
930 {
931 int length = GetClassName(aWnd, ws.mCandidateTitle, WINDOW_CLASS_SIZE); // Restrict the length to a small fraction of the buffer's size (also serves to leave room to append the sequence number).
932 // Below: i.e. this control's title (e.g. List) in contained entirely
933 // within the leading part of the user specified title (e.g. ListBox).
934 // Even though this is incorrect, the appending of the sequence number
935 // in the second comparison will weed out any false matches.
936 // Note: since some controls end in a number (e.g. SysListView32),
937 // it would not be easy to parse out the user's sequence number to
938 // simplify/accelerate the search here. So instead, use a method
939 // more certain to work even though it's a little ugly. It's also
940 // necessary to do this in a way functionally identical to the below
941 // so that Window Spy's sequence numbers match the ones generated here:
942 // Concerning strnicmp(), see lstrcmpi note below for why a locale-insensitive match isn't done instead.
943 if (length && !_tcsnicmp(ws.mCriterionClass, ws.mCandidateTitle, length)) // Preliminary match of base class name.
944 {
945 // mAlreadyVisitedCount was initialized to zero by WindowSearch's constructor. It is used
946 // to accumulate how many quasi-matches on this class have been found so far. Also,
947 // comparing ws.mAlreadyVisitedCount to atoi(ws.mCriterionClass + length) would not be
948 // the same as the below examples such as the following:
949 // Say the ClassNN being searched for is List01 (where List0 is the class name and 1
950 // is the sequence number). If a class called "List" exists in the parent window, it
951 // would be found above as a preliminary match. The below would copy "1" into the buffer,
952 // which is correctly deemed not to match "01". By contrast, the atoi() method would give
953 // the wrong result because the two numbers are numerically equal.
954 _itot(++ws.mAlreadyVisitedCount, ws.mCandidateTitle, 10); // Overwrite the buffer to contain only the count.
955 // lstrcmpi() is not used: 1) avoids breaking existing scripts; 2) provides consistent behavior
956 // across multiple locales:
957 if (!_tcsicmp(ws.mCandidateTitle, ws.mCriterionClass + length)) // The counts match too, so it's a full match.
958 {
959 ws.mFoundChild = aWnd; // Save this in here for return to the caller.
960 return FALSE; // stop the enumeration.
961 }
962 }
963 }
964 else // Caller told us to search by the text of the control (e.g. the text printed on a button)
965 {
966 // Use GetWindowText() rather than GetWindowTextTimeout() because we don't want to find
967 // the name accidentally in the vast amount of text present in some edit controls (e.g.
968 // if the script's source code is open for editing in notepad, GetWindowText() would
969 // likely find an unwanted match for just about anything). In addition,
970 // GetWindowText() is much faster. Update: Yes, it seems better not to use
971 // GetWindowTextByTitleMatchMode() in this case, since control names tend to be so
972 // short (i.e. they would otherwise be very likely to be undesirably found in any large
973 // edit controls the target window happens to own). Update: Changed from strstr()
974 // to strncmp() for greater selectivity. Even with this degree of selectivity, it's
975 // still possible to have ambiguous situations where a control can't be found due
976 // to its title being entirely contained within that of another (e.g. a button
977 // with title "Connect" would be found in the title of a button "Connect All").
978 // The only way to address that would be to insist on an entire title match, but
979 // that might be tedious if the title of the control is very long. As alleviation,
980 // the class name + seq. number method above can often be used instead in cases
981 // of such ambiguity. Update: Using IsTextMatch() now so that user-specified
982 // TitleMatchMode will be in effect for this also. Also, it's case sensitivity
983 // helps increase selectivity, which is helpful due to how common short or ambiguous

Callers

nothing calls this directly

Calls 1

IsTextMatchFunction · 0.85

Tested by

no test coverage detected