Automating Windows Applications using Python

Introduction

If you spend a lot of time using Windows applications, you‘ve probably encountered tedious, repetitive tasks that you wish you could automate. Fortunately, Python provides powerful libraries for automating virtually any Windows desktop application. By writing scripts to control applications, you can turn time-consuming manual processes into automated workflows.

In this article, we‘ll explore how to automate Windows applications using Python. We‘ll focus on the excellent open-source library pywinauto, while also touching on other options. You‘ll see realistic examples of automating apps like Notepad, Calculator, and Excel. By the end, you‘ll have a solid foundation to start using Python to take control of the applications you use every day.

Why Automate Applications?

There are many reasons you might want to automate a desktop application:

  • Time savings – Automating repetitive tasks like data entry can save huge amounts of time
  • Consistency – Automation scripts perform the same actions every time, eliminating human error
  • Scheduling – Scripts can be scheduled to run unattended while you focus on other things
  • Integration – Automation can integrate applications, passing data between them
  • Testing – Simulatinguser actions is useful for automated GUI testing of applications

Any application you regularly use likely has some processes that could benefit from automation. Developing scripts takes some up-front effort, but the time and frustration savings can be enormous, freeing you to focus on more important things.

Python Libraries for Windows Automation

Python has a rich ecosystem of open-source libraries for application automation. Here are a few of the most popular:

  • pywinauto – Provides a set of methods to automate Windows GUI controls and dialogs
  • pyautogui – Cross-platform library for GUI automation focused on keyboard/mouse simulation
  • robotframework – Generic test automation framework with support for Windows automation
  • Win32com – Lower-level module for integrating with Windows COM objects

In this article we‘ll primarily use pywinauto, as it provides high-level functions specifically for automating Windows front-end applications. However, the general concepts apply across libraries. Often a combination of tools works best, such as using pywinauto for precise UI control and pyautogui for global mouse/keyboard actions.

Automating Notepad Using pywinauto

To see pywinauto in action, let‘s start with a simple example – automating Windows Notepad. We‘ll write a script to launch Notepad, type some text, save the document, and exit.

First, make sure you have pywinauto installed:

pip install pywinauto

Then use the following code:

from pywinauto.application import Application 

# Start Notepad
app = Application(backend="uia").start("notepad.exe")

# Get the Notepad window 
notepad = app.window(title=‘Untitled - Notepad‘)

# Type some text
notepad.type_keys("Hello from pywinauto!", with_spaces=True)

# Save the file
notepad.menu_select("File->SaveAs")
app.SaveAs.edit.set_text("pywinauto_notepad_example.txt")
app.SaveAs.Save.click()

# Exit Notepad
notepad.menu_select("File->Exit")

This script does the following:

  1. Imports the Application class from pywinauto. This is the main entry point for automating apps.

  2. Starts Notepad using the start() method, specifying the UIA backend (more on backends later).

  3. Retrieves a reference to the main Notepad window using the window() method, specifying the window title.

  4. Types some text using the type_keys() method.

  5. Selects File->SaveAs from the menu to open the Save dialog.

  6. Sets the filename in the Save dialog‘s text box using set_text().

  7. Clicks the Save button to save the file.

  8. Exits Notepad by selecting File->Exit from the menu.

When you run this script, you‘ll see Notepad automatically launch, receive the typed text, save the document, and close itself. We‘ve eliminated the need to perform these steps manually.

This basic example demonstrates the core parts of a pywinauto automation script:

  1. Starting an application
  2. Getting window/dialog references
  3. Interacting with controls
  4. Exiting the application

With these building blocks, we can automate practically any Windows app.

Application Backends

You may have noticed we specified uia as the backend when starting Notepad. An application backend determines how pywinauto communicates with the application under automation.

There are two primary Windows backends:

  1. win32 – Uses the Win32 API. Legacy backend with limitations. Default in pywinauto.

  2. uia – Uses UIAutomation API. Modern backend that supports more controls and applications. Recommended for most use cases.

You can usually stick with the uia backend. If you encounter issues, try switching to win32. Some older applications may work better with win32.

Identifying Controls

To interact with an application, you need to locate the controls (buttons, menus, etc.) that you want to manipulate. Every control has a variety of attributes that uniquely identify it, such as:

  • name
  • class name
  • automation ID
  • etc.

There are a few ways to find these attributes:

  1. Spy++ Tool – Free tool included with Visual Studio that lets you view UI element properties.

  2. Inspect.exe – Another free Microsoft tool for examining UI elements. Recommended over Spy++.

  3. print_control_identifiers() – pywinauto method that prints out the attribute details of all controls in a window.

Once you have the unique attributes of a control, you can access it using pywinauto‘s methods like:

  • window()
  • child_window()
  • descendants()

For example, if a button had the unique automation ID "myButton", you could click it with:

window.child_window(auto_id="myButton").click()

Capturing the right control attributes is critical for reliably automating applications. Experiment with the tools above to find attributes that uniquely identify the controls you need.

Keyboard and Mouse Automation

While pywinauto provides methods for interacting with specific UI controls, sometimes you need to automate at a lower level using raw keyboard and mouse actions.

For mouse clicks, pywinauto provides methods like:

  • click()
  • double_click()
  • right_click()

You can specify coordinates to click at a specific location.

For keyboard input, pywinauto has useful methods like:

  • type_keys() – Sends keystrokes to the active window
  • send_keystrokes() – Sends keystrokes without activating a window

Special keys are represented with constants like:

  • {ENTER}
  • {ESC}
  • {F1}

Modifiers keys like Alt are specified with:

  • % (Alt)
  • ^ (Ctrl)
    • (Shift)

For example, to press Alt+F4 you would use:

send_keys(‘%{F4}‘)

Global mouse and keyboard automation is also useful for when there isn‘t a unique control to latch onto.

Waiting for Controls

Sometimes automation scripts need to wait for an application to be in a certain state before proceeding. For example, waiting for a dialog to appear after clicking a button.

pywinauto provides several methods for waiting:

  • wait() – Pauses execution until a control reaches a specified state
  • wait_for_idle() – Waits for the process to enter an idle state
  • wait_for_process_exit() – Waits for a process to finish

Using appropriate waits is important for creating robust automation scripts that can handle different application load times.

Automating Excel

Let‘s walk through a more advanced example – automating Microsoft Excel to read data from a sheet.

First, make sure you have Excel installed. Then use this script:

from pywinauto import Application

excel_path = r"C:\Program Files\Microsoft Office\root\Office16\EXCEL.EXE"
workbook_path = r"C:\Users\MyUser\Documents\data.xlsx"

# Start Excel with the specified workbook
app = Application(backend=‘uia‘).start(f‘{excel_path} "{workbook_path}"‘) 
workbook = app.window(title_re=".*data.xlsx")

# Wait for the sheet to be fully loaded 
workbook.wait(‘ready‘, timeout=30)  

# Get the sheet and data range 
sheet = workbook.child_window(title="Sheet1", control_type="Table")
data_range = sheet.descendants(control_type="DataItem", title="A1:C10")[0]

# Read values from the range into a list of lists
data = []
for row in data_range.children():
    data_row = []
    for cell in row.descendants(control_type="DataItem"):
        try:
            data_row.append(cell.get_value())
        except ValueError:
            data_row.append(None)
    data.append(data_row)

print(data)

# Save and exit
workbook.type_keys(‘^s‘) # Ctrl+S shortcut to save
workbook.type_keys(‘%{F4}‘) # Alt+F4 to close

This script does the following:

  1. Starts Excel with a specified workbook using the start() method

  2. Gets a reference to the workbook window using the window() method with a regular expression title search

  3. Waits for the sheet to finish loading using wait()

  4. Gets the sheet Table object using child_window()

  5. Locates the range of data using descendants()

  6. Reads the data cell-by-cell into a list of lists

  7. Saves and closes the workbook using keyboard shortcuts

By reading data directly from Excel into Python data structures, we can integrate Excel into larger automated workflows. You could also write data back to sheets or create entirely new workbooks.

A similar approach could be used to automate other Office apps like Word or Powerpoint.

GUI Testing with pywinauto

In addition to automating workflows, pywinauto is also useful for automated testing of Windows applications. By simulating user actions, we can validate that an application behaves as expected.

For example, let‘s say we wanted to test search functionality in Notepad. We could write a test case like:

from pywinauto.application import Application

def test_notepad_search():
    # Start Notepad
    app = Application(backend="uia").start("notepad.exe")
    notepad = app.window(title=‘Untitled - Notepad‘)

    # Type some text
    text = "The quick brown fox jumps over the lazy dog"
    notepad.type_keys(text, with_spaces=True)

    # Open the Find dialog 
    notepad.menu_select("Edit->Find")
    find_dialog = notepad.window(title="Find")

    # Type search term 
    find_dialog.type_keys("fox")

    # Click Find Next
    find_dialog.child_window(title="Find Next", control_type="Button").click()

    # Verify correct text is highlighted
    assert notepad.get_selection_indices() == (text.index("fox"), text.index("fox") + len("fox"))

    # Close Notepad
    notepad.menu_select("File->Exit")

This test function:

  1. Starts Notepad and types some sample text
  2. Opens the Find dialog and searches for "fox"
  3. Clicks Find Next
  4. Verifies the correct range of text is selected
  5. Exits Notepad

We could run this test as part of a larger suite to catch regressions in search functionality.

Automated GUI tests with pywinauto are a great supplement to unit tests for desktop applications. They test the actual user interface end-to-end. While GUI tests can be brittle compared to unit tests, tools like pywinauto make them much easier to implement.

Other Automation Libraries

While we‘ve focused on pywinauto for Windows automation, Python has a wealth of other libraries for different automation needs.

For web browser automation, Selenium with Python bindings is the go-to choice. It allows automating all major browsers for testing and web scraping.

For automating at the operating system level, the built-in os and subprocess modules are useful for working with files, directories, and external processes.

For general scripting and task automation, the standard Python libraries are often sufficient. Modules like time, datetime, logging, and argparse make it easy to write robust command-line automation scripts.

Resources and Next Steps

Hopefully this article has inspired you to start automating the applications you use with Python. Here are some useful resources for learning more:

The best way to get started is to pick a simple task you perform regularly in an application and try to automate it. Start small and gradually build up to more complex workflows.

Also, keep in mind that not every application can be easily automated with existing open-source tools. Some apps are very difficult to automate due to custom controls, anti-bot measures, or other complications. Be prepared to iterate and don‘t hesitate to use lower-level tools like Win32 API or UI Automation API directly if needed.

Happy automating!

How useful was this post?

Click on a star to rate it!

Average rating 5 / 5. Vote count: 1

No votes so far! Be the first to rate this post.

Similar Posts