在 C# 中,通过 Windows API 实现向其他程序的窗口发送按键信息

在 C# 中,向其他程序的窗口发送按键信息可以通过 Windows API 实现。具体步骤如下:


实现思路

激活目标窗口:

    使用 SetForegroundWindow 函数将目标窗口设置为前台窗口。

发送按键信息:

    SendInput 是 Windows API 中用于模拟键盘和鼠标输入的函数,比 PostMessage 更可靠。


代码实现

以下是完整的代码示例:

using System;using System.Diagnostics;using System.Linq;using System.Runtime.InteropServices;
class Program{    // 导入 Windows API 函数    [DllImport("user32.dll")]    private static extern bool SetForegroundWindow(IntPtr hWnd);
    [DllImport("user32.dll")]    private static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
    // 定义 INPUT 结构    private struct INPUT    {        public uint Type;        public InputUnion Data;    }
    [StructLayout(LayoutKind.Explicit)]    private struct InputUnion    {        [FieldOffset(0)]        public MOUSEINPUT MouseInput;        [FieldOffset(0)]        public KEYBDINPUT KeyboardInput;    }
    private struct MOUSEINPUT    {        public int dx;        public int dy;        public uint mouseData;        public uint dwFlags;        public uint time;        public IntPtr dwExtraInfo;    }
    private struct KEYBDINPUT    {        public ushort wVk;        public ushort wScan;        public uint dwFlags;        public uint time;        public IntPtr dwExtraInfo;    }
    // 常量    private const uint INPUT_KEYBOARD = 1;    private const uint KEYEVENTF_KEYDOWN = 0x0000;    private const uint KEYEVENTF_KEYUP = 0x0002;    private const uint KEYEVENTF_UNICODE = 0x0004;
    static void Main(string[] args)    {        // 目标进程名(例如记事本的进程名)        string processName = "notepad";
        // 目标窗口标题(可以为空,表示不筛选窗口标题)        string windowTitle = "无标题 - 记事本";
        // 查找目标进程        var targetProcess = FindProcessByNameAndTitle(processName, windowTitle);        if (targetProcess == null)        {            Console.WriteLine("未找到目标进程!");            return;        }
        // 获取目标窗口句柄        IntPtr hWnd = targetProcess.MainWindowHandle;        if (hWnd == IntPtr.Zero)        {            Console.WriteLine("未找到目标窗口!");            return;        }
        // 激活目标窗口        SetForegroundWindow(hWnd);
        // 发送按键信息        SendKeys("Hello World!");
        Console.WriteLine("按键信息已发送!");    }
    static Process FindProcessByNameAndTitle(string processName, string windowTitle)    {        // 获取所有目标进程        var processes = Process.GetProcessesByName(processName);        // 筛选窗口标题        if (!string.IsNullOrEmpty(windowTitle))        {            processes = processes                .Where(p => p.MainWindowTitle.Contains(windowTitle))                .ToArray();        }        // 返回第一个匹配的进程        return processes.FirstOrDefault();    }
    static void SendKeys(string text)    {        foreach (char c in text)        {            SendKey(c);        }    }
    static void SendKey(char key)    {        // 创建按键按下和释放的输入        INPUT[] inputs = new INPUT[2];        inputs[0] = CreateKeyboardInput(key, KEYEVENTF_KEYDOWN | KEYEVENTF_UNICODE);        inputs[1] = CreateKeyboardInput(key, KEYEVENTF_KEYUP | KEYEVENTF_UNICODE);        // 发送输入        SendInput(2, inputs, Marshal.SizeOf(typeof(INPUT)));    }
    static INPUT CreateKeyboardInput(char key, uint flags)    {        return new INPUT        {            Type = INPUT_KEYBOARD,            Data = new InputUnion            {                KeyboardInput = new KEYBDINPUT                {                    wVk = 0,                    wScan = key,                    dwFlags = flags,                    time = 0,                    dwExtraInfo = IntPtr.Zero                }            }        };    }}


代码说明

SendInput:

    用于模拟键盘和鼠标输入。支持 Unicode 字符和特殊按键。

INPUT 结构:

    定义键盘输入的数据结构。

SendKeys:

    遍历字符串中的每个字符,依次发送按键按下和释放事件。

CreateKeyboardInput:

    创建键盘输入事件(按下或释放)


使用示例

打开记事本(或其他目标程序)。

运行上述代码。

代码会找到记事本窗口,并向其发送 Hello World! 的按键信息。


扩展:发送特殊按键

如果需要发送特殊按键(如 Enter),可以使用虚拟键码:

private const ushort VK_RETURN = 0x0D;
static void SendSpecialKey(ushort virtualKeyCode){    // 创建按键按下和释放的输入    INPUT[] inputs = new INPUT[2];    inputs[0] = CreateKeyboardInput(virtualKeyCode, KEYEVENTF_KEYDOWN);    inputs[1] = CreateKeyboardInput(virtualKeyCode, KEYEVENTF_KEYUP);
    // 发送输入    SendInput(2, inputs, Marshal.SizeOf(typeof(INPUT)));}
static INPUT CreateKeyboardInput(ushort virtualKeyCode, uint flags){    return new INPUT    {        Type = INPUT_KEYBOARD,        Data = new InputUnion        {            KeyboardInput = new KEYBDINPUT            {                wVk = virtualKeyCode,                wScan = 0,                dwFlags = flags,                time = 0,                dwExtraInfo = IntPtr.Zero            }        }    };}
// 发送 Enter 键SendSpecialKey(VK_RETURN);

注意事项

权限问题:

    如果目标程序以管理员权限运行,当前程序也需要以管理员权限运行。

Unicode 字符:

    使用 KEYEVENTF_UNICODE 标志发送 Unicode 字符。

多窗口问题:

    如果目标进程有多个窗口,可能需要进一步筛选(如通过窗口类名)。


通过 SendInput 函数可以更可靠地模拟键盘输入,适用于发送普通字符和特殊按键。以上代码展示了如何根据进程名和窗口标题筛选窗口,并通过 SendInput 发送按键信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_38220914

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值