Skip to content

Desktop Activities

Version: 1.0.9  ·  ID: zoan-packages-desktop  ·  Author: Zoan Software

The Desktop package automates Windows desktop applications: installed programs such as an ERP, an accounting system, a desktop banking application or any Windows app. The bot works with their windows and controls —buttons, fields, lists, tables— just like a person with the keyboard and mouse.

Under the hood it uses UI Automation (UIA3), the Windows accessibility technology, which lets it reliably “see” an application’s controls (not by screen coordinates, but by the actual element). It also supports Java desktop applications (Swing).

To automate an app you first connect to its window. There are two pieces:

  • Open App: launches the application (if it is not open) and returns its process identifier (PID).
  • Win Attach: connects to a window and returns a session (ZoanDesktopSession).

As in Browser, there are two ways to work with the session:

The activities inside body inherit the session automatically; you don’t set session on any of them.

Win Attach selector = (window "Calculator")
└─ body:
Win Click selector = (button "5")
Win Click selector = (button "+")
Win Get Text selector = (display) → output: result

Win Attach stores the session in a variable; each activity receives it in session, and at the end you close it with Win Close.

Win Attach selector = (window "ERP") → output: app
Win Type session = app selector = (field "User") text = "admin"
Win Close session = app

As in the browser, a selector identifies the control to act on (this button, that field). You capture it with UI Discover by pointing at the element with the mouse; Zoan Automation stores a robust reference based on the control’s UIA properties (its controlType, name, automationId…), which survives changes in the window’s position or size.

A desktop selector is a list of nodes from the window down to the control:

NodeWhat it representsAttributes used when searching
wndThe application’s top-level windowprocess (process name, with or without .exe), title (window title), cls (window class)
ctrlEach control from the window down to the targetcontrolType, automationId, name, cls, idx (position among siblings, starting at 1)

How it is resolved:

  • Windows: only visible windows are considered; the first one that matches every attribute of the wnd node wins.
  • Value matching: case-insensitive; supports * and ? wildcards (Invoice *) and regular expressions between slashes (/^Order-\d+$/).
  • Dynamic values: write {{ expression }} inside a value (for example Row {{ index }}) and it is resolved at run time.
  • No guessing: if several controls match and nothing tells them apart, or none satisfies the anchors, the activity does not pick one at random: it fails and the diagnostics say why (add an anchor or an idx).
  • Retries: the search repeats every 250 ms until timeout runs out, including after momentary UI Automation errors (an app busy opening a dialog).

Concept 3: interaction methods (UIA vs physical)

Section titled “Concept 3: interaction methods (UIA vs physical)”

Several activities offer two ways to act on a control, and it helps to understand the difference:

Action”UIA” method (default)“Physical” method
Win Clickinvoke — on buttons, activates them without moving the mouse (a button that opens a dialog does not block the flow). On other controls it makes a real click.mouse — moves the mouse and makes a real click.
Win Typevalue — sets the text through the UIA Value pattern. Fast and safe.simulate — focuses the field and simulates keystrokes.

Start with the default method (invoke/value): it is more reliable. Switch to the physical one (mouse/simulate) only if a “stubborn” control does not respond to UIA (some custom controls, or fields that validate every key).

Before acting, the interaction activities (click, type, check, select, scroll) bring the window to the front and, if the control is scrolled out of view, try to scroll it into view; if they can’t, they fail instead of acting on something else. In Java applications, clicking, typing and selecting are always physical.

  • Finding the element: each activity waits up to timeout ms for its element to exist. If you leave it empty, it uses the UI timeout from the project settings or, if the project doesn’t set one, 30000 ms.
  • Instant checks: Win Element Exists does not wait by default (0); give it a timeout if you want it to wait.
  • Bringing the window to the front: Win Focus waits up to 15000 ms (or the project’s timeout); Win Key Press with a selector, up to 3 s.
  • Opening an application: Open App gives Windows 30000 ms (or the project’s timeout, if longer).
  • Delays: the project’s delays before and after each action apply to every element activity.

To wait for something to appear or disappear, use Win Wait For instead of a fixed Delay.

These messages are shared by every activity that searches for a control. Each activity’s own messages are on its page.

MessageCause and fix
Element not found with selector {…}. followed by Diagnostics: …The element did not appear within timeout. The diagnostics say at which node it was lost. Check that the window is open, validate the selector in UI Discover, or wait first with Win Wait For.
… elements match the selector and nothing tells them apart, so none was chosen (not guessing). Add an anchor or an index in the selector. (in the diagnostics)The selector is ambiguous. Add an automationId, an idx or an anchor.
'selector' is required and must be a valid desktop selector.The selector is missing or is not a desktop one (for example, a browser selector). Capture it again with UI Discover.
The selector must contain a 'wnd' node when there is no session.Without a session, the selector needs the window. Use the activity inside a Win Attach or pass session.
The element is outside the visible area and could not be scrolled into view, …The control is hidden by its container’s scrolling. Add a Win Scroll before it.
The Java control could not be located unambiguously, so nothing was done. …In a Java app, the bridge could not tell the control apart. Capture the selector again or add an anchor.

To retry after momentary failures, wrap the steps in a Retry or a Try / Catch.

ActivityTypeOutputWhat it does
Open Appopen-appintLaunches an application and returns its PID
Kill Processkill-processintTerminates processes by name or PID (a hung app)
Win Attachwin-attachZoanDesktopSessionConnects to a window
Win Focuswin-focus—Brings a window to the front
Win Closewin-close—Closes the window and releases the session
ActivityTypeOutputWhat it does
Win Clickwin-click—Clicks an element
Win Typewin-type—Types text into a field
Win Set Valuewin-set-value—Sets a field’s value (Value pattern)
Win Checkwin-check—Checks/unchecks a checkbox
Win Selectwin-select—Selects an item in a combo box/list
Win Key Presswin-key-press—Sends a key, a combination or a sequence of keys
Win Scrollwin-scroll—Scrolls an element
ActivityTypeOutputWhat it does
Win Get Textwin-get-textstringText or value of an element
Win Get Attributewin-get-attributeobjectA property of the element (enabled, value…)
Win List Itemswin-list-itemsstring[]Available items of a combo box/list
Win Element Existswin-element-existsbooleanDoes the element exist?
Win Extract Tablewin-extract-tableDataTableExtracts a table from a window into a DataTable
ActivityTypeOutputWhat it does
Win Wait Forwin-wait-forbooleanWaits for an element to appear or disappear
Win Screenshotwin-screenshot—Captures the window or an element to a file
Take Screenshottake-screenshotstringCaptures the whole desktop to a file and returns its path

Open a system, log in and read a value:

Open App path = "C:/ERP/erp.exe" → output: pid
Win Attach selector = (window "ERP — Login")
└─ body:
Win Type selector = (field "User") text = credential("erp")["user"]
Win Type selector = (field "Password") text = credential("erp")["password"]
Win Click selector = (button "Sign in")
Win Attach selector = (window "ERP — Home") // waits up to timeout for it to appear
└─ body:
Win Get Text selector = (label "Balance") → output: balance

And if the application hangs, the usual recovery is to keep evidence with Take Screenshot, terminate it with Kill Process and open it again. The built-in templates already include that pattern in their Recuperar playbook.