web-dev-qa-db-fra.com

Comment afficher une sortie / fenêtre de console dans une application de formulaire?

Pour rester coincé tout de suite, un exemple très basique:

using System;
using System.Windows.Forms;

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

Si je compile ceci avec les options par défaut (en utilisant csc sur la ligne de commande), comme prévu, il sera compilé dans une application console. De plus, comme j'ai importé System.Windows.Forms, une boîte de message s'affichera.

Maintenant, si j'utilise l'option /target:winexe, ce qui revient au même que choisir Windows Application dans les options du projet, comme prévu, je ne verrai que la boîte de message et aucune sortie de console.

(En fait, au moment où il est lancé depuis la ligne de commande, je peux lancer la commande suivante avant même que l'application soit terminée).

Ma question est donc la suivante: je sais que vous pouvez obtenir une sortie "windows"/forms à partir d’une application console, mais est-il possible de montrer la console à partir d’une application Windows?

110
Wil

celui-ci devrait fonctionner.

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

C'est peut-être trop simpliste ...

Créer un projet Windows Form ...

Ensuite: Propriétés du projet -> Application -> Type de sortie -> Application console

Ensuite, la console et les formulaires peuvent fonctionner ensemble, cela fonctionne pour moi

116
Chaz

Si vous ne souhaitez pas ouvrir une console sur commande, vous pouvez aller dans les propriétés de votre projet et le changer en Console Application.

screenshot of changing the project type .

Cela montrera toujours votre formulaire et ouvrira une fenêtre de console. Vous ne pouvez pas fermer la fenêtre de la console, mais cela fonctionne comme un excellent enregistreur temporaire pour le débogage.

Rappelez-vous simplement de le désactiver avant de déployer le programme.

54
gunr2171

Vous pouvez appeler AttachConsole en utilisant pinvoke pour obtenir une fenêtre de console attachée à un projet WinForms: http://www.csharp411.com/console-output-from-winforms-application/

Vous pouvez également envisager d’utiliser Log4net ( http://logging.Apache.org/log4net/index.html ) pour configurer la sortie du journal dans différentes configurations.

15
Adam Vandenberg

Cela a fonctionné pour moi, pour diriger la sortie vers un fichier. Appeler la console avec

cmd/c "C:\chemin\vers\votre\application.exe"> myfile.txt

Ajoutez ce code à votre application.

    [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;
            }
        }
    }

J'ai trouvé ce code ici: http://www.csharp411.com/console-output-from-winforms-application/ Je pensais qu'il était digne de l'afficher ici aussi.

11
Mike de Klerk

Il y a fondamentalement deux choses qui peuvent arriver ici.

Sortie de la console Il est possible qu'un programme winforms s'attache à la fenêtre de la console qui l'a créé (ou à une autre fenêtre de la console, voire à une nouvelle fenêtre de la console si vous le souhaitez). Une fois connecté à la fenêtre de la console, Console.WriteLine (), etc. fonctionne comme prévu. Un des pièges de cette approche est que le programme retourne immédiatement le contrôle à la fenêtre de la console, puis continue à l'écrire, de sorte que l'utilisateur puisse également taper dans la fenêtre de la console. Je pense que vous pouvez utiliser start avec le paramètre/wait pour gérer cela.

Lien pour démarrer la syntaxe de commande

Sortie de console redirigée C'est quand quelqu'un dirige la sortie de votre programme ailleurs, par exemple.

yourapp> fichier.txt

Dans ce cas, la connexion à une fenêtre de console ignore effectivement la tuyauterie. Pour que cela fonctionne, vous pouvez appeler Console.OpenStandardOutput () pour obtenir un descripteur du flux vers lequel la sortie doit être acheminée. Cela ne fonctionne que si la sortie est canalisée. Par conséquent, si vous souhaitez gérer les deux scénarios, vous devez ouvrir la sortie standard, y écrire et l'attacher à la fenêtre de la console. Cela signifie que la sortie est envoyée à la fenêtre de la console et au tuyau, mais que c'est la meilleure solution que j'ai pu trouver. Ci-dessous le code que j'utilise pour faire cela.

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

Vous pouvez créer une application Windows Forms et changer le type de sortie en Console.

Cela entraînera à la fois une console et le formulaire à ouvrir.

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

Vous pouvez n’importe quel moment pour basculer d’un type d’application à une console ou à une fenêtre. Donc, vous n'écrirez pas de logique spéciale pour voir la sortie standard. De plus, lors de l'exécution de l'application dans le débogueur, vous verrez tout le stdout dans la fenêtre de sortie. Vous pouvez également simplement ajouter un point d'arrêt et, dans les propriétés de point d'arrêt, modifier "Lorsque vous atteignez ...", vous pouvez générer tous les messages et variables. Aussi, vous pouvez cocher/décocher "Continuer l'exécution", et votre point d'arrêt deviendra carré. Ainsi, les messages de point d'arrêt ne changent rien dans l'application dans la fenêtre de sortie du débogage.

1
armagedescu

Pourquoi ne pas le laisser comme une application Windows Forms et créer un formulaire simple pour imiter la console. Le formulaire peut ressembler à la console à écran noir et doit répondre directement à une pression sur une touche. Ensuite, dans le fichier program.cs, vous décidez si vous devez exécuter le formulaire principal ou le formulaire ConsoleForm. Par exemple, j'utilise cette approche pour capturer les arguments de ligne de commande dans le fichier program.cs. Je crée le ConsoleForm, le masque initialement, puis passe les chaînes de ligne de commande à une fonction AddCommand, qui affiche les commandes autorisées. Enfin, si l'utilisateur a donné le -h ou -? Commande, j'appelle le .Show sur le ConsoleForm et lorsque l'utilisateur appuie sur une touche sur elle, je ferme le programme. Si l'utilisateur ne donne pas le -? Je ferme le formulaire masqué ConsoleForm et lance le formulaire principal.

0
gverge