c# - 单击其他程序工具栏中的按钮
问题描述
我正在尝试在我没有来源的遗留应用程序上自动化一些东西。所以我实际上是在尝试使用 Windows API 来单击我需要的按钮。
有一个类型如下的工具栏msvb_lib_toolbar
:
我可以通过使用以下代码来处理它(我认为):
IntPtr window = FindWindow("ThunderRT6FormDC", "redacted");
IntPtr bar = FindWindowEx(window, IntPtr.Zero,"msvb_lib_toolbar",null);
查看文档,似乎我应该能够使用SendMessage
并TB_PRESSBUTTON
单击这些按钮的消息:
[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
但是,我不确定如何设置wParam
并lParam
单击栏上的所需按钮。该文档似乎也没有太大帮助。
您能否提一些建议?
根据评论,我也尝试过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++ 没有显示该对象的更多子对象:
看着这个Current
属性,AutomationElement
我看不到任何东西向我跳来,但BoundingRectangle
似乎确实表明我找到了正确的元素。
使用inspector.exe
也不表示工具栏上有任何子项。
解决方案
不是一个真正理想的解决方案,但我使用 和 的组合得到了一些快速而肮脏的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 来处理除了屏幕抓取之外的所有内容,并通过一些额外的检查来等待窗口出现,而不是使用愚蠢的计时器。
话虽如此,这很有效,可能对未来的读者有所帮助。
推荐阅读
- python - 如何每秒使用字符串提要更新字符串列表?
- reactjs - 如何在 React.js 中使用函数之外的变量
- mysql - 更新语句中的编程列名和 where 条件
- javascript - 在不同的本地 npm 包中使用本地 npm 包
- java - Spring Security 和 Keycloak 因自定义身份验证提供程序而失败
- java - 在Java中,是否可以有两个具有完全相同签名的函数,除了一个是静态的
- python - 使用Python / elementtree / pandas将xml转换为csv时如何保留前导0
- python - 在时间序列数据中插入行作为分隔符
- python - 将数据帧行拆分为多个小数值
- python - Discord.py - 为什么我的机器人每条消息发送两次?