سؤال

System.Diagnostics.Process تكشف مجموعة StreamWriter باسم StandardInput ، والتي تقبل فقط الشخصيات بقدر ما أعرف.

لكنني بحاجة إلى إرسال ضغطات المفاتيح أيضًا ، وبعض ضربات المفاتيح لا تخطط جيدًا للشخصيات.

ماذا علي أن أفعل؟

هل كانت مفيدة؟

المحلول

أنت تمزج تدفقات الإدخال مع إشارات التحكم. تحتوي عملية وحدة التحكم على دفق إدخال افتراضي يمكنك التحكم فيه باستخدام StandardInput ، كما تعلم بالفعل. لكن Ctrl-C و Ctrl-Break ليسوا أحرفًا يتم إرسالها إلى العملية من خلال هذا الدفق ، ولكن بدلاً من ذلك فهي بدلاً من ذلك إشارات التحكم أن العملية تتلقى باستخدام معالجات الإشارات المسجلة ، انظر Ctrl+C و Ctrl+إشارات كسر:

بشكل افتراضي ، عندما يكون للنافذة وحدة التحكم تركيز لوحة المفاتيح ، يتم التعامل مع CTRL+C أو CTRL+كسر كإشارة (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);

نصائح أخرى

يوجد محاكاة مدخلات موجودة هنا codeplex التي قد تفعل الوظيفة لك فقط. أنا أعمل على رمز عينة وسأقوم بنشره هنا قريبًا ، ضع في اعتبارك أن محاكاة الإدخال مشابه لما تم العثور عليه في الرابط المقدم من Remus ...

يحرر: لقد وجدت أن هناك قيودًا على هذا ، يمكنك بالتأكيد الابتعاد عن النموذجي System.Windows.Forms.SendKeys.Send الطريقة ، إنها تعمل بفعالية! , ، ولكن يجب أن تكون العملية

  • لا توجد اتجاهات من الجداول
  • لا يمكن أن تكون نافذة مخفية (هذا هو المكان الذي سيفشل فيه ، لأن مقبض النافذة ليس في أي مكان يمكن رؤيته ، لا توجد طريقة لجلبها إلى المقدمة لجعلها نشطة!)
  • نافذة توضح العملية لتكون فعالة!

في حالتك ، إنها مسألة العثور على النافذة ، وقم بتعيينها نشطة عبر Pinvoke "SetForeGroundWindow" ، وأرسل التسلسلات ^{BREAK} الذي يرسل إشارة كسر CTRL+إلى العملية التي تعمل بشكل جيد للغاية (خاصةً إذا كانت العملية عبارة عن ملف/دفعة سطر أوامر). هذا مقال عن CodeProject هذا يفعل هذا بالضبط ويعكس sendkeys ... لا يزال يتعين علي لصق بعض التعليمات البرمجية في هذا لإظهار ....

تحرير#2: في الواقع أنا مندهش للغاية ... حيث سيظهر هذا الرمز (دليل على المفهوم) ... إنه يستخدم:

  • InputSimulator (كما ذكرنا سابقًا)
  • نموذج Windows يتكون من زر ، عند تحميل النموذج ، يقوم تلقائيًا بتشغيل الفصل. عند النقر فوق الزر ، يقوم بنشر كسر CTRL في العملية المخفية
  • يتم إعادة توجيه دفق الإخراج بالفعل وهو نافذة مخفية.
  • الشيء الغريب ، هو أن الإخراج يتم التقاطه ولكنه لا يظهر النتائج في نافذة التصحيح ، في الوقت الفعلي ، يتم تخزينه (على ما أظن) حتى تنتهي العملية ، يتم عرض الإخراج بالكامل ...
  • لقد خدعت قليلا على FindWindow API Call ، لأنني كنت أعرف أن عنوان النافذة كان وكان قادرًا بطريقة ما على إحضاره إلى المقدمة ، واستخدام InputSimulator لإرسال ضغطات المفاتيح إليه ... أو استخدام العادي القديم التقليدي 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);
         }
     }
}

إذا كانت Nitpicky جانباً ، أعرف أن netStat يتم تشغيل سلسلة "Probedterworker" ، وقد استدعت مباشرة طريقة "postctrlc" من مؤشر ترابط واجهة المستخدم الرسومية الرئيسية ... وهذا أمر متحمس كرمز إثبات للمفهوم ، لكنه يظهر أنه يحتاج إلى تنفيذ "isynchronizeinvoke" لجعله آمنًا للخيط ، ذلك جانباً ... إنه يعمل بالفعل.

هل رأيت هذه الأداة الرائعة - تلقائي. هذه أداة نصية. لإرسال مساحة خلفية ستستخدمها Send("{BACKSPACE}")

هذه أداة رائعة ويمكن أن تساعد في أتمتة العديد من النقرات اليدوية/النقرات المزدوجة/إلخ.

هل هذا ذو صلة بسؤالك؟

إذا كان لديك نافذة نماذج Windows يمكنك إرسال المفاتيح إليها ، إذن Sendkeys قد يكون حلًا مناسبًا.

للضغط على المسافة الخلفية و Ctrl+C ، يجب أن يكون ذلك

SendKeys.Send("{BACKSPACE}^C");
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top