2010-02-16 2 views
6

System.Diagnostics.Process는 내가 아는 한 문자 만 허용하는 StandardInput이라는 StreamWriter를 노출합니다.문자 대신 키를 프로세스에 보내는 방법은 무엇입니까?

그러나 키 스트로크도 보내야하며 일부 키 입력은 문자에 잘 맵핑되지 않습니다.

어떻게해야합니까?

+0

예를 들어 어떤 키 스트로크입니까? –

+0

@Rick 백 스페이스, Ctrl + C –

+1

이것은 유닉스 파이프 추상화의 궁극적 인 누수입니다. 리디렉션은 문자 스트림을 통해 이루어지며 비 타이핑 키 스트로크를 시뮬레이션 할 수 없습니다. –

답변

23

되어야 백 스페이스 Ctrl + C를 가압

는 제어 신호에 스트림. 콘솔 프로세스에는 이미 알고있는 것처럼 StandardInput으로 제어 할 수있는 기본 입력 스트림이 있습니다. 그러나 Ctrl 키 C 및 Ctrl 키 틈이 스트림을 통해 프로세스로 전송 문자 아니지만, 대신에 그들이 제어 신호는 프로세스가 등록 신호 처리기를 사용하여, CTRL+C and CTRL+BREAK Signals 참조받는 대신 같습니다

기본적

, 콘솔 창에 키보드 포커스가있는 경우 CTRL + C 또는 CTRL + BREAK는 (SIGINT 또는 SIGBREAK) 신호로 처리되며 키보드 입력으로 처리되지 않습니다.

GenerateConsoleCtrlEvent을 사용하고 CTRL_C_EVENT 또는 CTRL_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=ko#ncfzeHH4QLA/pubs/consoledotnet/consoledotnet.zip%7CYrqh4ujA6zA/ConsoleDotNet/WinCon.cs –

+0

화면 녹화의 FFmpeg 프로세스를 사용하고 있습니다. 이게 저에게 효과가 있습니까? 사실 FFmpeg – Ahmad

3

위대한 도구 - AutoIt을 보았습니까? 이것은 스크립팅 도구입니다. 백 스페이스를 보내려면 Send("{BACKSPACE}")

이것은 훌륭한 도구이며 많은 수동 클릭/두 번 클릭 등을 자동화하는 데 도움이 될 수 있습니다.

이 질문과 관련이 있습니까?

+0

안녕하세요, 관련성이 있습니다.하지만 .NET에서 직접 사용할 수있는 솔루션을 선호합니다. –

+1

@ Jader; 당신의 응용 프로그램에 쉽게 추가 할 수있는 AutoIt에 사용할 수있는 DLL이 있습니다 ... – jvenema

0

키를 보낼 수있는 Windows Forms 창이있는 경우 SendKeys이 적절한 해결책 일 수 있습니다. 사용자가 입력을 믹싱

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

보내는 Ctrl + C는 프로세스에서 실제로 작동하지 않습니다.^{BREAK} ... – t0mm13b

6

당신을 위해 단지 일을 할 수 시뮬레이터 Codeplex에 여기 입력이있다 : 당신은 단순히 함수 정의를 포함해야 .NET

은에서를 사용합니다. 나는 샘플 코드에 일하고 입력 시뮬레이터 레무스에서 제공하는 링크에서 발견 된 것과 유사하다 마음에, 곧 다시 여기 곰을 게시 할 예정입니다 ...

편집 : 나는이 있음을 발견했다 이것에 대한 제한은, 당신은 분명히 전형적인 System.Windows.Forms.SendKeys.Send 방법으로 벗어날 수 있습니다, 그것은 효과적으로 작동합니다! 하지만, 과정은

  • 창을 숨길 수 없습니다
  • 스트림의

    • 없음 리디렉션 (이 실패합니다 경우 윈도우의 핸들이 어디에도 볼 수없는 수 있기 때문에이, 그것을 가져 오는 방법입니다이 없어야합니다 전경을 활성화시켜야합니다!)
    • 효과적이기위한 프로세스를 보여주는 창!귀하의 경우에는

    , 그것은 창을 찾는 문제입니다, 'SetForegroundWindow'PInvoke를 통해 활성 설정하고 (매우 잘 작동 않는 시퀀스를 프로세스에 Ctrl 키 + 브레이크 신호를 보내 ^{BREAK}을 보내 특히 프로세스가 명령 행 프로그램/배치 파일 인 경우).이 사실 나는 매우 당황 스럽네요으로 ... : 다음은이를 정확하게 수행하고 내가 입증이에 몇 가지 코드를 붙여 아직 ...에서 SendKeys를 반영 CodeProject에 대한 기사 ....

    편집 # 2입니다

    • InputSimulator을
    • 양식이 그것을로드 버튼으로 구성된 창 양식, 자동으로 클래스를 실행합니다 (앞서 언급 한 바와 같이) :이 코드는 사용 ... (개념 증명)를 보여줍니다 . 버튼을 클릭하면 숨겨진 프로세스에 ctrl-break가 게시됩니다.
    • 출력 스트림은 실제로 리디렉션되어 숨겨진 창입니다.
    • 이상한 점은 출력이 캡처되고 있지만 디버그 창에 결과가 표시되지 않는 것입니다. 즉, 프로세스가 종료 될 때까지 버퍼링됩니다 (전체 출력이 표시됨).
    • FindWindow API 호출에서 약간의 부정 행위를했는데, 그 이유는 내가 창 제목이 무엇인지 알았고 어떻게 든 포 그라운드로 가져 와서 InputSimulator를 사용하여 키 입력을 보내거나 전통적인 평범한 구 SendKeys 기능 ... 내가 Thread.Sleep을 가지고 있었던 이유는 "액티브 전경 윈도우"의 키보드 대기열에 눌려 지도록 키 스트로크가 보내지는 것을 보장하는 것입니다. 그 외에도 "숨겨져 있습니다"
    • 'netstat -e 5'명령을 사용하여 forev를 반복합니다. 무한 루프를 깨기 위해 'Ctrl + C'를받을 때까지 매 5 초마다 결과를 새로 고침합니다. 옆
    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); 
         } 
        } 
    } 
    

    Nitpicky을, 나는 netStat가 'BackgroundWorker에'스레드를 실행하는 것을 알고, 내가 직접 메인 GUI 스레드에서 'PostCtrlC'방법을 호출 ... 이것은 같은 현학적이다 proof-of-concept 코드를 제공하지만 스레드 안전을 위해 'ISynchronizeInvoke'를 구현해야한다는 것을 보여줍니다. 그렇다고해서 실제로 작동합니다.

    +0

    을 사용하여 화면 녹화의 프로세스 시작을 중지하고 싶지만 netstat를 사용하는 여러 프로세스를 실행중인 경우.exe 인 경우 PostCtrlC()에 모두 영향을 미칩니 까? SessionId 프로세스를 알면 같은 일을 할 수있는 방법이 있습니까? – Constantin

    +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가 있는지 확인하십시오. 제목 ... 그 발견되면 포어 그라운드로 가져 와서 위의 개념 증명 코드와 같이 그것을 "압축"하십시오. – t0mm13b

    관련 문제