it-swarm.com.de

Wie zeige ich eine Konsolenausgabe / ein Konsolenfenster in einer Formularanwendung an?

Um gleich mitzumachen, ein sehr einfaches Beispiel:

using System;
using System.Windows.Forms;

class test
{ 
    static void Main()
    { 
        Console.WriteLine("test");
        MessageBox.Show("test");
    }
}

Wenn ich dies erwartungsgemäß mit Standardoptionen kompiliere (mithilfe von csc in der Befehlszeile), wird es in eine Konsolenanwendung kompiliert. Da ich System.Windows.Forms Importiert habe, wird auch ein Meldungsfeld angezeigt.

Wenn ich nun die Option /target:winexe Verwende, die meiner Meinung nach der Auswahl von Windows Application In den Projektoptionen entspricht, wird erwartungsgemäß nur die Meldungsbox und keine Konsolenausgabe angezeigt.

(Tatsächlich kann ich, sobald es über die Befehlszeile gestartet wird, den nächsten Befehl eingeben, noch bevor die Anwendung abgeschlossen ist.).

Meine Frage lautet also: Ich weiß, dass "Windows"/Formulare von einer Konsolenanwendung ausgegeben werden können, aber gibt es trotzdem eine Möglichkeit, die Konsole von einer Windows-Anwendung anzuzeigen?

110
Wil

dieser sollte funktionieren.

using System.Runtime.InteropServices;

private void Form1_Load(object sender, EventArgs e)
{
    AllocConsole();
}

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AllocConsole();
132
wizzardz

Vielleicht ist das zu einfach ...

Erstellen Sie ein Windows Form-Projekt ...

Dann: Projekteigenschaften -> Anwendung -> Ausgabetyp -> Konsolenanwendung

Dann können Console und Forms zusammen laufen, funktioniert bei mir

116
Chaz

Wenn Sie sich keine Gedanken über das Öffnen einer Konsole auf Befehl machen, können Sie die Eigenschaften Ihres Projekts aufrufen und in Konsolenanwendung ändern

screenshot of changing the project type .

Dadurch wird weiterhin Ihr Formular angezeigt und ein Konsolenfenster geöffnet. Sie können das Konsolenfenster nicht schließen, es fungiert jedoch als hervorragende temporäre Protokollfunktion zum Debuggen.

Denken Sie daran, es wieder auszuschalten, bevor Sie das Programm bereitstellen.

54
gunr2171

Sie können AttachConsole mit pinvoke aufrufen, um ein Konsolenfenster an ein WinForms-Projekt anzuhängen: http://www.csharp411.com/console-output-from-winforms-application/

Sie können auch Log4net ( http://logging.Apache.org/log4net/index.html ) in Betracht ziehen, um die Protokollausgabe in verschiedenen Konfigurationen zu konfigurieren.

15
Adam Vandenberg

Das hat bei mir funktioniert, um die Ausgabe in eine Datei umzuleiten. Rufen Sie die Konsole mit auf

cmd/c "C:\Pfad\zu\Ihrer\application.exe"> myfile.txt

Fügen Sie diesen Code Ihrer Anwendung hinzu.

    [DllImport("kernel32.dll")]
    static extern bool AttachConsole(UInt32 dwProcessId);
    [DllImport("kernel32.dll")]
    private static extern bool GetFileInformationByHandle(SafeFileHandle hFile, out BY_HANDLE_FILE_INFORMATION lpFileInformation);
    [DllImport("kernel32.dll")]
    private static extern SafeFileHandle GetStdHandle(UInt32 nStdHandle);
    [DllImport("kernel32.dll")]
    private static extern bool SetStdHandle(UInt32 nStdHandle, SafeFileHandle hHandle);
    [DllImport("kernel32.dll")]
    private static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, SafeFileHandle hSourceHandle, IntPtr hTargetProcessHandle, out SafeFileHandle lpTargetHandle, UInt32 dwDesiredAccess, Boolean bInheritHandle, UInt32 dwOptions);
    private const UInt32 ATTACH_PARENT_PROCESS = 0xFFFFFFFF;
    private const UInt32 STD_OUTPUT_HANDLE = 0xFFFFFFF5;
    private const UInt32 STD_ERROR_HANDLE = 0xFFFFFFF4;
    private const UInt32 DUPLICATE_SAME_ACCESS = 2;
    struct BY_HANDLE_FILE_INFORMATION
    {
        public UInt32 FileAttributes;
        public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime;
        public UInt32 VolumeSerialNumber;
        public UInt32 FileSizeHigh;
        public UInt32 FileSizeLow;
        public UInt32 NumberOfLinks;
        public UInt32 FileIndexHigh;
        public UInt32 FileIndexLow;
    }
    static void InitConsoleHandles()
    {
        SafeFileHandle hStdOut, hStdErr, hStdOutDup, hStdErrDup;
        BY_HANDLE_FILE_INFORMATION bhfi;
        hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
        hStdErr = GetStdHandle(STD_ERROR_HANDLE);
        // Get current process handle
        IntPtr hProcess = Process.GetCurrentProcess().Handle;
        // Duplicate Stdout handle to save initial value
        DuplicateHandle(hProcess, hStdOut, hProcess, out hStdOutDup,
        0, true, DUPLICATE_SAME_ACCESS);
        // Duplicate Stderr handle to save initial value
        DuplicateHandle(hProcess, hStdErr, hProcess, out hStdErrDup,
        0, true, DUPLICATE_SAME_ACCESS);
        // Attach to console window – this may modify the standard handles
        AttachConsole(ATTACH_PARENT_PROCESS);
        // Adjust the standard handles
        if (GetFileInformationByHandle(GetStdHandle(STD_OUTPUT_HANDLE), out bhfi))
        {
            SetStdHandle(STD_OUTPUT_HANDLE, hStdOutDup);
        }
        else
        {
            SetStdHandle(STD_OUTPUT_HANDLE, hStdOut);
        }
        if (GetFileInformationByHandle(GetStdHandle(STD_ERROR_HANDLE), out bhfi))
        {
            SetStdHandle(STD_ERROR_HANDLE, hStdErrDup);
        }
        else
        {
            SetStdHandle(STD_ERROR_HANDLE, hStdErr);
        }
    }

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
        // initialize console handles
        InitConsoleHandles();

        if (args.Length != 0)
        {

            if (args[0].Equals("waitfordebugger"))
            {
                MessageBox.Show("Attach the debugger now");
            }
            if (args[0].Equals("version"))
            {
                String TypeOfBuild = "";
                #if DEBUG
                    TypeOfBuild = "d";
                #else
                TypeOfBuild = "r";
                #endif
                String output = TypeOfBuild + Assembly.GetExecutingAssembly().GetName().Version.ToString();
                //Just for the fun of it
                Console.Write(output);
                Console.Beep(4000, 100);
                Console.Beep(2000, 100);
                Console.Beep(1000, 100);
                Console.Beep(8000, 100);
                return;
            }
        }
    }

Ich habe diesen Code hier gefunden: http://www.csharp411.com/console-output-from-winforms-application/ Ich dachte, es wäre wert, ihn auch hier zu posten.

11
Mike de Klerk

Grundsätzlich können hier zwei Dinge passieren.

Konsolenausgabe Es ist möglich, dass sich ein winforms-Programm an das Konsolenfenster anschließt, von dem es erstellt wurde (oder an ein anderes Konsolenfenster oder auf Wunsch an ein neues Konsolenfenster). Sobald die Verbindung zum Konsolenfenster hergestellt ist, funktioniert Console.WriteLine () usw. wie erwartet. Zu diesem Ansatz gehört, dass das Programm die Steuerung sofort an das Konsolenfenster zurückgibt und dann weiter darauf schreibt, sodass der Benutzer auch im Konsolenfenster tippen kann. Sie können Start mit dem Parameter/wait verwenden, um dies zu handhaben, denke ich.

Link zum Starten der Befehlssyntax

Umgeleitete Konsolenausgabe Dies ist, wenn jemand die Ausgabe Ihres Programms an eine andere Stelle leitet, z.

yourapp> file.txt

In diesem Fall ignoriert das Anbringen an einem Konsolenfenster die Rohrleitungen. Damit dies funktioniert, können Sie Console.OpenStandardOutput () aufrufen, um ein Handle für den Stream abzurufen, an den die Ausgabe weitergeleitet werden soll. Dies funktioniert nur, wenn die Ausgabe weitergeleitet wird. Wenn Sie also beide Szenarien verarbeiten möchten, müssen Sie die Standardausgabe öffnen, darauf schreiben und eine Verbindung zum Konsolenfenster herstellen. Dies bedeutet, dass die Ausgabe an das Konsolenfenster und an die Pipe gesendet wird, aber dies ist die beste Lösung, die ich finden konnte. Unterhalb des Codes verwende ich dazu.

// This always writes to the parent console window and also to a redirected stdout if there is one.
// It would be better to do the relevant thing (eg write to the redirected file if there is one, otherwise
// write to the console) but it doesn't seem possible.
public class GUIConsoleWriter : IConsoleWriter
{
    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    private static extern bool AttachConsole(int dwProcessId);

    private const int ATTACH_PARENT_PROCESS = -1;

    StreamWriter _stdOutWriter;

    // this must be called early in the program
    public GUIConsoleWriter()
    {
        // this needs to happen before attachconsole.
        // If the output is not redirected we still get a valid stream but it doesn't appear to write anywhere
        // I guess it probably does write somewhere, but nowhere I can find out about
        var stdout = Console.OpenStandardOutput();
        _stdOutWriter = new StreamWriter(stdout);
        _stdOutWriter.AutoFlush = true;

        AttachConsole(ATTACH_PARENT_PROCESS);
    }

    public void WriteLine(string line)
    {
        _stdOutWriter.WriteLine(line);
        Console.WriteLine(line);
    }
}
10
cedd

Sie können eine Windows Forms-Anwendung erstellen und den Ausgabetyp in "Konsole" ändern.

Dies führt dazu, dass sowohl eine Konsole als auch das Formular geöffnet werden.

enter image description here

3
Pedro Rodrigues
using System;
using System.Runtime.InteropServices;

namespace SomeProject
{
    class GuiRedirect
    {
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool AttachConsole(int dwProcessId);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr GetStdHandle(StandardHandle nStdHandle);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool SetStdHandle(StandardHandle nStdHandle, IntPtr handle);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern FileType GetFileType(IntPtr handle);

    private enum StandardHandle : uint
    {
        Input = unchecked((uint)-10),
        Output = unchecked((uint)-11),
        Error = unchecked((uint)-12)
    }

    private enum FileType : uint
    {
        Unknown = 0x0000,
        Disk = 0x0001,
        Char = 0x0002,
        Pipe = 0x0003
    }

    private static bool IsRedirected(IntPtr handle)
    {
        FileType fileType = GetFileType(handle);

        return (fileType == FileType.Disk) || (fileType == FileType.Pipe);
    }

    public static void Redirect()
    {
        if (IsRedirected(GetStdHandle(StandardHandle.Output)))
        {
            var initialiseOut = Console.Out;
        }

        bool errorRedirected = IsRedirected(GetStdHandle(StandardHandle.Error));
        if (errorRedirected)
        {
            var initialiseError = Console.Error;
        }

        AttachConsole(-1);

        if (!errorRedirected)
            SetStdHandle(StandardHandle.Error, GetStdHandle(StandardHandle.Output));
    }
}
2
rag
//From your application set the Console to write to your RichTextkBox 
//object:
Console.SetOut(new RichTextBoxWriter(yourRichTextBox));

//To ensure that your RichTextBox object is scrolled down when its text is 
//changed add this event:
private void yourRichTextBox_TextChanged(object sender, EventArgs e)
{
    yourRichTextBox.SelectionStart = yourRichTextBox.Text.Length;
    yourRichTextBox.ScrollToCaret();
}

public delegate void StringArgReturningVoidDelegate(string text);
public class RichTextBoxWriter : TextWriter
{
    private readonly RichTextBox _richTextBox;
    public RichTextBoxWriter(RichTextBox richTexttbox)
    {
        _richTextBox = richTexttbox;
    }

    public override void Write(char value)
    {
        SetText(value.ToString());
    }

    public override void Write(string value)
    {
        SetText(value);
    }

    public override void WriteLine(char value)
    {
        SetText(value + Environment.NewLine);
    }

    public override void WriteLine(string value)
    {
        SetText(value + Environment.NewLine);
    }

    public override Encoding Encoding => Encoding.ASCII;

    //Write to your UI object in thread safe way:
    private void SetText(string text)
    {
        // InvokeRequired required compares the thread ID of the  
        // calling thread to the thread ID of the creating thread.  
        // If these threads are different, it returns true.  
        if (_richTextBox.InvokeRequired)
        {
            var d = new StringArgReturningVoidDelegate(SetText);
            _richTextBox.Invoke(d, text);
        }
        else
        {
            _richTextBox.Text += text;
        }
    }
}
2
Kamil Kh

Sie können jederzeit zwischen den Anwendungstypen zu Konsole oder Windows wechseln. Sie werden also keine spezielle Logik schreiben, um die Standardausgabe zu sehen. Wenn Sie die Anwendung im Debugger ausführen, wird im Ausgabefenster die gesamte Standardausgabe angezeigt. Sie können auch einfach einen Haltepunkt hinzufügen und in den Haltepunkt-Eigenschaften "Bei Treffer ..." ändern, um beliebige Meldungen und Variablen auszugeben. Sie können auch "Ausführung fortsetzen" aktivieren/deaktivieren und Ihr Haltepunkt wird quadratisch. Die Breakpoint-Meldungen ändern also nichts an der Anwendung im Debug-Ausgabefenster.

1
armagedescu

Lassen Sie es einfach als Windows Forms-App und erstellen Sie ein einfaches Formular, um die Konsole zu imitieren. Das Formular kann so gestaltet werden, dass es genau wie die schwarz dargestellte Konsole aussieht und direkt auf Tastendruck reagiert. Anschließend entscheiden Sie in der Datei program.cs, ob Sie das Hauptformular oder das ConsoleForm ausführen müssen. Ich verwende diesen Ansatz zum Beispiel, um die Befehlszeilenargumente in der Datei program.cs zu erfassen. Ich erstelle die ConsoleForm, verstecke sie zunächst und übergebe dann die Befehlszeilenzeichenfolgen an eine darin enthaltene AddCommand-Funktion, in der die zulässigen Befehle angezeigt werden. Schließlich, wenn der Benutzer die -h oder -? Befehl, ich rufe die .Show auf der ConsoleForm und wenn der Benutzer eine Taste drückt, schließe ich das Programm. Wenn der Benutzer das - nicht gibt? Befehl schließe ich die versteckte ConsoleForm und führe das Hauptformular aus.

0
gverge