Delphi:模拟自动按键

2024-10-01 07:32:08 发布

您现在位置:Python中文网/ 问答频道 /正文

我想要一个外部控件的编辑。应用程序是用Delphi编写的。它有几种形式。我从Python库pywinauto+sendkeys开始测试第一个形式TLoginForm。它工作得很好。以下是伪代码:

helper = pywinauto.application.Application()
hwnd = pywinauto.findwindows.find_windows(class_name='TLoginForm')[0]
window = helper.window_(handle=hwnd)
ctrl = window[2]   # the second control is the edit control I want to access
ctrl.ClickInput()  # focus the control
ctrl.SetEditText('Hello world')  # text can be changed expectedly

作为第二步,我想为自动化工具创建一个UI。但是由于缺乏pythonui的知识,考虑到Python中二进制文件分发的复杂性,我想用Delphi来做。但奇怪的是,我无法使用Windows api在Delphi中读/写编辑控件。以下是一些尝试:

^{pr2}$

由于它在Python中工作,我想我一定错过了一些非常基本和非常重要的东西。但我现在太盲目了,找不到问题所在。如有任何提示,我们将不胜感激。在


Tags: the代码helper应用程序编辑window形式control
1条回答
网友
1楼 · 发布于 2024-10-01 07:32:08

But the weird thing is I am not able to read/write the edit control in Delphi by using Windows apis.

pywinauto使用标准的win32api,所以它能做的任何事情,都可以在Delphi中完成。在

pywinauto is open source,因此您可以看到ctrl.ClickInput()和{}是如何实现的。在

ctrl.ClickInput()调用^{}和{a3}。在

ctrl.SetEditText()发送一条^{}消息以突出显示编辑控件的当前文本,然后发送一条^{}消息,用新文本替换突出显示的文本。我猜想编辑控件的“反输入保护”可能不会阻止这些消息。在

另外需要注意的是,pywinauto倾向于在其他窗口/进程中执行操作后调用WaitForInputIdle()和{},给目标一些时间来处理这些操作。这可能是“反输入保护”试图清除自动代码但允许用户活动的一个因素。在

SetForegroundWindow(EditControlHandle); // Works, the application will be brought to front, the edit control will be focused

我从未听说过SetForegroundWindow()将子控件带到前台。即使是这样,SetForegroundWindow()也有许多限制,这些限制可能会阻止应用程序设置前景窗口。在

SetFocus(EditControlHandle); // Nothing happens, if it is focused at another edit control of the form currently

如果要将输入焦点更改为另一个进程中的窗口,则必须使用AttachThreadInput()将调用线程附加到目标窗口的线程。这在^{} documentation中有明确说明。在

SetText(EditControlHandle, 'Hello world'); // Nothing happens

SetText()不是标准的Win32 API函数。你是说^{}吗?SetWindowText()不能在另一个进程中设置窗口的文本,文档也这么说。在

或者SetText()WM_SETTEXT的包装?具有“anti-input protection”的控件可能会阻止它自己不生成的WM_SETTEXT消息。在

SendKeys32.SendKey('Hello world', {Wait=}True); // Nothing happens

SendKeys只是将击键放入系统的键盘队列中,让Windows将它们传递到焦点窗口。这应该是可行的,因为应用程序无法区分用户输入的击键和SendKeys注入的击键。除非目标应用程序挂接SendKeys()keybd_event()来检测注入的击键,也就是说。在

你试过这个代码了吗?在

http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_27432926.html

SendMessage(EditControlHandle, Ord('H'), WM_KEYDOWN, 0); // Nothing happens
SendMessage(EditControlHandle, Ord('H'), WM_KEYUP, 0);

您有MsgwParam参数值。Ord('H')是72,这是WM_POWER消息。编辑控件不关心电力状态的更改。在

发送这些消息时,还需要包含一些标志:

var
  ScanCode: UINT;

ScanCode := MapVirtualKey(Ord('H'), MAPVK_VK_TO_VSC);
SendMessage(EditControlHandle, WM_KEYDOWN, Ord('H'), ScanCode shl 16);
SendMessage(EditControlHandle, WM_KEYUP, Ord('H'), (ScanCode shl 16) or $C0000001);

FocusedThreadID := GetWindowThreadProcessID(ExternalAppMainWindowHandle, nil);

如果使用AttachThreadInput(),则需要附加到拥有编辑控件的线程,因此使用编辑控件的HWND,而不是其父HWND。在

if AttachThreadInput(GetCurrentThreadID, FocusedThreadID, {Attach=}True) then // Returns False

您使用的是什么版本的Windows?在Vista和更高版本上,GetLastError()如果AttachThreadInput()失败,则返回一个有效的错误代码。在

更新:在Delphi中,您展示的脚本的pywinauto源代码的大致翻译如下:

^{pr2}$

相关问题 更多 >