Wysłanie z aplikacji C# sekwencji klawiszy Ctrl+C

0

Witam kolegów
jestem tu nowy i jest to mój pierwszy post.

Mam problem z wysłaniem z aplikacji C# sekwencji klawiszy Ctrl+C, przygotowałem prosty programik testowy
który uruchamia "ping onet.pl -t" opcja "-t" jest celowo przekazana aby ping trwał w nieskończoność.
Aplikacja "ping" wywoływana jest jako "Process exeProcess " można ją zatrzymać na 2 sposoby :
1 - exeProcess.Kill();
oraz
2 - Ctrl+C

Ja właśnie chcę wykorzystać tą drugą możliwość - czyli wysłać Ctrl+C z programu który uruchomił proces.
W załączonym projekcie widać nieudane próby rozwiązania problemu.

Proszę o pomoc.

0

Dziękuję za szybką odpowiedz
oczywiście widziałem te przykłady w googlu, ale to jakoś nie działa, są zamieszczone w moim kodzie.
Coś robię źle, może wkleję kawałki kodu.

proces uruchamiam w nowym wątku

 
        Process exeProcess;
        Thread thread;
        StreamWriter sw;

        public bool StartTest()
        {

            ExeName = @"ping.exe";
            Arguments = "onet.pl -t";

            run = true;
            thread = new Thread(new ThreadStart(DebugThread));
            thread.Start();
            return true;
        }
 

tu fragment nowego wątku (całość w załączniku)

 
        private void DebugThread()
        {
            // Use ProcessStartInfo class
            ProcessStartInfo startInfo = new ProcessStartInfo();
            startInfo.CreateNoWindow = true;// false;
            startInfo.UseShellExecute = false;
            startInfo.FileName = ExeName;
            startInfo.WindowStyle = ProcessWindowStyle.Normal;
            startInfo.Arguments = Arguments;
            startInfo.WorkingDirectory = Path.GetDirectoryName(ExeName);
            startInfo.RedirectStandardOutput = true;
            startInfo.RedirectStandardError = true;
            startInfo.RedirectStandardInput = true;
            try
            {
                exeProcess = Process.Start(startInfo);
                sw = exeProcess.StandardInput;


 

a następnie staram się wysłać Ctrl+C na kilka sposobów

 
                GenerateConsoleCtrlEvent(ConsoleCtrlEvent.CTRL_C, exeProcess.SessionId);
                GenerateConsoleCtrlEvent(ConsoleCtrlEvent.CTRL_C, 0);

                UInt32 CommandCtrlC = 0;
                bool result = GenerateConsoleCtrlEvent(CommandCtrlC, Convert.ToUInt32(exeProcess.Id));


                const uint VK_CONTROL = 0x11;
                const int VK_C = 0x43;
                PostMessage(exeProcess.Handle, VK_CONTROL, VK_C, 0);

                //przykład z linku googla nr2, tak go rozumiem, w dniu wczorajszym też podobny testowałem
                string inputText = char.ConvertFromUtf32(3);
                sw.WriteLine(inputText);
 

jedyne co działa to :

 
exeProcess.Kill();
 

jednak nie chcę zabijać procesu, chcę aby nadal istniał.
Nie napisałem dokładnie że chodzi gdb.exe bo przykład z pingiem też powinien być dobry.
Do gdb.exe należy wysłać ctrl+c aby zatrzymać uruchomiony program, ale potem można dać "continue"
Właśnie z tego powodu nie mogę dać "exeProcess.Kill();"

Wymienione przykłady przerobiłem, muszę popełniać jakiś błąd którego nie jestem zupełnie świadomy.
Jeśli ktoś uruchamia mój kod to gdy wyłączyć ten fragment

 
        public void KillTest()
        {
            try
            {
                run = false;
                StandardError = "";
                StandardOutput = "";
//wyłącz                exeProcess.Kill();
            }
            catch
            {
            }
        }
 

po zamknięciu aplikacji ping pozostanie widoczny w uruchomionych aplikacjach do czasu ręcznego zabicia.
Gdyby dostał ctrl+c to przestał by działać.

Teraz jeszcze czytam i szukam i wymyśliłem że może wysyłanie do okna którego nie widać nie jest możliwe ?

0

Troszkę pogooglowałem i udało mi się zrobić coś takiego, może to nie 'Control+C', ale zawieszenie procesu.

Główne wejście programu:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            ProcessStartInfo proc = new ProcessStartInfo();

            proc.FileName = "ping.exe";
            proc.Arguments = "4programmers.net -t";
            proc.UseShellExecute = false;
            proc.RedirectStandardOutput = true;

            using (Process p = Process.Start(proc))
            {
                using (StreamReader r = p.StandardOutput)
                {
                    Console.Write((string)r.ReadToEnd());
                    // p.Suspend();
                    //
                    // p.Resume();
                }
            }
        }
    }
}
 

Rozszerzona klasa 'Process'

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;

namespace ConsoleApplication1
{

    [Flags]
    public enum ThreadAccess : int
    {
        TERMINATE = (0x0001),
        SUSPEND_RESUME = (0x0002),
        GET_CONTEXT = (0x0008),
        SET_CONTEXT = (0x0010),
        SET_INFORMATION = (0x0020),
        QUERY_INFORMATION = (0x0040),
        SET_THREAD_TOKEN = (0x0080),
        IMPERSONATE = (0x0100),
        DIRECT_IMPERSONATION = (0x0200)
    }


    public static class ClassExtension
    {
        [DllImport("kernel32.dll")]
        static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
        [DllImport("kernel32.dll")]
        static extern uint SuspendThread(IntPtr hThread);
        [DllImport("kernel32.dll")]
        static extern int ResumeThread(IntPtr hThread);

        public static void Suspend(this Process process)
        {
            foreach(ProcessThread thread in process.Threads)
            {
                var pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)thread.Id);
                if(pOpenThread ==  IntPtr.Zero)
                {
                    break;
                }
                SuspendThread(pOpenThread);
            }
        }


        public static void Resume(this Process process)
        {
            foreach(ProcessThread thread in process.Threads)
            {
                var pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)thread.Id);
                if(pOpenThread == IntPtr.Zero)
                {
                    break;
                }
                ResumeThread(pOpenThread);
            }
        }
    }
}

http://stackoverflow.com/questions/71257/suspend-process-in-c-sharp
https://msdn.microsoft.com/pl-pl/library/system.diagnostics.processstartinfo.redirectstandardoutput(v=vs.110).aspx
http://www.dotnetperls.com/redirectstandardoutput

0

Wyczytałem że to chodzi o : "SIGINT - CTRL+C signal" ale nie wiem co z tym fantem zrobić.
Szukam dalej.

0

Przypomniałem sobie że gdb ma otwarty port telnet - którym wydałem polecenie "halt" zamiast Ctrl+C , co skutecznie obchodzi problem.
Proponuję zostawić wątek otwarty - może ktoś kiedyś doda coś ciekawego.

1 użytkowników online, w tym zalogowanych: 0, gości: 1