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;
}
}
}
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 ?
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.
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.
Dann nimm doch statt p.kill einfach:
p.CloseMainWindow();
//Oder
p.Close();
Das beendet den Prozess ganz normal.
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!
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
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ß.
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
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ß.
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
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ß.
Hier
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).