문자 대신 키를 프로세스로 보내는 방법은 무엇입니까?
-
20-09-2019 - |
문제
System.Diagnostics.Process는 StandardInput이라는 스트림 라이터를 노출 시키는데, 이는 내가 아는 한 문자 만 허용합니다.
그러나 키 스트로크도 보내야하며 일부 키 스트로크는 문자에 잘 매핑되지 않습니다.
어떻게해야합니까?
해결책
입력 스트림과 제어 신호를 혼합하고 있습니다. 콘솔 프로세스에는 이미 알고 있듯이 StandardInput로 제어 할 수있는 기본 입력 스트림이 있습니다. 그러나 Ctrl-C와 Ctrl-Break 은이 스트림을 통해 프로세스로 전송되는 문자가 아니라 대신 대신입니다. 제어 신호 프로세스가 등록 된 신호 핸들러를 사용하여 수신한다는 것은 Ctrl+C 및 Ctrl+브레이크 신호:
기본적으로 콘솔 창에 키보드 초점이있는 경우 Ctrl+C 또는 Ctrl+Break는 키보드 입력이 아닌 신호 (Sigint 또는 Sigbreak)로 처리됩니다.
사용할 수있는 프로세스에 가짜 신호를 보내려면 GenerateConsoleCtrlEvent
그리고 둘 중 하나를 보내십시오 CTRL_C_EVENT
또는 CTRL_BREAK_EVENT
. 이 API에는 .NET 동등성이 없으므로 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 'Setforegroundwindow'를 통해 활성화하고 시퀀스를 보내는 문제입니다. ^{BREAK}
CTRL+브레이크 신호를 프로세스로 보냅니다 (특히 프로세스가 명령 줄 프로그램/배치 파일 인 경우). 여기에 관한 기사가 있습니다 CodeProject 이것이 정확히 수행하고 sendkeys를 반영합니다 ... 나는 아직도 이것에 몇 가지 코드를 붙여 넣지 않았다 ....
#2 편집 : 사실 나는 매우 놀랐습니다 ...이 코드가 표시 될 때 (개념 증명) ... 사용 중입니다.
- inputSimulator (앞에서 언급 한 바와 같이)
- 양식이로드 될 때 버튼으로 구성된 Windows 양식은 자동으로 클래스를 실행합니다. 버튼을 클릭하면 숨겨진 프로세스에 CTRL 브레이크를 게시합니다.
- 출력 스트림은 실제로 리디렉션되며 숨겨진 창입니다.
- 이상한 점은 출력이 캡처되고 있지만 디버그 창의 결과를 실시간으로 표시하지는 않습니다. 즉, 프로세스가 종료 될 때까지 버퍼링됩니다. 전체 출력이 표시됩니다 ...
- 나는 약간 속임수를 썼다
FindWindow
API Call은 창의 제목이 어쨌든 전경으로 가져올 수 있다는 것을 알았 기 때문에 입력 시스트 로크를 사용하여 키 스트로크를 보내거나 전통적인 평원 오래된 구식을 사용합니다.SendKeys
기능 ... 내가 가진 이유Thread.Sleep
'활성 전경 창의 키보드 대기열에 밀어 넣기 위해 키 스트로크가 전송되도록하는 것입니다. - 나는 'netstat -e 5'명령을 사용하여 영원히 루프를 사용하여 '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
'배경 작업자'스레드를 실행 중이며 메인 GUI 스레드에서 'PostCtrlc'메소드를 직접 호출했습니다. 그것을 실로 만들기 위해, 그것은 제쳐두고 ... 그것은 실제로 작동합니다.
이 훌륭한 도구를 보셨습니까? 오토이트. 이것은 스크립팅 도구입니다. 백 스페이스를 보내려면 사용할 것입니다 Send("{BACKSPACE}")
이 도구는 훌륭한 도구이며 많은 수동 클릭을 자동화/두 번 클릭하는 데 도움이 될 수 있습니다.
이것이 귀하의 질문과 관련이 있습니까?
Keys를 보낼 수있는 Windows Forms Window가있는 경우 sendkeys 적절한 솔루션 일 수 있습니다.
백 스페이스 및 Ctrl+C를 누르려면
SendKeys.Send("{BACKSPACE}^C");