Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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). 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?

like image 568
Iv4n Avatar asked Oct 10 '22 03:10

Iv4n


2 Answers

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.

like image 69
Stephen Cleary Avatar answered Oct 12 '22 01:10

Stephen Cleary


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.

like image 27
Iv4n Avatar answered Oct 12 '22 00:10

Iv4n