为什么 SendMessage 对某些应用程序不起作用?

Blu*_*bin 2 python winapi win32gui

背景:

我试图编写一个自动点击器来在后台点击应用程序(Roblox,而不是试图做任何恶意的事情)。我能够获取该窗口并执行诸如关闭它之类的命令。但是,当尝试将点击发送到窗口时,它会返回 0。(我正在使用 SendMessage,因此不会激活窗口。)

最小可重现示例:

import win32gui
import win32con
import win32api
Run Code Online (Sandbox Code Playgroud)
hwnd = win32gui.FindWindow(None, "Roblox")

while True:
    lParam = win32api.MAKELONG(100, 100)
    temp = win32gui.SendMessage(hwnd, win32con.WM_LBUTTONDOWN, None, lParam)
    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONUP, None, lParam)
    print(temp)
Run Code Online (Sandbox Code Playgroud)

我尝试过的事情:

  1. 我尝试更改窗口以查看是否是错误的窗口,或者是否没有看到该窗口

  2. 我尝试正常发送消息:

    lParam = win32api.MAKELONG(100, 100)  # Get the coordinates and change to long
    temp = win32gui.SendMessage(hwnd, win32con.WM_LBUTTONDOWN, None, lParam)  # Send message to handle
    win32gui.SendMessage(hwnd, win32con.WM_LBUTTONUP, None, lParam)  # Release key from sent message to handle
    
    Run Code Online (Sandbox Code Playgroud)
  3. 我在其他窗口上尝试过,它有效,但不适用于 Roblox

  4. 我尝试使用其他命令并且它有效,但点击却不起作用。这有效:(所以我知道这是正确的窗口)

    temp = win32gui.SendMessage(hwnd, win32con.WM_CLOSE, 0, 0)  # Close window with SendMessage
    
    Run Code Online (Sandbox Code Playgroud)

IIn*_*ble 8

你不能这样做。

\n

让我们首先重新表述问题陈述,以便更容易理解,为什么会出现这种情况:

\n
\n

“如何说服通过决定或巧合选择忽略鼠标输入消息\xe2\x80\x94的程序\xe2\x80\x94确认鼠标输入消息?”

\n
\n

事实证明,这部分实际上已经解决了。作为注释的文档WM_LBUTTONDOWN

\n
\n

如果应用程序处理此消息,它应该返回零。

\n
\n

您得到的结果为零,因此没有理由质疑消息已按照应用程序认为必要的程度进行处理这一事实。这可能属于“巧合”分支,其中应用程序对鼠标消息不感兴趣,而只是将它们传递到DefWindowProc,所有相关性不足以甚至忽略的消息的厨房水槽。

\n

这里的关键见解是:需要处理和响应鼠标输入的程序可以决定忽略鼠标输入消息1。(基于鼠标消息处理的客户端可以轻松识别虚假输入消息,并通过不完全响应来响应。)

\n

因此,从本质上讲,发送(或发布)假鼠标消息是行不通的。可靠。曾经。

\n

这基本上给你留下了 3 种选择:

\n\n

列出前两个选项只是为了完整性。它们通常可用于积极支持自动化的应用程序。游戏通常不会,并且防范这些途径既简单又便宜:应用程序不需要执行任何操作

\n

SendInput也行不通。就系统而言,注入的输入的处理方式与任何其他输入相同(这篇博客文章提供了一个有用的说明)。具体来说,当在窗口上单击鼠标时,该窗口将进入前台。因此,这不符合将应用程序置于“后台”的要求。

\n

即使情况并非如此,注入的输入也可以轻松可靠地识别。获得一个所需的全部就是低级鼠标钩子MSLLHOOKSTRUCT,其flags字段可以轻松地提供此信息。由于低级挂钩能够阻止输入传递到系统,因此return 1;只需使用 a 即可过滤掉这些输入事件。

\n
\n

这涵盖了所有支持的外部应用程序自动化方法。这是一条死胡同,根本不值得越过。

\n
\n

现在,如果使用虚假输入自动化在后台运行的应用程序总结了要求,那么您唯一的选择就是在虚拟化环境中运行该应用程序(这可确保单击保持在虚拟环境内,并且不会带来应用到前面)。请记住,上述所有限制仍然适用,并且您不能使用上述任何方法。您必须实现并安装一个自定义鼠标驱动程序,该驱动程序生成的输入与真正的硬件源输入事件无法区分。

\n

但即便如此,应用程序仍然有办法发现它们正在虚拟化环境中运行,并在运行时拒绝运行。

\n
\n

底线是:作弊很难。真的很难。而且您的问题没有简单的解决方案。

\n
\n

1 为方便起见,鼠标输入消息由系统生成。它们代表了对硬件输入事件的有用(且有损)抽象。“标准”应用程序通常不需要这些硬件输入事件的完全保真度。
另一方面,游戏通常会使用较低级别的输入处理基础设施,例如原始输入,甚至不会查看任何较高级别的处理工件。

\n