通过钩子直接将击键发送到另一个进程 [英] Directly sending keystrokes to another process via hooking

查看:17
本文介绍了通过钩子直接将击键发送到另一个进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道,在摆弄了 SendInput、SendKeys、PostMessage、SendMessage、SendNotifyMessage、keybd_event 等各种问题之后.为了找到那个好......尝试将键盘输入发送到另一个非前台进程是非常挑剔和不可靠的.

我尝试了一种 SendInput 方法,在该方法中我欺骗了 Z 顺序(将当前窗口保持在顶部)并快速将第 3 方窗口置于前台,发送输入,然后将我的窗口重新置于前台.其中最终失败了,而且,不知何故,不知道为什么,还设法在我的窗口上进行按键操作,而不是在前台(导致两个窗口之间发送和接收的无限循环,直到我设法关闭该进程).

我尝试了 SendMessage 和 PostMessage 的不同组合.一个用于向下,一个用于向上,因为同时使用向下和向上会导致问题,例如 PostMessage 用于两者,导致密钥在接收窗口上重复.或两者都使用 SendMessage,这会导致文本输入出现问题,但其他功能运行正常.用于 keydown 的 SendMessage 和用于 keyUp 的 PostMessage 适用于所有功能,但可靠性率急剧下降,并且增加了关键事件的延迟.只有用于 keydown 的 PostMessage 和用于 keyup 的 SendMessage 的组合才能做任何有用的事情,keyup 注册的失败率可能为 5-10%.SentNotifyMessage 也是如此(就可靠性而言,其行为方式与 SendMessage 基本相同).

所以本质上,我已经结束了,我想知道如何将钩子直接注入目标窗口,然后做一些伏都教以这种方式向它发送击键,绕过消息队列等.这样做不会触发全局键事件,只影响目标窗口的方式.唯一的问题是我在注入/挂钩等方面非常不了解.所以我求助于你,社区.

怎么办?

解决方案

这是一个允许您向后台应用程序发送消息的小代码.例如,要发送A"字符,只需调用 sendKeystroke(Keys.A),并且不要忘记使用命名空间 System.windows.forms 以便能够使用 Keys 对象.

使用系统;使用 System.Collections.Generic;使用 System.Linq;使用 System.Text;使用 System.Runtime.InteropServices;使用 System.Windows.Forms;命名空间键绑定{类 WindowHook{[DllImport("user32.dll")]public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);[DllImport("user32.dll")]公共静态外部 IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);[DllImport("user32.dll")]公共静态外部 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);}}}

I'm wondering, after fiddling with all sorts of issues with SendInput, SendKeys, PostMessage, SendMessage, SendNotifyMessage, keybd_event, etc and so forth. To find that well... trying to send a keyboard input to another non-foreground process is quite finicky and unreliable.

I tried a method of SendInput where I trick the Z-order (to keep the current window on top) and quickly foreground the 3rd party window, send the input, and re-foreground my window. Of which ultimately failed, and also, somehow, not sure why, managed to also proc the keystrokes on my window as well while not foreground (causing an infinite loop of sending and receiving between two windows until I managed to close the process).

I've tried different combinations of SendMessage and PostMessage. One for down, one for up, as using both for down and up leads to issues, like with PostMessage for both, causing the key to duplicate on the receiving window. or SendMessage for both, which caused issues with text entry, but other functions worked ok. SendMessage for keydown and PostMessage for keyUp worked for all functions, but the reliability rate dropped dramatically, as well as adding latency into key events. Only a combination of PostMessage for keydown, and SendMessage for keyup managed to do anything useful, with a maybe 5-10% fail rate of keyup registering. Same goes for SentNotifyMessage (behaves basically in the same fashion as SendMessage as far as reliability goes).

So essentially, I'm at whit's end, and I wanted to know about directly injecting a hook into the target window, and doing some voodoo to send keystrokes to it that way, bypassing the message queue etc. Doing so in a way that will not proc global key events, and only affect the target window. Only thing is I'm pretty unknowledgeable when it comes to injecting/hooking, etc. So I turn to you, community.

Wut do?

解决方案

This is a little code that allows you to send message to a backgrounded application. To send the "A" char for example, simply call sendKeystroke(Keys.A), and don't forget to use namespace System.windows.forms to be able to use the Keys object.

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);
    }
}
}

这篇关于通过钩子直接将击键发送到另一个进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆