You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中如何向外部进程窗口发送键盘输入?

向外部进程发送键盘输入的解决方案

你已经通过以下代码启动并等待进程:

Process reprocessor = Process.Start(@"C:\Scripts\Tools\Reprocessor\reprocessor.exe");

// 等待进程启动
Process[] processes;
do
{
    processes = Process.GetProcessesByName("reprocessor");    
    Thread.Sleep(1000);
}
while (processes.Length == 0);

但使用SendMessage未成功,大概率是未定位到正确的窗口/控件句柄,或是未先激活目标窗口。下面是几种靠谱的实现方式:


方法1:使用SendKeys(简单易用,适合大多数场景)

SendKeys会向当前活动窗口发送按键,所以需要先将目标进程的窗口设为前台。

实现代码:

using System.Diagnostics;
using System.Threading;
using System.Windows.Forms; // 需要引用System.Windows.Forms程序集

// 获取进程的主窗口句柄
IntPtr mainWindowHandle = processes[0].MainWindowHandle;

// 激活窗口
SetForegroundWindow(mainWindowHandle);
Thread.Sleep(500); // 等待窗口激活

// 发送按键:例如Ctrl+Tab,再按数字键1
SendKeys.SendWait("^{TAB}"); // ^代表Ctrl键
SendKeys.SendWait("1");

需要添加Windows API声明:

[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);

方法2:使用SendInput(底层模拟,不依赖前台窗口)

SendInput直接模拟硬件输入,不需要激活窗口,但实现稍复杂,适合需要后台操作的场景。

实现代码:

using System.Runtime.InteropServices;

// 定义API结构和函数
[StructLayout(LayoutKind.Sequential)]
private struct INPUT
{
    public uint Type;
    public INPUTUNION Data;
}

[StructLayout(LayoutKind.Explicit)]
private struct INPUTUNION
{
    [FieldOffset(0)]
    public KEYBDINPUT Keyboard;
}

[StructLayout(LayoutKind.Sequential)]
private struct KEYBDINPUT
{
    public ushort Vk;
    public ushort Scan;
    public uint Flags;
    public uint Time;
    public IntPtr ExtraInfo;
}

[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);

// 模拟按下和释放按键的方法
private static void SimulateKey(ushort keyCode, bool isPress)
{
    INPUT input = new INPUT();
    input.Type = 1; // 键盘输入类型
    input.Data.Keyboard.Vk = keyCode;
    input.Data.Keyboard.Flags = isPress ? 0 : 2; // 0=按下,2=释放
    input.Data.Keyboard.Time = 0;
    input.Data.Keyboard.ExtraInfo = IntPtr.Zero;

    INPUT[] inputs = new INPUT[1];
    inputs[0] = input;
    SendInput(1, inputs, Marshal.SizeOf(typeof(INPUT)));
}

// 使用示例:发送Ctrl+Tab,再按数字1
public static void SendKeysToProcess()
{
    // 按下Ctrl
    SimulateKey((ushort)Keys.ControlKey, true);
    // 按下Tab
    SimulateKey((ushort)Keys.Tab, true);
    // 释放Tab
    SimulateKey((ushort)Keys.Tab, false);
    // 释放Ctrl
    SimulateKey((ushort)Keys.ControlKey, false);

    Thread.Sleep(200);

    // 按下数字1
    SimulateKey((ushort)Keys.D1, true);
    SimulateKey((ushort)Keys.D1, false);
}

方法3:正确使用PostMessage(需要定位目标控件句柄)

如果SendMessage无效,可能是因为你直接发送到了进程的主窗口,而实际接收输入的是窗口内的子控件。可以通过VS自带的Spy++工具找到目标控件的句柄,再发送消息。

实现代码:

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

private const uint WM_KEYDOWN = 0x0100;
private const uint WM_KEYUP = 0x0101;

// 假设已找到目标控件的句柄targetHandle
SendMessage(targetHandle, WM_KEYDOWN, (IntPtr)Keys.Tab, IntPtr.Zero);
SendMessage(targetHandle, WM_KEYUP, (IntPtr)Keys.Tab, IntPtr.Zero);

额外注意:

  • 如果目标进程是WinForms,主窗口句柄可能需要等待加载完成,可以在循环里补充判断:
    while (processes[0].MainWindowHandle == IntPtr.Zero)
    {
        Thread.Sleep(500);
        processes[0].Refresh();
    }
    
  • SendKeys需要确保目标窗口处于前台,否则会发送到当前活动窗口;SendInput则可以在后台模拟,但部分场景下需要管理员权限。

内容的提问来源于stack exchange,提问作者gclark18

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 17:36:32