【问题标题】:PostMessage and SendMessage WM_SETCURSOR, WM_LBBUTTONDOWN/UP etc all send xPox0, yPos0PostMessage 和 SendMessage WM_SETCURSOR, WM_LBBUTTONDOWN/UP 等都发送 xPox0, yPos0
【发布时间】:2011-09-30 00:34:25
【问题描述】:

我正在编写一个 C# 程序来将点击从一个窗口发送到另一个窗口。我正在使用 winapi 中的 SendMessage 和 PostMessage。 SendMessage 适用于键盘事件,但是当我尝试使用它发送鼠标事件时,它总是发送鼠标坐标 0,0。我可以使用 spy++ 验证应用程序正在接收事件,但 x 和 y 位于 (0,0) 并且应用程序认为鼠标在屏幕外 NCHITTEST=NOTCLIENT。

代码如下:

PostMessage(appWin, (int)WMessages.WM_MOUSEMOVE, 0, MakeDword(300, 200));

PostMessage 声明为:

[DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]
protected static extern bool PostMessage(IntPtr hwnd, uint Msg, long wParam, long lParam);

其中 appWin 是窗口的句柄(用 spy++ 验证它接收事件)。 该窗口根本没有控件。 我还尝试了多个宏 MakeLParam、MakeDword、手工完成等。 我正在使用Windows7。

我昨晚/今天早上的大部分时间都在试图找出问题所在,但我一直没能找到。虽然网上有很多关于 Post/SendMessage 的帖子,但我只能找到一个出现类似问题并且没有答案的帖子。

总结问题: 有谁知道为什么 SendMessage 会向应用程序窗口发送正确的消息,而不是将 x 和 y 坐标传递给它,因为它总是传递 (0,0)?

谢谢!

【问题讨论】:

  • 伪造输入并不容易。有时你可以让它与 SendMessage/PostMessage 一起工作,但通常会失败。你要做的就是打电话给SendInput(),或者更容易使用的mouse_event()。
  • 感谢您的回答,但是 SendInput() 和 mouse_event() 都通过将事件注入设备队列来控制真正的鼠标。我需要真正的鼠标不受影响。您还有其他想法吗?
  • 不,我没有更多的想法。您是否准备好应对您所尝试的方法不起作用的可能性?
  • 如果你说我是否考虑过不可能做到的可能性,那么答案是否定的。如果您的意思是我是否想过我可能没有正确的技能来解决这个问题,那么我不得不说我仍然乐观地看到注入键盘输入正在起作用,我认为这里的问题是对于有经验的人来说很容易发现/解决。我希望这里有这样的人能善待我。
  • 我认为没有SendInput 就不可能。目标应用是什么?你想用伪造的输入做什么?也许还有另一种方法可以实现您的目标。我不认为您的最终目标是伪造输入。你可能有一个更平淡无奇的目标!

标签: c# objective-c winapi postmessage


【解决方案1】:

我想我终于可以看出你的代码有什么问题了。

[DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)] 
static extern bool PostMessage(IntPtr hwnd, uint Msg, long wParam, long lParam);

问题是long 在 C# 中是 64 位宽。在 32 位进程中这是不正确的,因为这些参数应该是 32 位宽。我原以为您在通过调试器运行时会看到堆栈不平衡警告。

正确的声明是:

static extern bool PostMessage(IntPtr hwnd, uint Msg, IntPtr wParam, IntPtr lParam);

您绝对不需要切换到本机 C++ 代码即可使其工作。

【讨论】:

  • 谢谢,说得有道理,现在就去测试一下,让你知道。
  • 嘿,我没有足够的代表来投票给你,但你的回答是正确的。我使用以下代码重新测试:SendMessage(hWndFour, (uint)WMessages.WM_LBUTTONDOWN, IntPtr.Zero, (IntPtr)MAKELPARAM(10, 10)); 其中:[DllImport("user32.dll", CharSet = CharSet.Auto)] static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lparam); 它工作正常。感谢您的帮助
  • 即使不能投票也可以接受。使答案顶部旁边的勾变为绿色。
【解决方案2】:

发布我自己问题的答案,因为有 cmets 大意是不可能做到的。

我不确定为什么它在 C# 中不起作用,可能是打字/转换问题,可能是它处理 lparam 的方式问题。在任何情况下,我在 C++ 中编写了相同的代码并将其设为 dll,所以现在我使用控制处理程序和输入从 dll 调用该函数,并将输入发送到适当的控件。直接通过 c++ 使用 windows api 工作正常。

感谢您的帮助。

【讨论】:

  • FWIW 我认为可能无法使用PostMessage 的原因是,某些应用程序将使用消息中的信息,这些信息仅在消息由SendInput 生成时可用。跨度>
  • 啊,我明白了。这更像是应用程序接收到正确消息但没有响应它们的情况。在这种情况下,消息永远不会被正确发送(x,y=0)。
  • 是的,没错。恐怕我对long 的了解非常缓慢。很难将这些不同语言的所有细微差别留在你的大脑前面。反正我从不写 C#,所以这特别难。
  • 同样,这是我第一次用 C# 编写,我想是时候写点新东西了。到目前为止我喜欢它,但托管/非托管交易变得非常烦人。
【解决方案3】:

出于与 emist 相同的原因,我一直在尝试使用 PostMessage/SendMessage 注入鼠标输入。这里遗漏的一个重要问题是 C# 应用程序(或者可能只是 WPF 应用程序)需要在其应用程序清单中设置 uiAccess=true 标志。否则,消息永远不会真正发送。此外,还有一个Authenticode 障碍要通过才能允许这样做,Visual Studio 将拒绝运行调试,但您可以将调试器附加到正在运行的进程。希望这可以帮助任何来这个帖子的人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-20
    • 1970-01-01
    • 1970-01-01
    • 2013-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多