Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Click Button in Toolbar of Other Program

I'm trying to automate some stuff on a legacy application that I don't have the source to. So I'm essentially trying to use the Windows API to click the buttons I'll need on it.

There is a toolbar of type msvb_lib_toolbar that looks like this:

Toolbar

I can get a handle to it (I think) by using this code:

IntPtr window = FindWindow("ThunderRT6FormDC", "redacted");
IntPtr bar = FindWindowEx(window, IntPtr.Zero,"msvb_lib_toolbar",null);

Looking at the docs, it seems I should be able to use SendMessage and the TB_PRESSBUTTON message to click these buttons:

[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);

However, I'm not sure how to go about setting the wParam and lParam to click the wanted button on the bar. The documentation doesn't seem to be helping much either.

Could you please advise?


Based on comments, I've also tried UIAutomation. I can locate the toolbar using the following code:

AutomationElement mainWindow = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Migration Expert"));
AutomationElement toolbar = mainWindow.FindFirst(TreeScope.Subtree, new PropertyCondition(AutomationElement.ClassNameProperty, "msvb_lib_toolbar"));

But from here, I'm not sure what to do as Spy++ shows no further children of this object:

Spy++

Loking at the Current property of this AutomationElement I can't seen anything jumping out at me but the BoundingRectangle does seem to indicate that I've found the right element.

Debugger

Using inspector.exe also doesn't indicate any children on the toolbar.

Inspector

like image 861
Persistence Avatar asked Jun 29 '20 12:06

Persistence


People also ask

What is a button that opens a group of related tools?

The toolbar, also called a bar or standard toolbar (originally known as ribbon) is a graphical control element on which on-screen icons can be used. A toolbar often allows for quick access to functions that are commonly used in the program.

What is group of Button in computer?

A button group is a group control out of which only one can be selected at a time. A button group is created through JButtonGroup component class of java Swing.


1 Answers

Not really an ideal solution but I got something quick and dirty working using a combination of pywinauto and pyautogui.

import pyautogui
import subprocess
import sys
import time
import os
from os import path
from glob import glob
from subprocess import check_output


from pywinauto import application


def click_at_image(image):
    location = pyautogui.locateOnScreen(image)
    buttonx, buttony = pyautogui.center(location)
    pyautogui.click(buttonx, buttony)

def get_dcf_filepaths():
    files = []
    start_dir = redacted
    pattern = "*.DCF"
    for dir, _, _ in os.walk(start_dir):
        files.extend(glob(os.path.join(dir, pattern)))
    return files

def get_csv_paths(paths):
    csv_paths = []
    for p in paths:
        csv_paths.append(p.replace(redacted,redacted).replace("DCF","csv").replace("dcf","csv"))
    return  csv_paths


def main():
    app = application.Application().start(redacted)
    files = get_dcf_filepaths()
    csv_paths = get_csv_paths(files)
    time.sleep(3)
    click_at_image("new_button.png") #Open new project
    for i in range(0, len(files)):
        if (path.exists(csv_paths[i])):
            #os.remove(csv_paths[i])
            continue
        time.sleep(1)
        # Click on nxt icon in dialog
        click_at_image("nxt_button.png")
        # Enter file path into OFD
        app.Open.Edit.SetText(files[i])
        pyautogui.press('enter')
        pyautogui.press('enter')
        time.sleep(1)
        # Click on m2c icon in toolbar
        click_at_image("m2c_button.png")
        # Wait for Excel to open
        time.sleep(6)
        # Open Save as dialog and browse
        pyautogui.press('alt')
        pyautogui.press('f')
        pyautogui.press('a')
        pyautogui.press('o')
        time.sleep(2)
        pyautogui.press('backspace')
        # Enter file path
        pyautogui.write(csv_paths[i], interval=0.01)
        #click_at_image("dummy.png")
        # Change file type to CSV and ignore any popups
        click_at_image("dd.png")
        time.sleep(1)
        
        click_at_image("csv.png")
        pyautogui.press('enter')
        pyautogui.press('enter')
        pyautogui.press('enter')
        time.sleep(2)
        # Kill excel
        pyautogui.hotkey('alt', 'f4')
        # Pull main window back to top
        app.top_window().set_focus()
        time.sleep(1)
        # New project
        click_at_image("new_button.png")
        time.sleep(0.50)
        # Don't save last one
        click_at_image("no.png")

if __name__ == "__main__":
    main()

Essentially I had to resort to using screenscraping to click the non-accessible buttons. If this was for something that needed to be more robust, I'd have done this in C# using the Win32 API directly for everything except the screen scraping with some additional checks to wait for windows to appear rather than using dumb timers.

That being said, this works and may be helpful for future readers.

like image 164
Persistence Avatar answered Oct 02 '22 00:10

Persistence