Hallo,
Gibt es eine Möglichket ein Consolenfenster in eine Form zu intigriren.
Gruß Mondi
_**
Gibt es eine Möglichket ein Consolenfenster in eine Form zu intigriren.
Gegenfrage: Macht so etwas Sinn ??
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
Ja indem fall schon also geht es oder nicht
Gruß Mondi
_**
GuckstDu:
Process
Process.StandardInput
Process.StandardOutput
Process.StandardError
Sowohl im SDK wie auch hier bei mycsharp
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
erklerst du mir vieleicht auch wie ich es so in meine form intigrire wäre echt net.
edit ich würde es gerne in einem MdiConteiner öffnen
Gruß Mondi
_**
Hallo Mondi,
ich glaube ihr redet etwas aneinander vorbei, also versteht etwas anderes unter "integrieren". So wie ich "integrieren" verstehe - also quasi ein Consolen-Control auf einem Form platzieren -, geht es wohl nicht.
herbivore
schade
wies dann fileicht jemand wie ich etws ähniches selber schreiben kann?
Gruß Mondi
_**
Hallo Mondi,
du könntest eine einzeilige TextBox nehmen, in die die Befehle eingegeben werden. Diese startest du dann mit Process.Start unter Verwendung der von Programmierhans genannten Eigenschaften. Auf diese Weise bekommst du die Ausgabe der Befehle zurück und kannst diese in einer mehrzeiligen TextBox darstellen.
Das ganze sieht dann ziemlich anders aus, hätte aber eine ähnliche Wirkung. Sicherlich lässt sich mein Vorschlag auch variieren (z.b. Aus- und Eingabe in der mehrzeiligen Textbox, die man farblich Weiß-auf-Schwarz einstellt). Macht es aber auch noch etwas aufwändiger.
Außerdem gibt es einen großen, prinzipiellen Nachteil. Die Ausgabe der Befehle erfolgt gepuffert. Man kriegt also nicht jedes einzelne Zeichen einzeln, sondern 1kb- oder 4kb-Blöcke. Die Ausgabe wird also mindestens sehr "ruckelig" erscheinen.
herbivore
Du könntest einen Trick anwenden, um das original Konsolen-Fenster als Control anzuzeigen. Die Windows API enthält eine Funktion namens SetParent. Damit kann man Fenster einfach "kapern".
Folgender Code importiert die nötigen Funktionen aus der Windows-API:
[DllImport("user32.dll")]
public static extern int FindWindow(
string lpClassName, // class name
string lpWindowName // window name
);
[DllImport("user32.dll")]
static extern int SetParent(int sheetWindow, int hWndNewParent);
[DllImport("user32.dll")]
static extern bool MoveWindow(int hWnd, int X, int Y, int nWidth, int nHeight,bool bRepaint);
Mit FindWindow kriegst Du den Window-Handle des Konsolenfensters (Du musst es natürlich vorher öffnen: System.Diagnostics.Process.Start("cmd.exe")). Dann brauchst Du noch den Handle Deines Fensters oder Controls:
this.Handle.ToInt32()
Mit SetParent kaperst Du das Konsolenfenster und schwupps wird es innerhalb Deines Fensters oder Controls angezeigt. Mit MoveWindow kannst Du die Größe anpassen. Kosmetik wie Fensterrahmen entfernen etc. ist auch kein Problem. Das geht (glaube ich) mit SetWindowLong.
SetParent(consoleWindowHandle, this.Handle.ToInt32());
Nähere Hilfe zu den API-Funktionen stehen in der MSDN Library.
Danke für die schnelle Hilfe werde beides mal testen.
Gruß Mondi
_**
Noch ne Frage,
Was soll die Variable ConsoleWindowHandle enthalten beziehungsweise welchen Parameter muss ich da Übergeben?
Gruß Mondi
_**
Außerdem gibt es einen großen, prinzipiellen Nachteil. Die Ausgabe der Befehle erfolgt gepuffert. Man kriegt also nicht jedes einzelne Zeichen einzeln, sondern 1kb- oder 4kb-Blöcke. Die Ausgabe wird also mindestens sehr "ruckelig" erscheinen.
Da ruckelt aber gar nix herbivore
Zugegeben es ist keine vollständige Implementierung... eher eine Fallstudie... Zudem ist der ErrorStream nicht abgefangen... und eine hässliche OO-Verletzung ist auch drin.... diese müsste wieder raus.... aber es ging für mich mal wieder nur um die Machbarkeit 🙂
Aber so würde es gehen🙂
Gruss
Programmierhans
public class VirtualConsole : System.Windows.Forms.TextBox
{
Process p=new Process();
StreamReader sr;
StreamWriter sw;
Thread _ThreadRead;
bool _End=false;
private bool _Ignore;
private System.ComponentModel.Container components = null;
public VirtualConsole()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();
// TODO: Add any initialization after the InitializeComponent call
this.Multiline=true;
ProcessStartInfo psi=new ProcessStartInfo("cmd.exe");
psi.CreateNoWindow=true;
p.StartInfo=psi;
psi.RedirectStandardInput=true;
psi.RedirectStandardOutput=true;
psi.UseShellExecute=false;
p.Start();
sw=p.StandardInput;
this._ThreadRead=new Thread(new ThreadStart(this.ReadInput));
this._ThreadRead.Start();
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
//
// VirtualConsole
//
this.AcceptsReturn = true;
}
#endregion
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
}
}
private void AddString(string ps, bool pAddNewLine)
{
if (pAddNewLine)
{
this.Text+=string.Concat(ps,Environment.NewLine);
}
else
{
this.Text+=ps;
}
this.SelectionLength=0;
this.SelectionStart=this.Text.Length;
this.ScrollToCaret();
}
delegate void AddStringDelegate(string ps, bool pAddNewLine);
delegate string ReadInputDelegate();
private void ReadInput()
{
this.sr=p.StandardOutput;
while (!this._End)
{
bool addNewLine=true;
string s=ReadInputLine();
s=s.Replace(Environment.NewLine,string.Empty);
if (s.IndexOf("echo on")>-1)
{
s=s.Replace("echo on",string.Empty);
addNewLine=false;
}
if (this._Ignore)
{
this._Ignore=false;
}
else
{
if (s!=string.Empty)
{
this.Invoke(new AddStringDelegate(this.AddString),new object[]{s, addNewLine});
}
}
Thread.SpinWait(1);
}
this.FindForm().Close();
this.Dispose();
}
private string ReadInputLine()
{
try
{
return sr.ReadLine();
}
catch{}
return string.Empty;
}
ArrayList _Buffer=new ArrayList();
protected override void OnKeyPress(KeyPressEventArgs e)
{
if (e.KeyChar=='\r')
{
char[] chars=new char[this._Buffer.Count];
Array.Copy(this._Buffer.ToArray(typeof(char)),0,chars,0,this._Buffer.Count);
string s=new string(chars);
if (s.ToLower()=="cls")
{
this.Text=string.Empty;
this.sw.WriteLine("echo on");
e.Handled=true;
}
else if (s.ToLower()=="exit")
{
this._End=true;
this._ThreadRead.Interrupt();
p.Close();
}
else
{
this._Ignore=true;
this.sw.WriteLine(s);
this.sw.WriteLine("echo on");
}
this._Buffer.Clear();
}
else
{
this._Buffer.Add(e.KeyChar);
this.AddString(new string(new char[]{e.KeyChar}),false);
e.Handled=true;
}
base.OnKeyPress (e);
}
protected override void OnHandleCreated(EventArgs e)
{
this.sw.WriteLine("echo on");
base.OnHandleCreated (e);
}
}
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
Hallo Programmierhans,
Da ruckelt aber gar nix herbivore
ich hatte vorgeschlagen, die Kommandos einzeln zu starten. Dein Vorschlag einfach den Command-Prozessor zu starten ist natürlich besser. Scheinbar flusht der jede Zeile. Wie er das schafft ist mir unklar.
herbivore
Hallo Mondi,
Was soll die Variable ConsoleWindowHandle enthalten beziehungsweise welchen Parameter muss ich da Übergeben?
das:
Mit FindWindow kriegst Du den Window-Handle des Konsolenfensters
herbivore
Sag bescheid, wenn es nicht klappt, dann poste ich einen Beispielcode.
Hallo Programmierhans
is echt super aber nenn bisel was stimt noch nicht wies nicht ob es an mir liegt die Backspace tasste geht nicht. Und er schreib dalles hintereinander kanst du mir noch sagen wie ich das umbigen kann?
Hallo Rainbird
were echt super würde das gerne auch mal testen.
Gruß Mondi
_**
Hallo Mondi,
Enter funktioniert nicht, weil du das 'r' in der einen Abfrage durch '\r' ersetzen musst. An der gleichen Stelle müsstest du noch was für die Backspace-Taste einbauen. Es ist ja nur eine Vorlage, den Rest musst du schon selbst machen. Oder erwartest du hier fertige Komponenten als Lösung? 🙂
herbivore
das wars was ich wissen wollte danke.
Nein ich erwart keinen fertigen Code sonst hätte ich mich ja beschwert das keine Verweise in dem Beispil forhanden sind wiel sowas is imer nur ne grunglage und nicht mehr. Ich stehe halt nur manchmal auf dem Schlach vorallem weil ich heut sehr viel stress hatte und vs.net in der Firma auch noch spint und stendig fehler ferursacht die keine sind du weisst bestimt wie das mach mal ist.
Ich poste auch relativ selten selber Fragen sondern suche mir den Kram zusammen den ich brauch aber zu dem Thema gibt es ja sogut wie nirgens etwas.
Gruß Mondi
_**
Backspace tasste geht nicht
Die musste halt auch abfangen wie die Enter-Taste bereits abgefangen ist... (wenn das Forum nicht nach belieben mal wieder die Backslashes auffrisst )...
Im Prinzip musste dann den ein Zeichen aus dem Buffer löschen und auch die TextAusgabe um ein Zeichen kürzen.....
Ich hab schon gesehen dass noch diverses zu tun ist, aber das rudimentärste läuft ja 🙂 womit bewiesen ist, dass so eine Realisierung möglich und auch sinnvoll ist..... Bis aber alles perfekt ist wirst Du noch ein paar Hürden nehmen müssen.... ich denke da vorallem an den ErrorStream der ja hier völlig unberücksichtigt bleibt.. (den kannst Du aber fast 1:1 so bauen wie den OutStream (also noch mal ein weiterer Thread)
Gruss
Programmierhans
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
Hallo zusammen!
@Programmierhans
Spitzen Vorlage!
Bei mir gibt der die Umlaute falsch aus, wie bekommt man das hin?
Gruß
Brovning
Hallo Brovning,
vermutlich Encoding-Klasse beim Öffnen der Ströme benutzen.
herbivore
Ja, aber normal macht man das ja so:
StreamWriter writer = new StreamWriter(path, false, System.Text.Encoding.Default)
Doch hier habe ich das doch nicht. Hier ist es folgendermaßen:
StreamWriter sw = p.StandardInput;
Wie mache ich es dann?
Gruß
Brovning
Hallo Brovning,
sollte mit
StreamWriter sw = new StreamWriter(p.StandardInput.BaseStream, false, System.Text.Encoding.Default)
gehen.
herbivore
So geht es leider nicht. Wenn man es so macht, dann motzt er.
Schreibt man:
sw = new StreamWriter(p.StandardInput.BaseStream, System.Text.Encoding.Default);
this.sr = new StreamReader(p.StandardOutput.BaseStream, System.Text.Encoding.Default);
Dann gibt er beim ersten Aufruf nur noch folgendes aus und lässt den momentanen Pfad weg:
Microsoft Windows 2000 [Version 5.00.2195]
(C) Copyright 1985-1999 Microsoft Corp.
Zudem zeigt er dann nur noch die Eingabe an und keine Ausgabe mehr.
Gruß
Brovning
Hallo Brovning,
naja, das überflüssige false war der Eile heute mogen geschuldet. Aber das war ja für dich auch nicht die Klippe.
Prinzipiell sollte es so gehen, wie ich geschrieben habe. Wenn es Unterschiede zum direkten Abrufen des StreamReaders/Writers gibt, dann muss man diese systematisch abstellen. Ich könnte mir vorstellen, dass StreamReader/Writer.AutoFlush so ein Unterschied ist. Wenn es das nicht ist, bzw. wenn es weitere Unterschiede gibt, kannst du jede Eigenschaft des abgerufenen und des neu erzeugten StreamReaders/Writers durchgehen und angleichen.
herbivore
[EDIT]Full-Quote von Programmierhans Code gelöscht[/EDIT]
Hi, kannst du mir mal erklaeren wie ich hier nun eine bestimmte textbox definieren kann?
Danke fuer die Hilfe.
Gar nicht, die Konsole ist die Textbox, ist doch von TextBox abgeleitet.
VirtualConsole : System.Windows.Forms.TextBox
Sprich statt einer normalen TextBox würdest du in deiner Form gleich diese Klasse verwenden.
Baka wa shinanakya naoranai.
Mein XING Profil.
if (s!=string.Empty)
{
this.Invoke(new AddStringDelegate(this.AddString),new object[]{s, addNewLine});
}
hier bekomme ich dann aber eine exception 🙁
koenntest du mir da vllt mal ein bsp geben wie ich das machen sollte? Waere nett.
Bei mir gibt der die Umlaute falsch aus, wie bekommt man das hin?
sw = new StreamWriter(p.StandardInput.BaseStream, System.Text.Encoding.Default);
Sicher ?
Ich dachte immer die Console arbeitet im Gegensatz zu Windows mit Codepage 850, also müsste es
sw = new StreamWriter(p.StandardInput.BaseStream, System.Text.Encoding.GetEncoding(850));
Hab ich aber nicht getestet.
Grüße Bernd
Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3
if (s!=string.Empty) { this.Invoke(new AddStringDelegate(this.AddString),new object[]{s, addNewLine}); }
hier bekomme ich dann aber eine exception 😦
Siehe die zwei Links hier: Konsole (cmd) auslesen - Problem
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
Hallo,
Das hat alles super funktioniert. Danke dafür.
Was ich mich nun frage ist, wie ich mitbekomme, wenn ein Befehl fertig durchgelaufen ist und welchen Errorlevel dieser geliefert hat!?
Danke.
FG Oliver
Hallo xOLIVERx,
bei der Variante, die Programmierhans gewählt hat, wohl gar nicht, wenn du die Angaben im Form bekommen willst, dass das Steuerelement anzeigt. Auf der Console kannst du den Errorlevel aber mit dem Befehl echo %errorlevel%
anzeigen.
Wenn du die Befehle mit Process.Start einzeln startest, bekommst du natürlich die gewünschten Informationen (siehe Doku Process-Klasse). Und du kannst die umgelenkte Ausgabe der gestarteten Befehl natürlich in einer TextBox anzeigen.
herbivore