Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/274.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何向进程发送密钥而不是字符?_C#_.net_Process_Keyboard_Streamwriter - Fatal编程技术网

C# 如何向进程发送密钥而不是字符?

C# 如何向进程发送密钥而不是字符?,c#,.net,process,keyboard,streamwriter,C#,.net,Process,Keyboard,Streamwriter,System.Diagnostics.Process公开名为StandardInput的StreamWriter,据我所知,它只接受字符 但是我也需要发送击键,有些击键不能很好地映射到字符 我该怎么办?你见过这个很棒的工具吗。这是一个脚本工具。要发送退格,可以使用send(“{backspace}”) 这是一个很好的工具,它可以帮助自动化许多手动点击/双击/等等 这与您的问题有关吗?如果您有一个可以将密钥发送到的Windows窗体窗口,那么可能是一个合适的解决方案 对于按backspace和Ct

System.Diagnostics.Process公开名为StandardInput的StreamWriter,据我所知,它只接受字符

但是我也需要发送击键,有些击键不能很好地映射到字符


我该怎么办?

你见过这个很棒的工具吗。这是一个脚本工具。要发送退格,可以使用
send(“{backspace}”)

这是一个很好的工具,它可以帮助自动化许多手动点击/双击/等等


这与您的问题有关吗?

如果您有一个可以将密钥发送到的Windows窗体窗口,那么可能是一个合适的解决方案

对于按backspace和Ctrl+C,应该是

SendKeys.Send("{BACKSPACE}^C");

您正在将输入流与控制信号混合。控制台进程有一个默认的输入流,您可以使用StandardInput进行控制,正如您已经知道的。但Ctrl-C和Ctrl-Break不是通过此流发送到进程的字符,而是进程使用注册的信号处理程序接收的控制信号,请参阅:

默认情况下,当控制台窗口 键盘焦点,CTRL+C或 CTRL+BREAK被视为一个信号 (SIGINT或SIGBREAK)而不是 键盘输入

要向进程发送假信号,可以使用并发送
CTRL\u C\u事件
CTRL\u BREAK\u事件
。这个API没有与.Net等效的API,所以您必须使用PInvoke

要从.NET使用它,只需包含函数定义:

const int CTRL_C_EVENT = 0;
const int CTRL_BREAK_EVENT = 1;

[DllImport("kernel32.dll")]
static extern bool GenerateConsoleCtrlEvent(
    uint dwCtrlEvent,
    uint dwProcessGroupId);

这里有一个输入模拟器,可以为你做这项工作。 我正在编写一个示例代码,并将很快发回这里,请记住输入模拟器与Remus提供的链接中发现的类似

编辑:我发现这有一个限制,你完全可以使用典型的
System.Windows.Forms.SendKeys.Send方法,它确实有效,但是,这一过程必须具备以下条件:

  • 没有流的重定向
  • 无法隐藏窗口(这是它将失败的地方,因为窗口的句柄不可见,无法将其带到前台使其处于活动状态!)
  • 一个窗口,显示此过程的有效性!
在您的情况下,只需找到窗口,通过pinvoke'SetForeGroundIndow'将其设置为活动状态,然后发送序列
^{BREAK}
,该序列将Ctrl+BREAK信号发送给运行良好的进程(尤其是当进程是命令行程序/批处理文件时)。这里有一篇文章介绍如何做到这一点,并镜像SendKeys…我还需要在其中粘贴一些代码来演示

编辑#2:事实上,我很惊讶…正如这段代码将显示的(概念验证)…它使用:

  • 输入模拟器(如前所述)
  • 由按钮组成的windows窗体,当窗体加载时,它会自动运行该类。单击按钮后,它会向隐藏的进程发布一个ctrl中断
  • 输出流确实被重定向,是一个隐藏窗口
  • 奇怪的是,输出被捕获,但没有在调试窗口中实时显示结果,也就是说,它被缓冲(我猜),直到进程终止,整个输出都显示出来
  • 我在
    FindWindow
    API调用中作弊了一点,因为我知道窗口的标题是,而且不知怎么的,能够把它带到前台,使用InputSimulator向它发送击键…或者使用传统的普通老
    SendKeys
    功能…我之所以有
    线程。Sleep
    是为了确保击键被发送,以便“被推到“活动前台窗口”的键盘队列中,尽管如此,它还是被隐藏”
  • 我使用'netstat-e5'命令永远循环,每5秒刷新一次结果,直到它收到一个'Ctrl+C'来打破无限循环

撇开挑剔不谈,我知道
netStat
正在运行“BackgroundWorker”线程,我直接从主GUI线程调用了“PostTrlc”方法……这是一个迂腐的概念验证代码,但它确实表明它需要实现“ISynchronizeInvoke”以使其线程安全,除此之外,它确实有效。

例如,哪些击键?这是Unix管道抽象中的最终漏洞。重定向是通过字符流进行的,它无法模拟非键入的笔划。您是在尝试捕获并重新发送到另一个进程,还是只是发送不可打印的字符作为控制手段,等等?@Marc我正在尝试为交互式脚本解释器(如octave.exe)创建GUI。请看,这是相关的,但我更喜欢一个可以直接在.NET中使用的解决方案。@Jader;有一个可用于AutoIt的dll,您可以轻松地将其添加到应用程序中…我正在使用FFmpeg屏幕录制过程。这对我有用吗?实际上,我想使用FFmpegSending Ctrl+C停止进程开始屏幕录制,就像在进程中实际不起作用一样,它应该是^{BREAK}…但是如果您正在运行多个使用netstat.exe的进程,那么您将使用postcrlc()影响所有进程吗?当你知道进程SessionId时,有没有办法做同样的事情?@Constantine代码只针对一个运行netstat.exe的窗口。您可以使用和创建回调函数来获取句柄,并检查该句柄的标题中是否有netstat.exe…如果找到了,则将其置于前台并“zap”它,如上面的概念验证代码所示:)
public partial class Form1 : Form
{
    private TestNetStat netStat = new TestNetStat();
    public Form1()
    {
       InitializeComponent();
       using (BackgroundWorker bgWorker = new BackgroundWorker())
       {
           bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
           bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
           bgWorker.RunWorkerAsync();
       }
    }

    void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
       System.Diagnostics.Debug.WriteLine("BGWORKER ENDED!");
    }

    private void  bgWorker_DoWork(object sender, DoWorkEventArgs e)
    {
       netStat.Run();
    } 
    void btnPost_Click(object sender, EventArgs e)
    {
       netStat.PostCtrlC();
       System.Diagnostics.Debug.WriteLine(string.Format("[{0}] - {1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), this.netStat.OutputData.Replace(Environment.NewLine, "")));
    }
}

public class TestNetStat
{
    private StringBuilder sbRedirectedOutput = new StringBuilder();
    //
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    [DllImport("user32")]
    public static extern int SetForegroundWindow(IntPtr hwnd);
    public string OutputData
    {
       get { return this.sbRedirectedOutput.ToString(); }
    }
    public void PostCtrlC()
    {
       IntPtr ptr = FindWindow(null, @"C:\Windows\System32\netstat.exe");
       if (ptr != null)
       {
          SetForegroundWindow(ptr);
          Thread.Sleep(1000);
          WindowsInput.InputSimulator.SimulateModifiedKeyStroke(VirtualKeyCode.CONTROL, VirtualKeyCode.CANCEL);
          // SendKeys.Send("^{BREAK}");
          Thread.Sleep(1000);
        }
    }
    public void Run()
    {
        System.Diagnostics.ProcessStartInfo ps = new System.Diagnostics.ProcessStartInfo();
        ps.FileName = "netstat";
        ps.ErrorDialog = false;
        ps.Arguments = "-e 5";
        ps.CreateNoWindow = true;
        ps.UseShellExecute = false;
        ps.RedirectStandardOutput = true;
        ps.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
        using (System.Diagnostics.Process proc = new System.Diagnostics.Process())
        {
           proc.StartInfo = ps;
           proc.EnableRaisingEvents = true;
           proc.Exited += new EventHandler(proc_Exited);
           proc.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(proc_OutputDataReceived);
           proc.Start();
           proc.BeginOutputReadLine();
           proc.WaitForExit();
        }
     }

     void proc_Exited(object sender, EventArgs e)
     {
        System.Diagnostics.Debug.WriteLine("proc_Exited: Process Ended");
     }

     void proc_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
     {
         if (e.Data != null)
         {
            this.sbRedirectedOutput.Append(e.Data + Environment.NewLine);
            System.Diagnostics.Debug.WriteLine("proc_OutputDataReceived: Data: " + e.Data);
         }
     }
}