向无窗口命令行进程发送命令(从 C# 应用程序启动)

发布于 2024-12-22 21:47:43 字数 289 浏览 0 评论 0原文

我有一个命令行应用程序可以启动并执行一些工作。在此期间,它会监听击键(s => 显示状态)。这不是典型的命令提示符,您可以按 's' 和键。 - 这种类型一旦按下按键就会做出反应并显示状态。

现在我试图通过发送击键从一个精美的 GUI 应用程序“控制”该命令行应用程序。我尝试了更传统的方法来写入进程的标准输入,但这似乎根本没有效果。另外,因为实际进程没有窗口(它以 CreateNoWindow=true 启动),所以我无法尝试使用 Win32 API 将击键发送到窗口。

还有其他方法吗?

I've got a command line application that starts up and does some work. During that time, it listens to keystrokes (s => show status). It's not the typical command prompt where you press 's' and <ENTER> - it's the type which reacts as soon as the key is pressed the status is shown.

Now I'm trying to "control" that command line application from a fancy GUI application by sending keystrokes. I've tried the more conventional approach of writing to the Process' StandardInput but that doesn't seem to have an effect at all. Also, because the actual process doesn't have a window (it's started with CreateNoWindow=true) I can't try the Win32 API for sending keystrokes to a window.

Is there any other way of doing it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

秋叶绚丽 2024-12-29 21:47:43

花哨的控制台应用程序是有问题的。

他们倾向于直接读取键盘输入,而不是通过标准输入。他们还倾向于直接控制控制台,而不是通过标准输出。

AFAIK,没有办法以编程方式控制这些应用程序。如果您真的,确实需要,我会探索类似 AutoHotKey 的东西 控制专用 桌面(AHK 使用虚拟键盘/鼠标驱动程序)。不过,我不确定您如何从控制台读取结果; 也许可以创建一个由您的程序(在私有桌面中)启动的中间控制台应用程序并启动目标应用程序。然后,中间应用程序将共享其console 与目标应用程序并使用 低级 I/O 用于检测更改。

或者,您可以使用 Detours 来使目标应用程序屈服于您的意愿。

Fancy console applications are problematic.

They have a tendency to directly read the keyboard input, instead of going through stdin. They also have a tendency to directly control their console, instead of going through stdout.

AFAIK, there is no way to programmatically control these apps. If you really, really need to, I would explore something like AutoHotKey controlling the app on a private desktop (AHK uses a virtual keyboard/mouse driver). I'm not sure how you would read the results off the console, though; it may be possible to create an intermediate console app that's started by your program (in the private desktop) and starts the target app. The intermediate app would then share its console with the target app and use low-level I/O to detect changes.

Or you could use Detours to bend the target app to your will.

心欲静而疯不止 2024-12-29 21:47:43

好吧,我似乎找到了自己问题的答案。
这是一个真正的“拼凑在一起”的解决方案,但它有效 - 并且对于我正在构建的应用程序的所有意图和目的来说,这并不重要。

因此,我所做的是使用两个名为

static extern bool ShowWindow(IntPtr WindowHandle, int nCmdShow);
static extern bool SetForegroundWindow(IntPtr WindowHandle);

“第一个”的 WinAPI 函数,通过分别将 nCmdShow 更改为 1 和 0,可以用来显示/隐藏窗口。另一个将窗口(由 WindowHandle 确定)放在前面。将这两者结合在一起,我能够以编程方式将控制台窗口放在前面,执行一个简单的 SendKeys.Send();操作,然后再次隐藏。

// Use a WIN API command to bring the command line to front
SetForegroundWindow(workerProcess.MainWindowHandle);
// Send a keystore to re-display the STATUS of the worker
SendKeys.Send("s");
// Hide the window again.
ShowWindow(workerProcess.MainWindowHandle, 0); 

现在,这确实是一项拼凑的工作,但它完成了工作。一个潜在的陷阱是,如果用户正在使用计算机执行其他操作,并且在窗口使用“q”处于活动状态时,会在 10000000 时刻内确定该 1 - 它将退出工作程序。但该应用程序旨在用于专用机器,这些机器很可能甚至不会连接显示器、键盘或鼠标,因此这不会成为问题。

感谢所有回答的人,因为您这样做了 - 以某种方式引导我找到正确的解决方案。

Well, I seem to have found an answer to my own question.
It's a real "kludged together" solution, but it works - and for all the intents and purposes of the application I'm building, it doesn't matter.

So, what I did was use two WinAPI functions called

static extern bool ShowWindow(IntPtr WindowHandle, int nCmdShow);
static extern bool SetForegroundWindow(IntPtr WindowHandle);

The first one can be used to Show/Hide a window by changing nCmdShow to 1 and 0 respectively. The other one puts the window (determined by WindowHandle) to the front. Combining these two together, I was able to programmaticly bring the console window up front, do a simple SendKeys.Send(); operation and then hide it again.

// Use a WIN API command to bring the command line to front
SetForegroundWindow(workerProcess.MainWindowHandle);
// Send a keystore to re-display the STATUS of the worker
SendKeys.Send("s");
// Hide the window again.
ShowWindow(workerProcess.MainWindowHandle, 0); 

Now, it's a real kludge job, but it gets the job done. One potential pitfall would be if a user is using the computer for something else, and would nail that 1 in a 10000000 moment when the window is active with a 'q' - it would quit the worker program. But the application is intended to be used on dedicated machines that most likely won't even have monitors, keyboards or mice attached to them so it wouldn't be an issue.

Thanks to all who answered, since you did - in one way or another, steer me towards the right solution.

脸赞 2024-12-29 21:47:43

我找到了一种更好的方法来完成该功能,而理论上不会存在因同时用户输入和窗口切换而导致问题的风险。

诀窍是使用名为 PostMessage 的 WinAPI 函数将 KeyDown(或 KeyUp)消息发送到执行相同操作的进程。无需将进程窗口置于前面并随后立即隐藏它!

我正在发送以“S”键作为参数的按键命令:

        // 0x0100 - VM_KEYDOWN
        // 0x0101 - VM_KEYUP
        // 0x53 - S-key
        PostMessage(workerProcess.MainWindowHandle, 0x0100, 0x53, 0);
        PostMessage(workerProcess.MainWindowHandle, 0x0101, 0x53, 0);

I found an even better way to accomplish the functionality without the theoretical risk of causing problems with simultaneous user input and window-switching.

The trick is to use the WinAPI functions called PostMessage to send up KeyDown (or KeyUp) message to the process which does the same thing. No need to bring the process window to the front and hide it immediately afterwards!

I'm sending the key-down command with key 'S' as the argument:

        // 0x0100 - VM_KEYDOWN
        // 0x0101 - VM_KEYUP
        // 0x53 - S-key
        PostMessage(workerProcess.MainWindowHandle, 0x0100, 0x53, 0);
        PostMessage(workerProcess.MainWindowHandle, 0x0101, 0x53, 0);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文