Laden...

CTRL C senden um Prozess zu beenden

Erstellt von lestremm vor 14 Jahren Letzter Beitrag vor 14 Jahren 3.827 Views
L
lestremm Themenstarter:in
4 Beiträge seit 2009
vor 14 Jahren
CTRL C senden um Prozess zu beenden

Hi,

ich habe u.a. über die System.Diagnostic-Klasse von C# versucht, einen CTRL-C Befehl an einen Prozess zu senden, den ich vorher selbst erzeugt habt. Im Prinzip habe ich dabei das selbe Problem wie hier schon beschrieben:

Strg-C an einen Prozess senden

Ich habe es auch leider mit

inputWriter.WriteLine("\x03");

nicht geschafft, ein CTRL-C zu senden. Darüber hinaus habe ich es auch mit einigen Windows-APIs versucht, was allerdings auch nicht funktioniert hat.

Was geht, ist die sendKeys-Methode. Die steht mir aber leider nicht zur Verfügung, da der Prozess im Hintergrund läuft und ich die Ausgabe in eine Form umlenke.

Deshalb meine Frage: Hat jemand eine Idee, wie ich am besten über den inputWriter ein CTRL-C an einen Prozess senden kann? Ich würde zur Not auch was aus der Win32-API nehmen 😃 Hier einmal meine Klasse, das Problem ist in der Methode sendAbort();

Vielen Dank!



using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Windows.Forms;
using System.IO;

namespace GTC_CP
{

    class InternalProcess
    {
        Process p;
        GUI g;
        String shortProcessName;
        StreamWriter inputWriter;


        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, uint lParam);

        // Get a handle to an application window.
        [DllImport("USER32.DLL")]
        public static extern IntPtr FindWindow(string lpClassName,
            string lpWindowName);

        // Activate an application window.
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern int GenerateConsoleCtrlEvent(XConsoleEvent sigevent, int dwProcessGroupId);

        


        public enum XConsoleEvent
        {
            CTRL_C = 0, // From wincom.h
            CTRL_BREAK = 1,
            CTRL_CLOSE = 2,
            CTRL_LOGOFF = 5,
            CTRL_SHUTDOWN = 6
        } 

        public InternalProcess(GUI g, String filename, String arguments)
        {
            this.g = g;

            p = new Process();

            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            p.OutputDataReceived += new DataReceivedEventHandler(process_OutputDataReceived);
            p.StartInfo.UseShellExecute = false;

            p.StartInfo.FileName = filename;
            p.StartInfo.Arguments = arguments;

            shortProcessName = getShortnameFromProcess(p);

            
            
           
        }

        public void start()
        {

            if (Process.GetProcessesByName(shortProcessName).Length == 0)
            {

                p.Start();

                p.OutputDataReceived += new DataReceivedEventHandler(process_OutputDataReceived);
                p.ErrorDataReceived += new DataReceivedEventHandler(process_ErrorDataReceived);

                inputWriter = p.StandardInput;
                p.BeginOutputReadLine();


                p.BeginErrorReadLine();
                //p.BeginOutputReadLine();
                //p.Kill();
                //p = null;
            }
            else
            {
                //receive_message("The process '" + getNameFromProcess(p) + "' has already started, please stop first.");
                g.receiveMessage("The process '" + shortProcessName + "' has already started, please stop first.");
            }

        }

        public Boolean stop()
        {
            Boolean returnValue = true;

            //Process was initialized
            if (p != null)
            {
                try
                {
                    //p.StandardInput.WriteLine("\x3");   
                    //if (!p.CloseMainWindow()) p.Kill();
                    //p.WaitForExit(1000);
                    //p.Close();

                    //butCtrlC_Click();


                    p.Kill();
                    p = null;

                    //mysql_process = null;
                    //receive_message("Process has stoped.");
                }
                catch (Exception e)
                {
                    try
                    {
                        //Process[] tmpprocess = Process.GetProcessesByName(shortProcessName);
                        //tmpprocess[0].Kill();
                        //tmpprocess = null;
                    }
                    catch (Exception ex)
                    {
                        g.receiveException(ex.Message.ToString(), "");
                        returnValue = false;
                    }

                }
            }
            else
            {
                returnValue = false;
            }

            return returnValue;

        }


	 
	public void sendAbort() 
	{
        const int WM_COPY = 0;

        /*
        IntPtr hWindow = p.MainWindowHandle;


        SetForegroundWindow(hWindow);
        
        SendKeys.SendWait("^C");
        */

        //SendMessage(p.MainWindowHandle, WM_COPY, 0, 0);

        inputWriter.WriteLine("\x03");

        /*
        try
        {
            GenerateConsoleCtrlEvent(XConsoleEvent.CTRL_C, 0);
            GenerateConsoleCtrlEvent(XConsoleEvent.CTRL_C, p.Id);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message.ToString());
        }
        */
        //p.WaitForExit();
        //WriteLine(ConsoleSpecialKey.ControlC);

        //p.CloseMainWindow();
        //p.Close();

	 
	} 


        void process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            g.receiveMessage(e.Data, shortProcessName);
        }

        void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            g.receiveMessage(e.Data, shortProcessName);
        }


        String getShortnameFromProcess(Process p)
        {
            String processName = p.StartInfo.FileName.Substring((p.StartInfo.FileName.LastIndexOf('/') + 1));
            processName = processName.Substring(0, processName.LastIndexOf('.'));

            return processName;
        }

    }

    
}

173 Beiträge seit 2006
vor 14 Jahren

Wenn ich dich richtig verstanden habe willst du doch lediglich einen Prozess aus der gleichen Applikation beenden, oder ?

Dann erscheint mir eine „ private bool userWantsAbort“ am einfachsten oder sind es zwei verschiedene Applikationen die nichts voneinander wissen ?

L
lestremm Themenstarter:in
4 Beiträge seit 2009
vor 14 Jahren

Hi,

genau, ich möchte einen Prozess beenden, der vorher erstellt wurde (Process p).

Ich möchte Ihn aber nicht mit


p.kill();

beenden, da der Prozess dann nicht sauber runterfährt. Statt dessen wollte ich ihm eigentlich ein CTRL+C senden, scheitere aber daran.

173 Beiträge seit 2006
vor 14 Jahren

Sorry, aber was jetzt.

Wenn das nur ein Thread aus deiner Applikation ist frage einfach den bool wert während deiner Verarbeitung ab und beende den Prozess sauber.

T
708 Beiträge seit 2008
vor 14 Jahren

Dann nimm doch statt p.kill einfach:

p.CloseMainWindow();
            //Oder
            p.Close();

Das beendet den Prozess ganz normal.

L
lestremm Themenstarter:in
4 Beiträge seit 2009
vor 14 Jahren

Hi,

das Problem bei


p.CloseMainWindow();
//oder
p.Close();

ist, dass der Prozess auch nicht "sauber" beendet wird. Konkret starte ich über C# einen MySQL-Server, der gerne wieder richtig heruntergefahren werden möchte. Das jedoch macht weder


p.CloseMainWindow();
//noch
p.Close();
//noch
p.Kill()

aber CTRL-C. Ich habe mir mittlerweile damit beholfen, dass ich einen zweiten Prozess (mysqladmin) starte und dieser dann den anderen Prozess mit

mysqladmin shutdown

beendet. Nichts desto trotz wäre ich noch daran interessiert, wie ich ein CTRL+C an einen Prozess senden kann.

Vielen Dank!

1.361 Beiträge seit 2007
vor 14 Jahren

Hi lestremm,

MySQL-Server als service starten. Schließlich ist es das, und kein "schnöder" Prozess.
Dann solltest du auch mit "net stop mysql" das gewünschte Resultat erzielen können.

//Edit: oder aber du nutzt dies MySQL-C-Api. Also DLL inkludieren.
Mit dem Funktionen dann Verbindung zum Server aufbauen und anschließend mysql_shutdown() aufrufen.

beste Grüße
zommi

1.564 Beiträge seit 2007
vor 14 Jahren

Hallo

CTRL+C bei einer Konsolenapplikation entspricht einem Taskmanager-Kill. Konsolenapplikationen haben keine Msg-Loop und können kein normales Close() handeln.

Grüße
Flo

Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+

Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo Florian Reischl,

CTRL+C bei einer Konsolenapplikation entspricht einem Taskmanager-Kill.

also das wage ich zu bezweifeln. So pauschal stimmt das sicher nicht. Eine Konsolenanwendung kann ja sogar einstellen, dass es Ctrl-C als ganz normale Eingabe bekommt.

herbivore

1.564 Beiträge seit 2007
vor 14 Jahren

Hallo herbivore

CTRL+C bei einer Konsolenapplikation entspricht einem Taskmanager-Kill.
Eine Konsolenanwendung kann ja sogar einstellen, dass es Ctrl-C als ganz normale Eingabe bekommt.

Echt? Habe ich noch nie gesehen.

Das funktioniert bei mir nicht:

         ConsoleKeyInfo keyInfo = Console.ReadKey();
         if (keyInfo.Modifiers == ConsoleModifiers.Control && keyInfo.Key == ConsoleKey.C)
         {
            Console.WriteLine("Blah");
         }

Wo könnte man dass denn einstellen?

Grüße
Flo

Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+

Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo Florian Reischl,

Console.TreatControlCAsInput

true, wenn STRG+C als normale Eingabe behandelt wird, andernfalls false.

Console.CancelKeyPress

Das CancelKeyPress-Ereignis ermöglicht es einer Konsolenanwendung, das STRG+C-Signal abzufangen, sodass die Anwendung bestimmen kann, ob sie weiter ausgeführt oder beendet werden soll.

herbivore

1.564 Beiträge seit 2007
vor 14 Jahren

Wow. Wieder was dazugelernt, die Property ist mir noch nie aufgefallen!

Danke
Flo

Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+

Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.

L
lestremm Themenstarter:in
4 Beiträge seit 2009
vor 14 Jahren

Hier

ConsoleSpecialKey-Enumeration

gibts noch ein komplettes Beispiel, wie man auf einer Konsole STRC+C gezielt abfangen und z.B. durch "x" ersetzen kann.

@zommi: Leider lassen die Rechte (Windows Vista) das installieren bzw. starten eines Dienstes als Benutzer nicht zu. Davon abgesehen bietet sich ja nicht jeder Prozess als Dienst an.

Versteh ich das also richtig, dass CTRL+C unter .NET nicht möglich ist? Kann ich mir irgendwie nur schwer vorstellen, da ich es mit der SendKeys-Methode schon hinbekommen habe (dazu muss die Anwendung allerdings offen sein).