单击其他程序工具栏中的按钮
Click Button in Toolbar of Other Program
我正在尝试在我没有源代码的遗留应用程序上自动化一些东西。所以我实际上是在尝试使用 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++ 没有显示该对象的其他子对象:
看着这个 AutomationElement
的 Current
属性 我没有看到任何东西跳到我身上但是 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 直接对除屏幕抓取之外的所有内容进行此操作并等待一些额外的检查windows 出现而不是使用哑计时器。
话虽这么说,这是有效的,可能对未来的读者有所帮助。
我正在尝试在我没有源代码的遗留应用程序上自动化一些东西。所以我实际上是在尝试使用 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++ 没有显示该对象的其他子对象:
看着这个 AutomationElement
的 Current
属性 我没有看到任何东西跳到我身上但是 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 直接对除屏幕抓取之外的所有内容进行此操作并等待一些额外的检查windows 出现而不是使用哑计时器。
话虽这么说,这是有效的,可能对未来的读者有所帮助。