Как отправить ключи вместо символов на процесс?
-
20-09-2019 - |
Вопрос
System.diagnostics.Process обнаруживает стригритера с именем StandardInput, который, насколько я знаю, принимает только символы.
Но мне также нужно отправить клавишные, а некоторые нажатия на несколько наметок не сопоставляются с символами.
Что я должен делать?
Решение
Вы смешиваете входные потоки с контрольными сигналами. Консольный процесс имеет поток ввода по умолчанию, который вы можете управлять со стандартным INTINPUT, как вы уже знаете. Но Ctrl-C и Ctrl-Break не являются символами, отправляемыми в процесс через этот поток, а вместо этого они вместо этого контрольные сигналы что процесс получает с использованием зарегистрированных обработчиков сигнала, см. CTRL+C и CTRL+Break Signals:
По умолчанию, когда окно консоли имеет фокус клавиатуры, CTRL+C или CTRL+Break рассматривается как сигнал (Sigint или SigBreak), а не как вход клавиатуры.
Чтобы отправить фальшивые сигналы в процесс, который вы можете использовать GenerateConsoleCtrlEvent
и отправить тоже CTRL_C_EVENT
или же CTRL_BREAK_EVENT
. Анкет Этот API не имеет эквивалента .NET, поэтому вы должны его писать.
Чтобы использовать его из .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+Break в процесс, который работает очень хорошо (особенно, если процесс является программой командной строки/файла партии). Вот статья о Кодепроект Это делает это точно и отражает Sendkeys ... Мне еще предстоит вставить в это какой -то код, чтобы продемонстрировать ...
РЕДАКТИРОВАТЬ № 2: На самом деле я очень удивлен ... Как покажет этот код (доказательство концепции) ... он использует:
- Inputsimulator (как упоминалось ранее)
- Форма Windows, которая состоит из кнопки, когда форма загружается, она автоматически запускает класс. Нажав кнопку, она публикует CTRL-перерыв в скрытый процесс
- Выходной поток действительно перенаправляется и является скрытым окном.
- Странная вещь-это то, что вывод захватывается, но не показывает результаты в окне отладки, в режиме реального времени он буферируется (я думаю), пока процесс не завершится, весь вывод показан ...
- Я немного обманул на
FindWindow
Вызов API, потому что я знал, что название окна было и было каким -то образом, способным вывести его на передний план и использовать входнойсимулятор для отправки на него клавишSendKeys
функция ... причина, по которой у меня былаThread.Sleep
для обеспечения того, чтобы нажатые клавишные были отправлены для того, чтобы «толкнуть в очередь клавиатуры« окно активного переднего плана », что, несмотря на это, скрыто» - Я использовал команду «NetStat -e 5», чтобы навсегда зацикливаться, обновляя результаты каждые 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
Запускается из потока «Фонообрабатывателя», и я напрямую призвал метод «postctrlc» из основного потока графического интерфейса ... это педантично в качестве кода подтверждения концепции, но он показывает, что он должен реализовать «isynchronizeinvoke» Чтобы сделать это безопасным, это в стороне ... это действительно работает.
Вы видели этот замечательный инструмент - Авто. Анкет Это инструмент сценариев. Чтобы отправить обратное пространство, которое вы бы использовали Send("{BACKSPACE}")
Это отличный инструмент, и он может помочь в автоматизации многих ручных кликов/дважды щелкнуть/и т. Д.
Это имеет отношение к вашему вопросу?
Если у вас есть окно Windows Forms, в которое вы можете отправить клавиши, тогда Sendkeys может быть подходящим решением.
Для нажатия Backspace и Ctrl+C, это должно быть
SendKeys.Send("{BACKSPACE}^C");