通过挂钩直接向另一个进程发送击键

Hyd*_*dra 19 c# winapi code-injection sendmessage c#-4.0

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

我尝试了一种SendInput的方法,我在其中欺骗Z顺序(保持当前窗口在顶部)并快速前进第三方窗口,发送输入,并重新前景我的窗口.其中最终失败了,而且,不知何故,不知道为什么,设法同时也在我的窗口上触发键盘而不是前景(导致在两个窗口之间发送和接收的无限循环,直到我设法关闭该过程).

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

基本上,我已经结束了,我想知道直接在目标窗口中注入一个钩子,并做一些伏都教以这种方式向它发送击键,绕过消息队列等.这样做将会不会触发全局键事件,只会影响目标窗口.唯一的问题是,当涉及到注射/挂钩等时,我是不可知的.所以我转向你,社区.

哇呢?

Lou*_*bob 16

这是一个小代码,允许您将消息发送到后台应用程序.例如,要发送"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);
    }
}
}
Run Code Online (Sandbox Code Playgroud)

  • PostMessage对此非常有用.使用Spy ++帮助我构建消息,使其看起来与我从实际键盘中完全一样. (4认同)
  • 刚刚在 Windows 10 上试过这个,但没有效果。不确定是我做错了什么还是它不再起作用了? (2认同)

小智 8

你可能不得不搞乱这个,但你可以通过进程发送数据.这可能不适用于您的情况,但这是一个想法.

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);
         }
     }
Run Code Online (Sandbox Code Playgroud)

如果这不起作用,你可以随时做:

System.Threading.Thread.Sleep(1000);
//User clicks on active form.
System.Windows.Forms.Sendkeys.Sendwait("<Message>");
Run Code Online (Sandbox Code Playgroud)

  • 您可以使用Spy ++找出lpClassName是什么.如果lpClassName为NULL,则FindWindow将查找标题与lpWindowName参数匹配的任何窗口.(https://msdn.microsoft.com/en-us/library/windows/desktop/ms633499(v=vs.85).aspx) (2认同)