通过挂钩直接将击键发送到另一个进程
本文关键字:进程 另一个 | 更新日期: 2023-09-27 18:33:04
在摆弄了SendInput,SendKeys,PostMessage,SendMessage,SendNotifyMessage,keybd_event等各种问题之后,我想知道。要找到那个好...尝试将键盘输入发送到另一个非前台进程是非常挑剔和不可靠的。
我尝试了一种 SendInput 方法,其中我欺骗了 Z 顺序(以将当前窗口保持在顶部(并快速将第三方窗口前景、发送输入并重新前景我的窗口。其中最终失败了,而且,不知何故,不知道为什么,还设法在我的窗口上处理击键,而不是前景(导致两个窗口之间的发送和接收的无限循环,直到我设法关闭进程(。
我尝试了SendMessage和PostMessage的不同组合。一个用于向下,一个用于向上,因为同时用于向下和向上会导致问题,例如两者都使用 PostMessage,导致密钥在接收窗口上重复。或两者的SendMessage,这会导致文本输入问题,但其他功能工作正常。用于键关闭的SendMessage和用于KeyUp的PostMessage适用于所有功能,但可靠性急剧下降,并且增加了关键事件的延迟。只有用于键控的PostMessage和用于键控的SendMessage的组合设法做了任何有用的事情,键控注册的失败率可能为5-10%。SentNotifyMessage也是如此(就可靠性而言,其行为方式与SendMessage基本相同(。
所以从本质上讲,我处于白头,我想知道如何直接将钩子注入目标窗口,并做一些巫毒教以这种方式向其发送击键,绕过消息队列等。唯一的问题是我在注入/挂钩等方面非常不了解。所以我转向你,社区。
咋办?
这是一个小代码,允许您将消息发送到后台应用程序。例如,要发送"A"字符,只需调用sendKeystroke(Keys.A(,并且不要忘记使用命名空间System.windows.forms来使用Keys对象。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace keybound
{
class WindowHook
{
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
public static void sendKeystroke(ushort k)
{
const uint WM_KEYDOWN = 0x100;
const uint WM_SYSCOMMAND = 0x018;
const uint SC_CLOSE = 0x053;
IntPtr WindowToFind = FindWindow(null, "Untitled1 - Notepad++");
IntPtr result3 = SendMessage(WindowToFind, WM_KEYDOWN, ((IntPtr)k), (IntPtr)0);
//IntPtr result3 = SendMessage(WindowToFind, WM_KEYUP, ((IntPtr)c), (IntPtr)0);
}
}
}
你可能不得不搞砸这个,但你可以通过进程发送数据。这可能不适用于您的情况,但这是一个想法。
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
static void Send(string message)
{
Process[] notepads = Process.GetProcessesByName("notepad");
if (notepads.Length == 0)
return;
if (notepads[0] != null)
{
IntPtr child = FindWindowEx(notepads[0].MainWindowHandle,
new IntPtr(0), "Edit", null);
SendMessage(child, 0x000C, 0, message);
}
}
如果这不起作用,您可以随时执行以下操作:
System.Threading.Thread.Sleep(1000);
//User clicks on active form.
System.Windows.Forms.Sendkeys.Sendwait("<Message>");