Laden...

Console als Steuerelement einbinden

Erstellt von Mondi vor 18 Jahren Letzter Beitrag vor 8 Jahren 30.490 Views
Mondi Themenstarter:in
30 Beiträge seit 2005
vor 18 Jahren
Console als Steuerelement einbinden

Hallo,

Gibt es eine Möglichket ein Consolenfenster in eine Form zu intigriren.

Gruß Mondi

_**

"Man muss sich vorstellen vor den PC sitzen nur Idiotn die das Programm benutzen, deshlab muss man es so schreiben das auch der dümmste damit umgehen kann."[/b][/i]

4.221 Beiträge seit 2005
vor 18 Jahren

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...

Mondi Themenstarter:in
30 Beiträge seit 2005
vor 18 Jahren

Ja indem fall schon also geht es oder nicht

Gruß Mondi

_**

"Man muss sich vorstellen vor den PC sitzen nur Idiotn die das Programm benutzen, deshlab muss man es so schreiben das auch der dümmste damit umgehen kann."[/b][/i]

4.221 Beiträge seit 2005
vor 18 Jahren

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...

Mondi Themenstarter:in
30 Beiträge seit 2005
vor 18 Jahren

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

_**

"Man muss sich vorstellen vor den PC sitzen nur Idiotn die das Programm benutzen, deshlab muss man es so schreiben das auch der dümmste damit umgehen kann."[/b][/i]

49.485 Beiträge seit 2005
vor 18 Jahren

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

Mondi Themenstarter:in
30 Beiträge seit 2005
vor 18 Jahren

schade
wies dann fileicht jemand wie ich etws ähniches selber schreiben kann?

Gruß Mondi

_**

"Man muss sich vorstellen vor den PC sitzen nur Idiotn die das Programm benutzen, deshlab muss man es so schreiben das auch der dümmste damit umgehen kann."[/b][/i]

49.485 Beiträge seit 2005
vor 18 Jahren

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

3.728 Beiträge seit 2005
vor 18 Jahren
Api

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.

Mondi Themenstarter:in
30 Beiträge seit 2005
vor 18 Jahren

Danke für die schnelle Hilfe werde beides mal testen.

Gruß Mondi

_**

"Man muss sich vorstellen vor den PC sitzen nur Idiotn die das Programm benutzen, deshlab muss man es so schreiben das auch der dümmste damit umgehen kann."[/b][/i]

Mondi Themenstarter:in
30 Beiträge seit 2005
vor 18 Jahren

Noch ne Frage,

Was soll die Variable ConsoleWindowHandle enthalten beziehungsweise welchen Parameter muss ich da Übergeben?

Gruß Mondi

_**

"Man muss sich vorstellen vor den PC sitzen nur Idiotn die das Programm benutzen, deshlab muss man es so schreiben das auch der dümmste damit umgehen kann."[/b][/i]

4.221 Beiträge seit 2005
vor 18 Jahren

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...

49.485 Beiträge seit 2005
vor 18 Jahren

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

49.485 Beiträge seit 2005
vor 18 Jahren

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

3.728 Beiträge seit 2005
vor 18 Jahren

Sag bescheid, wenn es nicht klappt, dann poste ich einen Beispielcode.

Mondi Themenstarter:in
30 Beiträge seit 2005
vor 18 Jahren

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

_**

"Man muss sich vorstellen vor den PC sitzen nur Idiotn die das Programm benutzen, deshlab muss man es so schreiben das auch der dümmste damit umgehen kann."[/b][/i]

49.485 Beiträge seit 2005
vor 18 Jahren

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

Mondi Themenstarter:in
30 Beiträge seit 2005
vor 18 Jahren

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

_**

"Man muss sich vorstellen vor den PC sitzen nur Idiotn die das Programm benutzen, deshlab muss man es so schreiben das auch der dümmste damit umgehen kann."[/b][/i]

4.221 Beiträge seit 2005
vor 18 Jahren

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...

B
152 Beiträge seit 2005
vor 18 Jahren

Hallo zusammen!

@Programmierhans
Spitzen Vorlage!

Bei mir gibt der die Umlaute falsch aus, wie bekommt man das hin?

Gruß

Brovning

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo Brovning,

vermutlich Encoding-Klasse beim Öffnen der Ströme benutzen.

herbivore

B
152 Beiträge seit 2005
vor 18 Jahren

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

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo Brovning,

sollte mit

StreamWriter sw = new StreamWriter(p.StandardInput.BaseStream, false, System.Text.Encoding.Default)

gehen.

herbivore

B
152 Beiträge seit 2005
vor 18 Jahren

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

49.485 Beiträge seit 2005
vor 18 Jahren

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

S
7 Beiträge seit 2006
vor 17 Jahren

[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.

6.862 Beiträge seit 2003
vor 17 Jahren

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.

S
7 Beiträge seit 2006
vor 17 Jahren

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.

3.825 Beiträge seit 2006
vor 17 Jahren

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

4.221 Beiträge seit 2005
vor 12 Jahren
  
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...

X
9 Beiträge seit 2009
vor 8 Jahren

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

49.485 Beiträge seit 2005
vor 8 Jahren

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