2010-02-16 43 views
6

System.Diagnostics.Process公開了一個名爲StandardInput的StreamWriter,它只接受字符,據我所知。如何將密鑰而不是字符發送到進程?

但是我還需要發送擊鍵以及一些擊鍵不能很好地映射到字符。

我該怎麼辦?

+0

哪些按鍵,例如? – 2010-02-16 17:05:56

+0

@Rick退格,Ctrl + C – 2010-02-16 17:14:16

+1

這是Unix管道抽象中的最終漏洞。重定向通過字符流發生,它不能模擬非鍵入的按鍵。 – 2010-02-16 17:33:48

回答

23

你混合輸入流的控制信號。正如你已經知道的,控制檯進程有一個默認的輸入流,你可以用StandardInput控制它。但是,按Ctrl-C和Ctrl-中斷無法通過此流發送到進程的人物,而是他們是不是控制信號該進程接收使用已註冊的信號處理程序,請參見CTRL+C and CTRL+BREAK Signals

默認情況下,當控制檯窗口具有鍵盤焦點時,CTRL + C或 CTRL + BREAK被視爲信號 (SIGINT或SIGBREAK)而不是 鍵盤輸入。

要發送假信號的過程中,你可以使用GenerateConsoleCtrlEvent和發送任何CTRL_C_EVENTCTRL_BREAK_EVENT。這個API沒有.Net等價物,所以你必須PInvoke它。

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

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

http:// www。 google.com/codesearch/p?hl=zh-CN#ncfzeHH4QLA/pubs/consoledotnet/consoledotnet.zip%7CYrqh4ujA6zA/ConsoleDotNet/WinCon.cs – 2010-02-20 23:17:36

+0

我正在使用FFmpeg屏幕錄製過程。這對我有用嗎?其實我想停止使用FFmpeg – Ahmad 2017-07-09 08:41:27

3

你見過這個偉大的工具 - AutoIt。這是一個腳本工具。要發送退格,您可以使用Send("{BACKSPACE}")

這是一個很棒的工具,它可以幫助自動化許多手動點擊/雙擊/等。

這與您的問題有關嗎?

+0

嗨,這是相關的,但我更喜歡我可以直接在.NET中使用的解決方案。 – 2010-02-17 14:21:18

+1

@Jader;有一個DLL可用於AutoIt,你可以很容易地添加到您的應用程序... – jvenema 2010-02-20 23:17:01

0

如果你有一個Windows窗口可以發送密鑰,那麼SendKeys可能是一個合適的解決方案。

對於按壓退格鍵和Ctrl + C,這應該是

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

發送Ctrl + C這樣做實際上並沒有在一個過程中,它應該是^ {BREAK} ... – t0mm13b 2010-02-21 16:12:31

6

有一個輸入模擬器發現這裏Codeplex它可以爲你做只是工作:

從.NET你只需要包含函數定義中使用它。 我工作的一個示例代碼,將回到這裏後不久,牢記輸入模擬器是類似於在由瑞摩斯提供的鏈接找到...

編輯:我發現有這是一個限制,你一定可以擺脫典型的System.Windows.Forms.SendKeys.Send方法,它確實有效! ,但過程必須有

  • 不能隱藏窗口的流沒有重定向(這是它會失敗,因爲窗口的句柄是無處可看,沒有將其帶到方式使其活躍的前景!)
  • 一個窗口顯示過程,這是有效的!

在你的情況下,它發現窗口的問題,將其通過的PInvoke活躍「SetForegroundWindow」,併發送序列^{BREAK}其發送CTRL + BREAK信號的過程,並很好地工作(特別是如果進程是命令行程序/批處理文件)。這裏有CodeProject,這是否準確,反映了...的SendKeys我還沒有粘貼一些代碼,這證明了一篇文章....

編輯#2:其實我很驚訝......作爲這個代碼將顯示(概念的證明)...它使用:

  • InputSimulator(如前所述)
  • 甲窗口形式,它由一個按鈕,當窗體加載它自動運行類。點擊該按鈕後,它會向隱藏進程發送ctrl-break
  • 輸出流確實是重定向的,並且是一個隱藏窗口。
  • 奇怪的是,輸出被捕獲,但沒有在調試窗口中實時顯示結果,也就是說,它被緩衝(我猜),直到進程終止,整個輸出顯示。
  • 我在FindWindow API調用中有點欺騙,因爲我知道窗口的標題是,並且以某種方式能夠將它帶到前臺,並使用InputSimulator將鍵擊發送給它......或使用傳統普通舊SendKeys函數...我有Thread.Sleep的原因是爲了確保按鍵被髮送,以便'被推入到'主動前景窗口'的鍵盤隊列中,儘管如此,它被隱藏'
  • I使用'netstat -e 5'命令來循環forev呃,每5秒刷新一次結果,直到它收到一個'Ctrl + C'來打破無限循環。
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); 
     } 
    } 
} 

挑剔之外,我知道netStat運行斷「的BackgroundWorker」線程,我直接調用從主界面線程的「PostCtrlC」的方法......這是迂腐的但它確實表明它需要實現'ISynchronizeInvoke'以使其線程安全,除此之外......它確實有效。

+0

屏幕錄製的過程開始,但如果你有多個進程使用netstat。exe,那麼你會影響所有與PostCtrlC()?當你知道進程SessionId時,有沒有辦法做同樣的事情? – Constantin 2012-05-24 19:35:28

+0

@Constantine代碼只能運行一個運行netstat.exe的窗口。您可以使用[EnumWindows](http://msdn.microsoft.com/en-us/library/windows/desktop/ms633497(v = vs.85).aspx)並創建回調函數[EnumWindowsProc](http: //msdn.microsoft.com/en-us/library/windows/desktop/ms633498(v=vs.85).aspx)來獲取句柄並檢查它是否在該句柄的標題中有netstat.exe標題......如果找到它,然後將它帶入前臺,並將其作爲概念驗證代碼「zap」進行演示:) – t0mm13b 2012-05-28 22:59:59

相關問題