Frage

System.Diagnostics.Process enthüllt einen Streamwriter namens StandardInput, der soweit ich weiß, nur Zeichen akzeptiert.

Aber ich muss auch Tastenanschläge senden, und einige Tastenanschläge sind nicht gut auf Zeichen zugeordnet.

Was soll ich machen?

War es hilfreich?

Lösung

Sie mischen Eingangsströme mit Steuersignalen. Ein Konsolenprozess verfügt über einen Standardeingangsstrom, den Sie mit dem StandardInput steuern können, wie Sie bereits wissen. Aber Strg-C und Strg-Break sind keine Zeichen Kontrollsignale dass der Prozess mit den registrierten Signalhandlern empfängt, siehe Strg+C und Strg+Break -Signale:

Wenn ein Konsolenfenster den Tastaturfokus aufweist, wird standardmäßig Strg+C oder Strg+Break als Signal (Sigint oder Sigbreak) und nicht als Tastatureingang behandelt.

Senden Sie gefälschte Signale an einen Prozess, den Sie verwenden können GenerateConsoleCtrlEvent und entweder senden CTRL_C_EVENT oder CTRL_BREAK_EVENT. Diese API hat kein .NET -Äquivalent, also musst du sie steigern.

Um es von .NET von .NET zu verwenden, müssen Sie lediglich die Funktionsdefinition einbeziehen:

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

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

Andere Tipps

Es gibt einen Eingangssimulator hier auf Codeplex Das kann nur den Job für Sie erledigen. Ich arbeite an einem Beispielcode und werde hier in Kürze wieder veröffentlichen. Beachten Sie, dass der Eingabesimulator ähnlich ist, was in dem von Remus gelieferten Link gefunden wurde ...

Bearbeiten: Ich habe festgestellt, dass es eine Einschränkung gibt, Sie können definitiv mit dem typischen davonkommen System.Windows.Forms.SendKeys.Send Methode, es funktioniert effektiv! , aber der Prozess muss haben

  • Keine Umleitungen der Ströme
  • Kann nicht versteckt werden (hier wird es fehlschlagen, da der Griff des Fensters nirgends zu sehen ist, keine Möglichkeit, es in den Vordergrund zu bringen, um es aktiv zu machen!)
  • Ein Fenster, das den Prozess zeigt, damit dies effektiv ist!

In Ihrem Fall geht es darum, das Fenster zu finden, es über Pinvoke 'setforecroundWindow' aktiv einzustellen und die Sequenzen zu senden ^{BREAK} Dies sendet das Strg+Break -Signal an den Prozess, der sehr gut funktioniert (insbesondere wenn der Prozess ein Befehlszeilenprogramm/eine Batch -Datei ist). Hier ist ein Artikel über CodeProject Das tut genau das und spiegelt die Sendkeys wider ... Ich muss noch einen Code in diesen einfügen, um zu demonstrieren ....

Bearbeiten#2: Eigentlich bin ich ziemlich überrascht ... wie dieser Code zeigt (Proof of Concept) ... es verwendet:

  • Eingabesimulator (wie zuvor erwähnt)
  • Ein Windows -Formular, das aus einer Taste besteht, wird die Klasse automatisch ausgeführt, wenn das Formular geladen wird. Beim Klicken auf die Schaltfläche veröffentlicht es einen Strg-Ausbruch in den versteckten Prozess
  • Der Ausgangsstrom wird tatsächlich umgeleitet und ist ein verstecktes Fenster.
  • Das Seltsame ist, dass die Ausgabe erfasst wird, aber die Ergebnisse im Debug-Fenster nicht zeigt, in Echtzeit wird es gepuffert (ich denke), bis der Prozess endet, die gesamte Ausgabe wird angezeigt ...
  • Ich habe ein bisschen auf die betrogen FindWindow API -Anruf, weil ich wusste, dass der Titel des Fensters irgendwie in den Vordergrund stellt und den Inputsimulator verwendet hatte, um die Tastenanschläge an sie zu senden oder die traditionelle Plain Old zu verwenden SendKeys Funktion ... der Grund, warum ich das hatte Thread.Sleep soll sicherstellen, dass die Tastenanschläge gesendet werden, um "in die Tastaturwarteschlange des" aktiven Vordergrundfensters "gedrückt zu werden, was trotz dessen versteckt ist"
  • Ich habe den Befehl 'netstat -e 5' verwendet, um für immer zu schleifen und die Ergebnisse alle 5 Sekunden zu erfrischen, bis er ein 'Strg+C' erhält, um die unendliche Schleife zu brechen.
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 beiseite, ich weiß, dass die netStat Läuft den Thread "Hintergrundworker" ab, und ich habe die "postctrlc" -Methode aus dem Haupt-GUI-Thread direkt aufgerufen ... dies ist pedantisch als Proof-of-Concept-Code, aber es zeigt, dass er "isynchronizeInvoke" implementiert muss. Damit es thread-sicher ist, abgesehen von ... funktioniert es tatsächlich.

Haben Sie dieses großartige Werkzeug gesehen - Autoit. Dies ist ein Skriptwerkzeug. Um einen Rückraum zu senden, den Sie verwenden würden Send("{BACKSPACE}")

Dies ist ein großartiges Werkzeug und kann bei der Automatisierung vieler manueller Klicks/Doppelklicks/usw. helfen.

Ist das für Ihre Frage relevant?

Wenn Sie ein Windows -Formulationsfenster haben, an das Sie die Schlüssel senden können, dann Sendkeys könnte eine geeignete Lösung sein.

Zum Drücken von Rückenraum und Strg+C sollte dies sein

SendKeys.Send("{BACKSPACE}^C");
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top