简体   繁体   English

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

[英]Sending Commands to a Windowless Command Line process (started from the C# Application)

I've got a command line application that starts up and does some work. 我有一个启动的命令行应用程序,并做了一些工作。 During that time, it listens to keystrokes (s => show status). 在此期间,它会监听击键(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. 这不是典型的命令提示符,您按下's'和<ENTER> - 它是按下键时响应状态的类型。

Now I'm trying to "control" that command line application from a fancy GUI application by sending keystrokes. 现在我试图通过发送击键来从一个奇特的GUI应用程序“控制”该命令行应用程序。 I've tried the more conventional approach of writing to the Process' StandardInput but that doesn't seem to have an effect at all. 我已经尝试过更传统的方法来编写Process的StandardInput,但这似乎根本没有效果。 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. 此外,因为实际进程没有窗口(它以CreateNoWindow = true开头),我无法尝试使用Win32 API向窗口发送击键。

Is there any other way of doing it? 这样做还有其他办法吗?

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. AFAIK,无法以编程方式控制这些应用程序。 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). 如果你真的, 真的需要,我会探索像AutoHotKey控制私人桌面上的应用程序(AHK使用虚拟键盘/鼠标驱动程序)。 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. 然后,中间应用程序将与目标应用程序共享其控制台 ,并使用低级I / O来检测更改。

Or you could use Detours to bend the target app to your will. 或者您可以使用Detours将目标应用程序弯曲到您的意愿。

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 所以,我所做的是使用两个WinAPI函数调用

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. 第一个可用于通过将nCmdShow分别更改为1和0来显示/隐藏窗口。 The other one puts the window (determined by WindowHandle) to the front. 另一个将窗口(由WindowHandle确定)放在前面。 Combining these two together, I was able to programmaticly bring the console window up front, do a simple SendKeys.Send(); 将这两者结合在一起,我能够以编程方式将控制台窗口放在前面,做一个简单的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. 现在,这是一个真正的kludge工作,但它完成了工作。 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. 一个潜在的缺陷是,如果用户正在使用计算机进行其他操作,并且当窗口处于活动状态时使用'q'将在10000000时刻确定1 - 它将退出工作程序。 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. 感谢所有回答的人,因为你做过 - 以这样或那样的方式,引导我走向正确的解决方案。

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. 诀窍是使用名为PostMessage的WinAPI函数将KeyDown(或KeyUp)消息发送到执行相同操作的进程。 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: 我正在发送带有键'S'的按键命令作为参数:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM