2

I create a child console application with

_process = new Process();
_process.StartInfo.FileName = @"cmd.exe";
_process.StartInfo.UseShellExecute = false;
_process.StartInfo.RedirectStandardInput = true;
_process.StartInfo.RedirectStandardOutput = true;
_process.StartInfo.CreateNoWindow = true;

_proccess.Start();

Now I can go to c:\aaa

_process.StandardInput.Write("cd c:\\aaa\xD\xA");

But normally user can type c:\ + TAB + ENTER. How can I do the same? This does not work:

_process.StandardInput.Write("cd c:\\\0x9\xD\xA");
alex2k8
  • 42,496
  • 57
  • 170
  • 221

2 Answers2

2

There's a fundamental difference between the standard input of the child process, and the console that it is attached to. A command interpreter in interactive mode is expecting to be talking either to a console or to a pipe/file as its standard input, and it changes its behaviour to match which one it finds. For a pipe/file, it just makes a simple call the ReadFile() function. For a console, however, it receives input through ReadConsoleInput(), where non-alphanumeric keys are recognizable by their virtual key codes.

See the ReadCommand() function in the ReactOS CMD for an example.

If you write a byte with the value 9 down a pipe to the standard input of a process, that's what it will see from its call to ReadFile(). But it won't treat it as a Tab keypress, because (for starters) it isn't one; it's just byte value 9 coming down a pipe. Moreover, the command-line editing that a command interpreter does in interactive mode only occurs when the standard input is detected to be a console, not when it is a pipe or a file. The command interpreter uses ReadConsoleInput(), which doesn't read buffers of bytes but reads sequences of INPUT_RECORDs; and thus you have to WriteConsoleInput() to that console handle an appropriate INPUT_RECORD simulating the Tab key if you want the command interpreter to see a Tab keypress in its input stream.

Of course, since you've set StartInfo.RedirectStandardInput to true, under the covers .NET has connected the standard input of the command interpreter process to a pipe; and so the command interpreter is just calling ReadFile(), without doing any interactive command-line editing, as it would if its standard input had been a console. Even if you could find and open a handle to the command interpreter process' console, and write a INPUT_RECORD for a Tab key to it, the command interpreter is reading a pipe for its standard input, and ignoring its console.

If you want a command interpreter to act just as it would if it were talking to a console, command line editing and all, you have to spawn the process with its standard input as a console, whose handle you have to (then) obtain so that you can simulate keypresses with WriteConsoleInput(). That's fairly difficult within .NET.

JdeBP
  • 2,127
  • 16
  • 24
1

What about dipping into the Windows API?

using System.Runtime.InteropServices;
//...
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
private const int WM_CHAR = 0x0102;
private const int VK_TAB = 0x9;
private const int VK_RETURN = 0xD;
//...
SendMessage(_process.Handle, WM_CHAR, new IntPtr(VK_TAB), new IntPtr(0));
SendMessage(_process.Handle, WM_CHAR, new IntPtr(VK_RETURN), new IntPtr(0));

However that doesn't allways work according to Kevin Montrose's answer here.

Community
  • 1
  • 1
Matt Blaine
  • 1,976
  • 14
  • 22