Addressing Objects in MSAA Open Applications

Applies to TestComplete 14.70, last modified on April 22, 2021
Information in this topic applies to desktop applications only.

This topic explains how TestComplete names objects of MSAA applications exposed via the Microsoft Active Accessibility Support plugin and how you can address these objects in your tests. For more information on addressing windows, controls and objects in other Open Applications and in black-box applications, see Object Browser Naming Notation.

Obtaining Processes

Addressing windows, controls and objects is hierarchical, that is, to obtain any object of the MSAA application’s window, you should first obtain the corresponding process. To do this, you can use the Sys.Process or Sys.WaitProcess method that returns a Process object. The difference between the mentioned methods is that Sys.Process returns the result immediately while Sys.WaitProcess delays the script execution until the specified process appears or until the specified time limit is reached.

If the specified process does not exist, the Process method will post an error message to the test log and return an empty object. If you then attempt to call any other methods or properties using this object, TestComplete will post an error message to the test log. To determine whether the desired process exists, use the Exists property.

JavaScript, JScript

if (! Sys.WaitProcess("MyMSAAApp").Exists )
  Log.Warning("The specified process does not exist.");

Python

if not Sys.WaitProcess("MyMSAAApp").Exists:
  Log.Warning("The specified process does not exist.")

VBScript

If Not Sys.WaitProcess("MyMSAAApp").Exists Then
  Log.Warning "The specified process does not exist."
End If

DelphiScript

if not Sys.WaitProcess('MyMSAAApp').Exists then
  Log.Warning('The specified process does not exist.');

C++Script, C#Script

if (! Sys["WaitProcess"]("MyMSAAApp")["Exists"])
  Log["Warning"]("The specified process does not exist.");

For detailed information on how to obtain processes, see Object Browser Naming Notation.

Obtaining Windows and Controls

The way you can address windows and controls in MSAA Open Applications depends on the MSAA engine mode. TestComplete 14 includes the compatibility mode that was used in TestComplete 6 and earlier. The active mode is specified by the Work with MSAA objects in mode compatible with TestComplete 6 and earlier property of your project. If it is unchecked (by default, it is), TestComplete uses the default mode. Otherwise, it uses the compatibility mode.

The two modes are incompatible. The tests recorded or created in the compatibility mode will not play back correctly in the new mode and vice versa.

The rest of this topic explains how to address object principles in both modes.

Addressing Objects (New Mode)

To address controls and objects that are exposed by the MSAA engine, TestComplete uses the objects’ type names that indicate their accessibility roles in the application:

View Image

Using type names simplifies the tests and makes them more readable. For a full list of object types that correspond to various accessibility roles, see the following topics:

Besides type names, TestComplete identifies objects by accessibility names. If there are several objects with the same accessibility roles and names in a parent container, TestComplete addresses the object by the accessibility name plus its index among siblings of the same type (the ControlIndexInGroup property value). The default index, 0, is always omitted. For example:

ListItem("My item")

ListItem("My item", 1)

ListItem("My item", 2)

and so on

The accessible names are case-insensitive. That is, Button("OK") and Button("ok") refer to the same object. Note also, that you can use wildcards (* and ?) or regular expressions when addressing objects whose accessibility names have variable parts. The asterisk (*) corresponds to a string of any length (including an empty string), the question mark corresponds to any single character (including none). To specify more complicated parts of accessibility names, use regular expressions.

If the object does not have an accessibility name specified, the way TestComplete addresses this object depends on whether it is windowed or not:

  • Non-windowed objects are addressed by type names and indexes within the parent container. For example:

    Table(1)

    Link(0)

  • Windowed controls can be addressed with the Window method of the parent window like controls of black-box applications.

The following code illustrates MSAA object addressing. It launches Notepad using the Windows Start | Run menu command. The example requires that the “*” item in the project’s MSAA Options is checked.

JavaScript, JScript

function Test()
{
  var p, w;

  // Select Start and then Run
  p = Sys.Process("Explorer");
  p.Window("Shell_TrayWnd").Button("Start").Click();
  p.Popup("Application").Window("MenuSite").Popup("Application").MenuItem("Run...").Click();

  // Run Notepad
  w = p.Dialog("Run");
  w.ComboBox("Open:").Window("Edit").Keys("notepad");
  w.Button("OK").Click();
}

Python

def Test():

  # Select Start and then Run
  p = Sys.Process("Explorer")
  p.Window("Shell_TrayWnd").Button("Start").Click()
  p.Popup("Application").Window("MenuSite").Popup("Application").MenuItem("Run...").Click()

  # Run Notepad
  w = p.Dialog("Run")
  w.ComboBox("Open:").Window("Edit").Keys("notepad")
  w.Button("OK").Click()

VBScript

Sub Test
  Dim p, w

  ' Select Start and then Run
  Set p = Sys.Process("Explorer")
  p.Window("Shell_TrayWnd").Button("Start").Click
  p.Popup("Application").Window("MenuSite").Popup("Application").MenuItem("Run...").Click

  ' Run Notepad
  Set w = p.Dialog("Run")
  w.ComboBox("Open:").Window("Edit").Keys("notepad")
  w.Button("OK").Click
End Sub

DelphiScript

procedure Test;
var p, w;
begin
  // Select Start and then Run
  p := Sys.Process('Explorer');
  p.Window('Shell_TrayWnd').Button('Start').Click;
  p.Popup('Application').Window('MenuSite').Popup('Application').MenuItem('Run...').Click;

  // Run Notepad
  w := p.Dialog('Run');
  w.ComboBox('Open:').Window('Edit').Keys('notepad');
  w.Button('OK').Click;
end;

C++Script, C#Script

function Test()
{
  var p, w;

  // Select Start and then Run
  p = Sys["Process"]("Explorer");
  p["Window"]("Shell_TrayWnd")["Button"]("Start")["Click"]();
  p["Popup"]("Application")["Window"]("MenuSite")["Popup"]("Application")["MenuItem"]("Run...")["Click"]();

  // Run Notepad
  w = p["Dialog"]("Run");
  w["ComboBox"]("Open:")["Window"]("Edit")["Keys"]("notepad");
  w["Button"]("OK")["Click"]();
}

Also, to wait for an object that is exposed by the MSAA engine, to be exposed, TestComplete adds a number of Wait methods to parent objects: WaitPanel, WaitTable, WaitListItem, WaitPropertyPage and so on. These methods are not displayed in the Object Browser and other TestComplete panels and windows, however, they are fully accessible from scripts. The syntax of these Wait methods is as follows:

WaitTypeName(ObjectNameOrIndex, Timeout)

The methods use the following parameters:

  • TypeName - the type name of the child object (Panel, Table, ListItem, Button, PropertyPage and so on).

  • ObjectNameOrIndex - the accessibility name of the target object, or its index within the container (the ControlIndexInGroup property value). It must be the same as the name or index that is displayed in the Object Browser. For example, if the child object is named Panel("Standard"), then this parameter should be "Standard"; if the child object is named Table(2), the parameter should be 2.

    If the target object is addressed both using the name and index, you should specify both parameters. For example, if the child object is names ListItem("My Item", 3), you should specify -- "My Item", 3.

  • Timeout - specifies the waiting time (in milliseconds). If this parameter is 0, the method checks for the object’s existence once and returns immediately. If the parameter is -1, the waiting time is infinite.

If the specified object becomes available before the time period elapses, the Wait methods return this object. Otherwise, they return an empty stub object that only contains the Exists property. You can use this property to check whether the returned object actually exists.

Below are some examples of child object names and the corresponding Wait method calls (the Timeout parameter is 1000 in all the examples):

Object Wait Method
Panel("Standard") WaitPanel("Standard", 1000)
Table(2) WaitTable(2, 1000)
ListItem("My Item", 3) WaitListItem("My Item", 3, 1000)
Addressing Objects (Compatibility Mode)

If the Work with MSAA objects in mode compatible with TestComplete 6 and earlier property of your project is checked, then TestComplete addresses objects exposed by the MSAA engine in the same way it did in TestComplete ver. 4 - 6, namely, using the MSAAObject and WaitMSAAObject methods. The difference between these two methods is that MSAAObject returns the requested object immediately, while WaitMSAAObject delays the test execution until the requested object becomes available to TestComplete or until the specified timeout elapses.

View Image

The MSAAObject and WaitMSAAObject methods use special object identifiers that specify both the object’s accessible name and role. These identifiers consist of the following parts, which are combined with the underscore characters (_):

  • The prefix that specifies the object’s accessible role. Possible prefixes are listed in the table below. TestComplete uses the short prefix if the object has an accessibility name specified, and the long prefix otherwise.

    Prefixes

  • The object’s accessible name (if any), with spaces replaced by underscore characters and any characters except for alphanumeric ones removed, so that the name becomes a valid script identifier.

  • The object’s index among objects that have the same accessible name and role (if greater than 1).

For example:

Identifier Description
editable_text_Comments An edit box with the accessible name of “Comments”.
btn_Normal_View A button with the accessible name of “Normal View”.
table A table with no accessible name.
cell_2 The second cell within the table.

The objects returned by the MSAAObject and WaitMSAAObject methods contain methods, properties and actions of onscreen objects as well as methods and properties of the IAccessible interface. For more information on the IAccessible members, see the documentation of the IAccessible Interface in the MSDN library.

The following code demonstrates how you can address MSAA objects in the compatibility mode. It launches Notepad using the Windows Start | Run menu command. The example requires that the “*” item in the project’s MSAA Options is checked.

JavaScript, JScript

function Test()
{
  var p, w, menu;

  // Click the Start button
  p = Sys.Process("Explorer");
  p.Window("Shell_TrayWnd").Window("Button", "Start").MSAAObject("btn_Start").DoDefaultAction();

  // Select the Run command in the Start menu
  menu = p.Window("BaseBar", "", 1).Window("MenuSite").Window("ToolbarWindow32").MSAAObject("pm_Application");
  menu.MSAAObject("mi_Run").MSAAObject("mi_Run").DoDefaultAction();

  // Run Notepad
  w = p.Window("#32770", "Run");
  w.Window("ComboBox").Window("Edit").Keys("notepad");
  w.Window("Button", "OK").MSAAObject("btn_OK").DoDefaultAction();
}

Python

def Test():

  # Click the Start button
  p = Sys.Process("Explorer")
  p.Window("Shell_TrayWnd").Window("Button", "Start").MSAAObject("btn_Start").DoDefaultAction()

  # Select the Run command in the Start menu
  menu = p.Window("BaseBar", "", 1).Window("MenuSite").Window("ToolbarWindow32").MSAAObject("pm_Application")
  menu.MSAAObject("mi_Run").MSAAObject("mi_Run").DoDefaultAction()

  # Run Notepad
  w = p.Window("#32770", "Run")
  w.Window("ComboBox").Window("Edit").Keys("notepad")
  w.Window("Button", "OK").MSAAObject("btn_OK").DoDefaultAction()

VBScript

Sub Test
  Dim p, w, menu

  ' Click the Start button
  Set p = Sys.Process("Explorer")
  p.Window("Shell_TrayWnd").Window("Button", "Start").MSAAObject("btn_Start").DoDefaultAction

  ' Select the Run command in the Start menu
  Set menu = p.Window("BaseBar", "", 1).Window("MenuSite").Window("ToolbarWindow32").MSAAObject("pm_Application")
  menu.MSAAObject("mi_Run").MSAAObject("mi_Run").DoDefaultAction

  ' Run Notepad
  Set w = p.Window("#32770", "Run")
  w.Window("ComboBox").Window("Edit").Keys("notepad")
  w.Window("Button", "OK").MSAAObject("btn_OK").DoDefaultAction
End Sub

DelphiScript

procedure Test;
var p, w, menu;
begin
  // Click the Start button
  p := Sys.Process('Explorer');
  p.Window('Shell_TrayWnd').Window('Button', 'Start').MSAAObject('btn_Start').DoDefaultAction;

  // Select the Run command in the Start menu
  menu := p.Window('BaseBar', '', 1).Window('MenuSite').Window('ToolbarWindow32').MSAAObject('pm_Application');
  menu.MSAAObject('mi_Run').MSAAObject('mi_Run').DoDefaultAction;

  // Run Notepad
  w := p.Window('#32770', 'Run');
  w.Window('ComboBox').Window('Edit').Keys('notepad');
  w.Window('Button', 'OK').MSAAObject('btn_OK').DoDefaultAction;
end;

C++Script, C#Script

function Test()
{
  var p, w, menu;

  // Click the Start button
  p = Sys["Process"]("Explorer");
  p["Window"]("Shell_TrayWnd")["Window"]("Button", "Start")["MSAAObject"]("btn_Start")["DoDefaultAction"]();

  // Select the Run command in the Start menu
  menu = p["Window"]("BaseBar", "", 1)["Window"]("MenuSite")["Window"]("ToolbarWindow32")["MSAAObject"]("pm_Application");
  menu["MSAAObject"]("mi_Run")["MSAAObject"]("mi_Run")["DoDefaultAction"]();

  // Run Notepad
  w = p["Window"]("#32770", "Run");
  w["Window"]("ComboBox")["Window"]("Edit")["Keys"]("notepad");
  w["Window"]("Button", "OK")["MSAAObject"]("btn_OK")["DoDefaultAction"]();
}

See Also

Using Microsoft Active Accessibility
Limiting the Number of MSAA Child Objects

Highlight search results