如何在Delphi中运行命令行程序并向运行中的程序发送按键?
如何向通过ShellExecute启动的控制台程序发送按键输入?
嘿,你提到用ShellExecute(Handle, 'open', 'example.exe', nil, nil, SW_SHOWNORMAL);启动了一个等着用户按"q"的程序,想要自动给它发送这个按键对吧?我给你整理了两种实用的方法,看哪种更适配你的场景:
方法1:用Windows API模拟物理按键
这是最直观的方式,相当于替你手动按键盘,但前提是得找到目标程序的窗口句柄,步骤如下:
- 先通过
FindWindow(知道窗口标题的话)或者EnumWindows遍历找到example.exe的窗口句柄; - 把目标窗口激活到前台;
- 用
SendInput模拟按下再释放"q"键的动作。
给你写个Delphi的示例代码,直接就能用:
uses Windows; procedure SendQKeyToTargetApp; var TargetWnd: THandle; InputEvents: array[0..1] of TInput; begin // 替换成你的example.exe实际的窗口标题,比如它的控制台标题 TargetWnd := FindWindow(nil, 'Example Console Window'); if TargetWnd <> 0 then begin // 把窗口调到前台 SetForegroundWindow(TargetWnd); Sleep(100); // 给系统一点时间完成窗口激活,避免按键发错地方 // 模拟按下Q键 InputEvents[0].Itype := INPUT_KEYBOARD; InputEvents[0].ki.wVk := Ord('Q'); InputEvents[0].ki.dwFlags := 0; // 模拟释放Q键 InputEvents[1].Itype := INPUT_KEYBOARD; InputEvents[1].ki.wVk := Ord('Q'); InputEvents[1].ki.dwFlags := KEYEVENTF_KEYUP; // 发送这两个输入事件 SendInput(2, InputEvents[0], SizeOf(TInput)); end; end;
方法2:启动时重定向标准输入(更推荐)
如果你的场景允许换一种启动方式,那我强烈推荐用CreateProcess替代ShellExecute,同时重定向程序的标准输入流。这样你可以直接把"q"写入程序的输入流,完全不需要模拟按键,也不受窗口是否激活的影响,稳定性拉满。
同样给你Delphi示例:
uses Windows, SysUtils; procedure LaunchAppAndSendInput; var StartInfo: TStartupInfo; ProcInfo: TProcessInformation; StdInWriteHandle: THandle; BytesWritten: DWORD; InputChar: Char; begin ZeroMemory(@StartInfo, SizeOf(StartInfo)); ZeroMemory(@ProcInfo, SizeOf(ProcInfo)); StartInfo.cb := SizeOf(StartInfo); StartInfo.dwFlags := STARTF_USESTDHANDLES; // 创建管道,用来给目标程序传输入 if not CreatePipe(StdInWriteHandle, StartInfo.hStdInput, nil, 0) then begin ShowMessage('创建输入管道失败'); Exit; end; // 启动example.exe,注意参数要正确 if not CreateProcess(nil, PChar('example.exe'), nil, nil, True, 0, nil, nil, StartInfo, ProcInfo) then begin ShowMessage('启动程序失败'); CloseHandle(StdInWriteHandle); Exit; end; // 关闭不需要的句柄,避免资源泄漏 CloseHandle(ProcInfo.hThread); CloseHandle(StartInfo.hStdInput); // 发送'q'到程序的标准输入 InputChar := 'q'; WriteFile(StdInWriteHandle, InputChar, SizeOf(InputChar), BytesWritten, nil); // 关闭写入句柄,让程序知道输入结束了 CloseHandle(StdInWriteHandle); // 可选:等待程序执行完再继续 WaitForSingleObject(ProcInfo.hProcess, INFINITE); CloseHandle(ProcInfo.hProcess); end;
两种方法的小总结
- 方法1适合你没办法改启动逻辑的场景,比如已经用
ShellExecute启动了程序,只能事后补按键;但它依赖窗口前台状态,容易受其他窗口干扰。 - 方法2是更专业的进程间通信方式,完全不依赖窗口,稳定性和可控性都更好,能改启动方式的话优先选这个。
内容的提问来源于stack exchange,提问作者Xel Naga
相关产品推荐
相关产品推荐

