【问题标题】:Is there any way to wait for a PostMessage to be processed by the recipient?有什么方法可以等待收件人处理 PostMessage 吗?
【发布时间】:2014-10-26 04:26:33
【问题描述】:

我遇到的问题是,在发布一些 WM_KEYDOWN/WM_KEYUP 消息后,我需要使用 Thread.Sleep 至少 200 毫秒,然后才能发布 WM_LMOUSEDOWN/WM_LMOUSEUP 消息。如果我不这样做,接收者会首先处理鼠标单击,这意味着较早的击键会转到目标句柄的错误位置。 我不能使用 SendMessage,因为收件人忽略了 WM_KEYDOWN/WM_KEYUP。

有什么方法可以等待 PostMessage 被处理?

【问题讨论】:

  • 你为什么要伪造输入?
  • 呃,UI自动化有UIAutomation
  • 不,我正在编写的应用程序应该能够与任何 gui 一起使用,例如flash 或 java 应用程序.. 为什么这很重要?
  • 有人想知道为什么目标应用程序会乱序处理排队的消息
  • 没错。这就是我问这个问题的原因。

标签: c# winapi message-queue


【解决方案1】:

有什么方法可以等待 PostMessage 被处理?

不,没有。没有 API 可让您等待或收到已发布消息已被收件人处理的通知。

【讨论】:

  • 但是,SendMessageCallback 基本上就是这样做的。即使消息没有发布(因此移动到输入队列的前面),跨线程使用时的效果是相同的,就目标应用程序而言。对GetMessage 的调用不是从队列中检索第一条消息,而是调度所有从其他线程发送的排队消息,然后继续从消息队列中检索第一条消息。
  • @IInspectable 这不是真正的可比性。发送的消息直接发送到窗口过程。通过调用GetMessage 提取发布的消息,并在消息循环中进行处理。这通常但不一定会调用TranslateMessage,然后调用DispatchMessage。很难确定目标应用是什么,或者正在做什么。
  • SendMessage 跨线程时,发送的消息将全部排队。它们不会立即派出,还需要调用GetMessage/PeekMessage 才能派出。跨线程时,SendMessageNotify(或SendMessageCallback)和PostMessage 几乎相同。
  • @IInspectable 我的意思是,如果目标应用程序直接处理某些输入消息,而不是调用DispatchMessage,那么如果输入消息是发送而不是发布,那么该代码将不会执行。
  • 跨线程时,发送消息排队,并作为调用GetMessage/PeekMessage的一部分发送。这可能会导致宁愿不发送某些(输入)消息的应用程序失败,而 posted 消息将得到正确处理。您对效果的解释是正确的,而导致它的复杂性略有不准确。
【解决方案2】:

您可以将SetWindowsHookExWH_GETMESSAGE 一起使用。

dll 中的CALLBACK 函数MsgProc 将通知您的应用程序任何将由目标应用程序和所有其他应用程序处理的消息。

您还可以使用VirtualAllocExWriteProcessMemory 注入一些shellcode,通知您的应用程序目标应用程序将要处理的消息。

然后使用SetWindowLongPtrGWLP_WNDPROC修改窗口过程指向注入的shell代码,并确保注入的shell代码最后CallWindowProcGetWindowLongPtrGWLP_WNDPROC的返回值。

显然,GetWindowLongPtrGWLP_WNDPROC 应该在 SetWindowLongPtrGWLP_WNDPROC 之前首先被调用。

你的应用也可以DebugActiveProcess目标应用,在GetWindowLongPtr返回的地址处插入断点GWLP_WNDPROC

当目标应用程序派发消息并调用窗口过程时,目标应用程序到达断点,通知您的应用程序目标应用程序已到达断点,然后目标应用程序被挂起。

此时你的应用程序可以调用GetThreadContext来检索到达断点的线程栈帧上的四个​​参数。

这四个参数正是目标应用程序即将处理的消息。

如果目标应用程序中的WM_KEYDOWNWM_KEYUP 都只调用一个带有一个UINT 参数的函数,并且如果您成功找到这些函数的入口点,那么CreateRemoteThreadWaitForSingleObject 也可以正常工作。

【讨论】:

  • 我已经有一段时间没有放弃这个问题了,因为我不想使用复杂的黑客技术。我没有深入研究您可能的解决方案,但它不是只考虑发送的消息而不是发布的消息吗?正如我所写:“我不能使用 SendMessage,因为收件人忽略了那些作为 WM_KEYDOWN/WM_KEYUP”如果您仍然认为您的解决方案有效,您可能需要咨询 David Heffernan,他发布的答案与您的直接矛盾。
【解决方案3】:

是的:只需使用SendMessage 而不是PostMessage(请注意,SendMessage 在由不同的线程使用时会带来死锁风险,并且 GUI 线程出于任何原因偶然等待该线程)

一般情况下:如果您需要伪造输入,则永远不要自己发布消息。相反,您应该使用SendInput()

【讨论】:

  • 正如我所写,它必须是 PostMessage,因为目标应用程序忽略了 SendMessage。
  • 这不是答案,SendMessage 不好,可能导致内存问题等(它不等待任何其他消息)
  • @vtz SendMessage 工作正常。它是Win32的重要组成部分。您遇到的任何问题都是由于您自己的代码中的缺陷、SendMessage 的滥用等造成的。
  • @DavidHeffernan 你是对的,关于我的问题,问题不在于使用 SendMessage 和字符串变量,当我用字符文本缓冲区更改它然后使用 SendMessage 是我需要的。谢谢!
猜你喜欢
  • 2020-12-10
  • 1970-01-01
  • 2020-03-02
  • 2021-07-05
  • 1970-01-01
  • 2020-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多