.net 将选项卡发送到子控制台(windows)

.net 将选项卡发送到子控制台(windows),.net,console,tab-completion,.net,Console,Tab Completion,我创建了一个子控制台应用程序 _process = new Process(); _process.StartInfo.FileName = @"cmd.exe"; _process.StartInfo.UseShellExecute = false; _process.StartInfo.RedirectStandardInput = true; _process.StartInfo.RedirectStandardOutput = true; _process.StartInfo.Creat

我创建了一个子控制台应用程序

_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();
现在我可以去c:\aaa了

_process.StandardInput.Write("cd c:\\aaa\xD\xA");
但通常用户可以键入c:\+TAB+ENTER。我该怎么做呢?这不起作用:

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

那么看看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));

然而,这并不是所有的工作方式都是如此。

子进程的标准输入和它所连接的控制台之间有一个根本的区别。交互模式下的命令解释器期望与控制台或管道/文件进行对话,作为其标准输入,并且它会更改其行为以匹配找到的行为。对于管道/文件,它只需简单地调用函数。然而,对于控制台,它通过接收输入,其中非字母数字键可通过其虚拟键代码识别

有关示例,请参阅ReactOS
CMD
中的函数

如果将一个值为9的字节沿管道写入进程的标准输入,它将从对
ReadFile()
的调用中看到这一点。但它不会将其视为Tab按键,因为(对于初学者而言)它不是一个;它只是从管道中流出的字节值9。此外,命令解释器在交互模式下进行的命令行编辑仅在检测到标准输入是控制台时发生,而不是在它是管道或文件时发生。命令解释器使用
ReadConsoleInput()
,它不读取字节缓冲区,而是读取字节序列;因此,如果您希望命令解释器在其输入流中看到Tab键,则必须对该控制台处理一个适当的
INPUT\u记录
,模拟Tab键

当然,由于您已将
StartInfo.RedirectStandardInput
设置为
true
,因此.NET已将命令解释器进程的标准输入连接到管道;因此,命令解释器只是调用
ReadFile()
,而没有进行任何交互式命令行编辑,就像它的标准输入是控制台一样。即使您可以找到并打开命令解释器进程控制台的句柄,并为其中的制表键写入
INPUT\u RECORD
,命令解释器也会读取其标准输入的管道,而忽略其控制台

如果您想让命令解释器像与控制台对话、命令行编辑和所有操作一样工作,则必须将其标准输入作为控制台生成该进程,您必须(然后)获取其句柄,以便可以使用
writeconoleinput()
模拟按键操作。在.NET中这是相当困难的