Skip to main content

Drive legacy Delphi/VCL and DevExpress Windows desktop apps from Python — by relative control order, with write-and-read-back verification.

Project description

vcldrive

Drive legacy Delphi/VCL and DevExpress Windows desktop apps from Python — by relative control order, with write-and-read-back verification.

CI License: MIT Python Platform


Why this exists

Plenty of business runs on old Windows desktop software built in Delphi/VCL with DevExpress controls — ERP, manufacturing, accounting. Automating those apps is unreasonably hard:

  • No automation ids. Forms expose several controls of the same class (for example four TcxImageComboBox editors in a column) with nothing to tell them apart.
  • Pixel scripts are brittle. Addressing controls by absolute coordinates breaks the moment the window moves or the screen resolution changes.
  • Owner-drawn controls are opaque. Many DevExpress editors are not exposed to UI Automation, so the usual accessibility path returns nothing (pywinauto #757, #950). The vendor's dxUIAutomationEnabled flag would help, but you cannot set it inside a compiled third-party .exe.
  • Values do not commit. A TcxCalcEdit accepts a number only after real, per-character key events followed by a focus change. Convenience APIs that set the window text leave the value unposted, which surfaces later as a validation error.

vcldrive packages the techniques that actually work against these forms, so you do not have to rediscover them. It builds on pywinauto and adds the missing layer for owner-drawn DevExpress/VCL forms.

What it gives you

Capability What it solves
Map by relative order Identify look-alike controls top-to-bottom, left-to-right — resilient to window moves and resolution changes.
Row-cluster detection Skip a band of look-alike fields (a material picker, a grid row) that sits between the inputs you care about.
Committing numeric input Type with real key events and a Tab commit, the only path that posts a TcxCalcEdit.
Dropdown by arrows Open with F4 and step with arrow keys in one session — reliable for long Unicode items.
Write-and-read-back Write, read back, normalise, retry — so a value that did not stick is caught and re-applied.
Modal recognition Read a validation dialog's text and react (re-enter a field, retry).
Screenshot as truth Capture the form, because on-screen state is the only trustworthy confirmation for owner-drawn controls.

Installation

# Pure logic only (mapping, verification, geometry, dialog matching):
pip install vcldrive

# With the Windows backend, to actually drive an app:
pip install "vcldrive[win32]"

The Windows extra pulls in pywinauto and pywin32. The core package has no runtime dependencies and imports on any operating system, which keeps the position logic testable in CI without a desktop.

Quickstart

from vcldrive import Form

# Attach to an already-open window by its class name.
form = Form.connect("TFrmItemEditor")

# Map the column of combo editors to roles by relative order, skipping a
# middle band of 3+ look-alike "material" combos.
combos = form.map_roles(
    "TcxImageComboBox",
    ["anchor", "group", "variant", "color", "side"],
    exclude_cluster_min=3,
)

# Pick a group by prefix, then a variant by stepping the open dropdown.
form.combo(combos["group"]).select_by_prefix("Widgets")
form.combo(combos["variant"]).select_by_arrows(7)

# Set the length with committing key events (width follows from the variant).
length = form.map_roles("TcxCalcEdit", ["length", "width"])["length"]
form.numeric(length).set_value(1600)

# Prove it on screen, then commit.
form.screenshot("item_form.png")
form.button("OK").click()

A complete, runnable walkthrough — including the "length is required" retry loop — is in examples/erp_accessory_form.py.

How it works

Map by relative order, not pixels

map_roles collects every control of a class, sorts them into reading order, and binds your role names to them one by one. Because it reasons about order rather than coordinates, the mapping holds when the window moves.

When a form interleaves a band of identical controls between the fields you want, exclude_cluster_min removes that band first. detect_row_clusters finds any row where that many same-class controls line up within an 8-pixel tolerance, so roles on both sides of the band still align.

Commit values the way the editor demands

NumericEdit.set_value focuses the editor, clears it, types each character as a real key event, and presses Tab. That on-exit commit is what posts the value to a TcxCalcEdit. ComboBox.select_by_arrows opens the list with F4 and steps with arrow keys in a single call, because the dropdown closes between separate key batches.

Trust the screen, then verify

For owner-drawn controls the committed value is not readable as window text, so Form.screenshot captures ground truth. For controls that are readable, verify_write writes, reads back, and retries until the value matches — turning a silent failure into a handled one.

Testing

The pure logic is fully unit-tested with in-memory fakes — no GUI, any OS:

pip install "vcldrive[dev]"
pytest

Compatibility

  • Python: 3.10+
  • OS: Windows (for driving). Core logic imports anywhere.
  • Backend: pywinauto win32. Bring your own backend by implementing the small ControlHandle protocol.

Contributing

Issues and pull requests are welcome — especially backend adapters and wrappers for more DevExpress/VCL control classes. Please keep new logic covered by tests.

License

MIT © 2026 Alple

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vcldrive-0.1.0.tar.gz (22.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vcldrive-0.1.0-py3-none-any.whl (21.0 kB view details)

Uploaded Python 3

File details

Details for the file vcldrive-0.1.0.tar.gz.

File metadata

  • Download URL: vcldrive-0.1.0.tar.gz
  • Upload date:
  • Size: 22.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for vcldrive-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3d35dde78eb7a6a61a67315dae54b4f8fba659870a1fd7e3ac72d5c14c0c1eec
MD5 459412c81d4a7fffa7b0c27d61975f8b
BLAKE2b-256 7d27df6bc2b1a1dfa02a74c7d33e09f5583955b3868fe2630b7dedafff2f9b4e

See more details on using hashes here.

File details

Details for the file vcldrive-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: vcldrive-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 21.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for vcldrive-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4d6fb697f41178d31ae817f1bf3c02e0aafc47e4d4875b6bff2c1a2a5f5ebf8c
MD5 07b611aa21b262b643554eaea7d9d51a
BLAKE2b-256 733f8d4cd621fafd144e5ac152931862988f995ab193be1870e1b20845fee62d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page