[英]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.
所以我实际上是在尝试使用 Windows API 来单击我需要的按钮。
There is a toolbar of type msvb_lib_toolbar
that looks like this:有一个
msvb_lib_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:查看文档,似乎我应该能够使用
SendMessage
和TB_PRESSBUTTON
消息来单击这些按钮:
[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.但是,我不确定如何设置
wParam
和lParam
以单击栏上的所需按钮。 The documentation doesn't seem to be helping much either.该文档似乎也没有太大帮助。
Could you please advise?您能否提一些建议?
Based on comments, I've also tried UIAutomation
.根据评论,我也尝试过
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++ 没有显示此 object 的其他子代:
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.看着这个
AutomationElement
的Current
属性,我看不到任何东西跳出来,但BoundingRectangle
似乎确实表明我找到了正确的元素。
Using inspector.exe
also doesn't indicate any children on the toolbar.使用
inspector.exe
也不表示工具栏上有任何子项。
Not really an ideal solution but I got something quick and dirty working using a combination of pywinauto
and pyautogui
.不是一个真正理想的解决方案,但我使用
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()
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.如果这是为了需要更强大的东西,我会在
C#
中使用Win32
API 直接针对所有内容执行此操作,除了屏幕刮擦并进行一些额外的检查以等待 Z0F4137ED1502B5045D6083AA258B 出现,而不是使用愚蠢的计时器出现。
That being said, this works and may be helpful for future readers.话虽如此,这很有效,可能对未来的读者有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.