c# - 单击其他程序工具栏中的按钮

标签 c# winapi ui-automation user32

我正在尝试在我没有源的遗留应用程序上自动化一些东西。所以我基本上是在尝试使用 Windows API 来单击我需要的按钮。
有一个类型为 msvb_lib_toolbar 的工具栏看起来像这样:
Toolbar
我可以通过使用以下代码来处理它(我认为):

IntPtr window = FindWindow("ThunderRT6FormDC", "redacted");
IntPtr bar = FindWindowEx(window, IntPtr.Zero,"msvb_lib_toolbar",null);
查看文档,似乎我应该可以使用 SendMessageTB_PRESSBUTTON单击这些按钮的消息:
[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
但是,我不确定如何设置 wParamlParam单击栏上的所需按钮。该文档似乎也没有多大帮助。
您能否提一些建议?

根据评论,我也试过 UIAutomation .我可以使用以下代码找到工具栏:
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"));
但是从这里开始,我不确定该怎么做,因为 Spy++ 没有显示此对象的其他子项:
Spy++
望着 Current此属性 AutomationElement除了 BoundingRectangle 之外,我什么也看不见。似乎表明我找到了正确的元素。
Debugger
使用 inspector.exe也不会在工具栏上指示任何子项。
Inspector

最佳答案

不是一个理想的解决方案,但我使用 pywinauto 的组合得到了一些快速而肮脏的工作和 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()
本质上,我不得不求助于使用屏幕抓取来单击无法访问的按钮。如果这是为了需要更强大的东西,我会在 C# 中这样做使用 Win32 API 直接用于除屏幕抓取之外的所有内容,并带有一些额外的检查以等待窗口出现,而不是使用愚蠢的计时器。
话虽如此,这很有效,可能对 future 的读者有所帮助。

关于c# - 单击其他程序工具栏中的按钮,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62638138/

相关文章:

c++ - GET_X_LPARAM 给出负值

windows - 检索 Windows 10 电源模式 slider 的状态

c# - 限制非数值运算

winforms - 如何将 WinForm 窗口捕获为不带插入符号的位图

c# - 比较 List<string> 是否包含字符串 C#

ios - 如何获取应用程序 iOS UIA 自动化的 Bundle Id

android - 如何进行 10 次快速点击 [UIautomator]

python - 在 python 中识别 windows/linux GUI 中的文本以进行自动化测试

c# - 如何枚举所有可用的无线网络并将它们显示在列表框中?

C# HasValue 与 !=null