| Please read Guide: Windows and S+ Overview first!
Executables, Titles, Handles, Oh My!
Each program has an executable (sometimes referred to as an image by Windows) which contains all of the necessary code to run the program. The program has one or more windows (with or without titles), one or more processes, each having one or more threads. Generally, you're simply looking for the handle of the main window for the program with which you'd like to interact. Finding that window can sometimes be a challenge for new users, especially if they're inexperienced with Windows development or scripting.
Okay, But How Do I Find The Main Window Handle?
There are multiple ways which S+ provides the necessary functionality to locate the handle for the window with which you'd like to interact. This includes searching by EXE name, exact window title, matching based on a Regular Expression pattern, window class name, by the window located at a specific pair of coordinates on the screen, and more.
One of the most common and simple method is via location on the screen. For example, to get the main window based on where a gesture began:
local handle = acGetOwnerWindowByPoint(gsx, gsy)This snippet gets the owner window handle for the window where the gesture was started (gsx and gsy are variables internally populated by S+ and passed into all action scripts). The variable named "handle" now has a number stored in it, this number is the handle (address). Defining the variable with "local" in front of it means it will only exist during that action's script; generally this is preferred so you don't cause memory to continually increase over time.
S+ also offers acGetWindowByPoint and acGetParentWindowByPoint which return the respective window handle. The prior gets the window handle exactly at the supplied coordinates, where the latter gets the parent window handle of the window at the exact coordinates. acGetOwnerWindowByPoint walks all the way up through the parent windows to find the overall owning window of the window at the location specified, then returns its handle.
Exact Class and/or Window Title (case-sensitive)
S+ includes an action function named acFindWindow which allows you to find the window where the class name and/or window title exactly matches the supplied parameters. Passing in nil for either parameter means the function will match any window. For example, when you first open Notepad (the one which comes with Windows), the title is "Untitled - Notepad" and the class name for the main typing area is "Edit". So if you happened to want to find the exact text area of Notepad, you could call:
local handle = acFindWindow("Edit", nil)The "handle" variable would now store the handle for first window with a class of "Edit". However, this could be pretty much any edit box in any application. If only Notepad were open program to have an edit control, it would return the handle for that control; note that the handle to the main window for Notepad would not be the handle to the text editing area. However, calling this would get you the main window:
acFindWindow(nil, "Untitled - Notepad")Now for some programs, the latter method is fine, but many programs' window title text changes. For example, if you saved the file in Notepad, the title would change to something like "Test File.txt - Notepad", which means the call above wouldn't find any window which matched the supplied criteria. However, if there happened to be another program or window/control which had the same exact title, you'd want to use this:
acFindWindow("Notepad", "Untitled - Notepad")Note that the class name for the Notepad application is called "Notepad". To find the class names for windows, you can use Spy++ (which comes with Visual Studio, or something like WinID.
Of course, since the main window's class is "Notepad", it's a pretty safe bet to use this, since it won't matter what the title of the window is:
Window Title By Pattern
Using Regular Expression (or just regex) and the acFindWindowByTitleRegex action function, you can craft very powerful patterns to find the window handle for which you're looking. While 90% of the time, the pattern you'd need should be simple, Regular Expressions can get very complicated and cryptic. RegExLib is a GREAT resource for understanding and testing regex patterns.
In the example above, the following expression (pattern) would always find Notepad due to the fact that Notepad uses a specific pattern for window titles:
local handle = acFindWindowByTitleRegex(".* - Notepad")The pattern above basically says find any window with ends with " - Notepad". As I mentioned, Regular Expressions can be very complex and I will not get into depth on the topic here.
Executable Name (case-sensitive)
Sometimes programs can have many windows open or are simply difficult to find the main window's handle via the above methods. The pair of actions acGetProcessIDFromPattern and acGetWindowFromProcessID can be used to obtain the main window handle for a given program; although it is substantially more resource intensive from a technical perspective. In the example below, we're going to find the main window handle for Notepad, regardless of what the window title is:
local pid = acGetProcessIDFromPattern("notepad.*")
local handle = acGetWindowFromProcessID(pid)The variable named "handle" now contains the main window handle for Notepad. Note, however, that it only returns the handle for the first instance of notepad.exe found.
Once you have the right window handle, anything is possible! One of the most common actions is bringing the window into focus:
acActivateWindow(handle) --Bring the window to the frontBut the possibilities are virtually endless.
Well, that's all for now...until next time!