Frage Konsole in Windows-Anwendung anzeigen?


Gibt es eine Möglichkeit, die Konsole in einer Windows-Anwendung anzuzeigen?

Ich möchte so etwas machen:

static class Program
{
    [STAThread]
    static void Main(string[] args) {
        bool consoleMode = Boolean.Parse(args[0]);

        if (consoleMode) {
            Console.WriteLine("consolemode started");
            // ...
        } else {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

75
2018-01-23 08:45


Ursprung


Antworten:


Was Sie tun möchten, ist auf vernünftige Weise nicht möglich. Es gab eine ähnliche Frage also sieh dir die Antworten an.

Dann gibt es auch ein wahnsinniger Ansatz (Seite nicht verfügbar - Backup verfügbar hier.) geschrieben von Jeffrey Ritter:

Frage: Wie erstelle ich eine Anwendung, die in beiden GUI ausgeführt werden kann?   (Windows) -Modus oder Befehlszeile / Konsolenmodus?

Auf der Oberfläche erscheint das einfach: Sie erstellen eine Konsole   Anwendung, fügen Sie ein Windows-Formular hinzu, und Sie sind am Laufen.   Es gibt jedoch ein Problem:

Problem: Wenn Sie im GUI-Modus laufen, erhalten Sie sowohl ein Fenster als auch ein   lästige Konsole lauert im Hintergrund, und Sie haben keine Möglichkeit zu   Verstecke es.

Was die Leute zu haben scheinen, ist eine echte Amphibienanwendung, die laufen kann   reibungslos in jedem Modus.

Wenn Sie das Problem lösen, gibt es hier vier Anwendungsfälle:

User starts application from existing cmd window, and runs in GUI mode
User double clicks to start application, and runs in GUI mode
User starts application from existing cmd window, and runs in command mode
User double clicks to start application, and runs in command mode.

Ich poste den Code, um dies zu tun, aber mit einem Vorbehalt.

Ich denke tatsächlich, dass diese Art von Ansatz Sie in viel mehr führen wird   Ärgere die Straße als es wert ist. Zum Beispiel müssen Sie   haben zwei verschiedene Benutzeroberflächen - eine für die GUI und eine für das Kommando /   Schale. Du wirst eine seltsame zentrale Logik aufbauen müssen   Engine, die von GUI vs. Befehlszeile abstrahiert, und es geht nur   komisch werden. Wenn ich es wäre, würde ich zurücktreten und darüber nachdenken   wird in der Praxis verwendet werden, und ob diese Art der Modus-Umschaltung ist   die Arbeit wert. So, es sei denn, ein besonderer Fall verlangte es, I   würde diesen Code nicht selbst benutzen, denn sobald ich reinkomme   Situationen, in denen ich API-Aufrufe benötige, um etwas zu erledigen, tendiere ich dazu   hör auf und frage mich: "übertreibe ich Dinge?".

Ausgabetyp = Windows-Anwendung

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Microsoft.Win32;

namespace WindowsApplication
{
    static class Program
    {
        /*
    DEMO CODE ONLY: In general, this approach calls for re-thinking 
    your architecture!
    There are 4 possible ways this can run:
    1) User starts application from existing cmd window, and runs in GUI mode
    2) User double clicks to start application, and runs in GUI mode
    3) User starts applicaiton from existing cmd window, and runs in command mode
    4) User double clicks to start application, and runs in command mode.

    To run in console mode, start a cmd shell and enter:
        c:\path\to\Debug\dir\WindowsApplication.exe console
        To run in gui mode,  EITHER just double click the exe, OR start it from the cmd prompt with:
        c:\path\to\Debug\dir\WindowsApplication.exe (or pass the "gui" argument).
        To start in command mode from a double click, change the default below to "console".
    In practice, I'm not even sure how the console vs gui mode distinction would be made from a
    double click...
        string mode = args.Length > 0 ? args[0] : "console"; //default to console
    */

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool AllocConsole();

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool FreeConsole();

        [DllImport("kernel32", SetLastError = true)]
        static extern bool AttachConsole(int dwProcessId);

        [DllImport("user32.dll")]
        static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll", SetLastError = true)]
        static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

        [STAThread]
        static void Main(string[] args)
        {
            //TODO: better handling of command args, (handle help (--help /?) etc.)
            string mode = args.Length > 0 ? args[0] : "gui"; //default to gui

            if (mode == "gui")
            {
                MessageBox.Show("Welcome to GUI mode");

                Application.EnableVisualStyles();

                Application.SetCompatibleTextRenderingDefault(false);

                Application.Run(new Form1());
            }
            else if (mode == "console")
            {

                //Get a pointer to the forground window.  The idea here is that
                //IF the user is starting our application from an existing console
                //shell, that shell will be the uppermost window.  We'll get it
                //and attach to it
                IntPtr ptr = GetForegroundWindow();

                int  u;

                GetWindowThreadProcessId(ptr, out u);

                Process process = Process.GetProcessById(u);

                if (process.ProcessName == "cmd" )    //Is the uppermost window a cmd process?
                {
                    AttachConsole(process.Id);

                    //we have a console to attach to ..
                    Console.WriteLine("hello. It looks like you started me from an existing console.");
                }
                else
                {
                    //no console AND we're in console mode ... create a new console.

                    AllocConsole();

                    Console.WriteLine(@"hello. It looks like you double clicked me to start
                   AND you want console mode.  Here's a new console.");
                    Console.WriteLine("press any key to continue ...");
                    Console.ReadLine();       
                }

                FreeConsole();
            }
        }
    }
}

76
2018-01-23 08:48



Das ist ein bisschen alt (OK, es ist sehr alt), aber ich mache genau das gleiche jetzt. Hier ist eine sehr einfache Lösung, die für mich funktioniert:

    public static void ShowConsoleWindow()
    {
        var handle = GetConsoleWindow();

        if (handle == IntPtr.Zero)
        {
            AllocConsole();
        }
        else
        {
            ShowWindow(handle, SW_SHOW);
        }
    }

    public static void HideConsoleWindow()
    {
        var handle = GetConsoleWindow();

        ShowWindow(handle, SW_HIDE);
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool AllocConsole();

    [DllImport("kernel32.dll")]
    static extern IntPtr GetConsoleWindow();

    [DllImport("user32.dll")]
    static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    const int SW_HIDE = 0;
    const int SW_SHOW = 5;

62
2018-02-26 00:18



Am einfachsten ist es, eine WinForms-Anwendung zu starten, zu den Einstellungen zu wechseln und den Typ in eine Konsolenanwendung zu ändern.


17
2018-01-23 10:12



Haftungsausschluss

Es gibt einen Weg, dies zu erreichen, der ganz einfach ist, aber ich würde nicht vorschlagen, dass es ein guter Ansatz für eine App ist, die Sie anderen Leuten zeigen lassen. Aber wenn Sie möchten, dass ein Entwickler die Konsolen- und Windows-Formulare gleichzeitig anzeigt, kann dies sehr einfach durchgeführt werden.

Diese Methode unterstützt auch das Anzeigen nur des Konsolenfensters, unterstützt jedoch nicht nur das Anzeigen der Windows Form - d. H. Die Konsole wird immer angezeigt. Sie können nur interagieren (d. H. Daten empfangen - Console.ReadLine(), Console.Read()) mit dem Konsolenfenster, wenn Sie die Windows-Formulare nicht anzeigen; Ausgabe an die Konsole - Console.WriteLine() - funktioniert in beiden Modi.

Dies wird so wie es ist zur Verfügung gestellt; Keine Garantie, dass dies später nicht etwas Schreckliches tun wird, aber es funktioniert.

Projektschritte

Beginne von einem Standard Konsolenanwendung.

Markiere die Main Methode als [STAThread]

Fügen Sie eine Referenz in Ihrem Projekt hinzu System.Windows.Forms

Fügen Sie ein Windows hinzu Bilden zu deinem Projekt.

Fügen Sie Ihrem Windows-Standardcode den Standardcode hinzu Main Methode:

Endresultat

Sie werden eine Anwendung haben, die die Konsolen- und optional Windows-Formulare anzeigt.

Beispielcode

Programm.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ConsoleApplication9 {
    class Program {

        [STAThread]
        static void Main(string[] args) {

            if (args.Length > 0 && args[0] == "console") {
                Console.WriteLine("Hello world!");
                Console.ReadLine();
            }
            else {
                Application.EnableVisualStyles(); 
                Application.SetCompatibleTextRenderingDefault(false); 
                Application.Run(new Form1());
            }
        }
    }
}

Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ConsoleApplication9 {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }

        private void Form1_Click(object sender, EventArgs e) {
            Console.WriteLine("Clicked");
        }
    }
}

13
2018-01-23 09:30



Einen alten Thread wieder auferstehen zu lassen, da keine der Antworten hier sehr gut für mich funktioniert hat.

Ich habe einen einfachen Weg gefunden, der ziemlich robust und einfach erscheint. Es hat für mich funktioniert. Die Idee:

  • Kompilieren Sie Ihr Projekt als Windows-Anwendung. Es kann eine übergeordnete Konsole geben, wenn die ausführbare Datei gestartet wird, aber möglicherweise nicht. Das Ziel besteht darin, die vorhandene Konsole erneut zu verwenden, falls eine vorhanden ist, oder eine neue zu erstellen, falls dies nicht der Fall ist.
  • AttachConsole (-1) sucht nach der Konsole des übergeordneten Prozesses. Wenn es einen gibt, hängt es daran und du bist fertig. (Ich habe es versucht und es funktionierte ordnungsgemäß beim Aufruf meiner Anwendung von cmd)
  • Wenn AttachConsole false zurückgibt, gibt es keine übergeordnete Konsole. Erstellen Sie eine mit AllocConsole.

Beispiel:

static class Program
{
    [DllImport( "kernel32.dll", SetLastError = true )]
    static extern bool AllocConsole();

    [DllImport( "kernel32", SetLastError = true )]
    static extern bool AttachConsole( int dwProcessId );

    static void Main(string[] args)
    {
        bool consoleMode = Boolean.Parse(args[0]);
        if (consoleMode)
        {
           if (!AttachConsole(-1))
              AllocConsole();
           Console.WriteLine("consolemode started");
           // ...
        } 
        else
        {
           Application.EnableVisualStyles();
           Application.SetCompatibleTextRenderingDefault(false);
           Application.Run(new Form1());
        }
    }
}

Ein Wort der Vorsicht: Wenn Sie versuchen, vor dem Anhängen oder Zuweisen einer Konsole an die Konsole zu schreiben, funktioniert dieser Ansatz nicht. Meine Vermutung ist das erste Mal, dass Sie Console.Write / WriteLine aufrufen. Wenn es noch keine Konsole gibt, erstellt Windows automatisch eine versteckte Konsole für Sie. (Vielleicht ist Anthonys ShowConsoleWindow-Antwort besser, nachdem Sie bereits in die Konsole geschrieben haben, und meine Antwort ist besser, wenn Sie noch nicht in die Konsole geschrieben haben). Wichtig ist, dass dies nicht funktioniert:

static void Main(string[] args)
    {
        Console.WriteLine("Welcome to the program");   //< this ruins everything
        bool consoleMode = Boolean.Parse(args[0]);
        if (consoleMode)
        {
           if (!AttachConsole(-1))
              AllocConsole();
           Console.WriteLine("consolemode started");   //< this doesn't get displayed on the parent console
           // ...
        } 
        else
        {
           Application.EnableVisualStyles();
           Application.SetCompatibleTextRenderingDefault(false);
           Application.Run(new Form1());
        }
    }

6
2018-05-10 19:04



Was für mich funktionierte, war, eine Konsolen-App separat zu schreiben, die das tat, was ich tun wollte, sie zu einer EXE kompilieren und dann tun Process.Start("MyConsoleapp.exe","Arguments")


3
2017-09-18 18:47



Überprüfen Sie diesen Quellcode. Alle kommentierten Code - verwendet, um eine Konsole in einer Windows-App zu erstellen. Unkommentiert - um die Konsole in einer Konsolenanwendung auszublenden. Von Hier. (Vorher Hier.) Projekt reg2run.

// Copyright (C) 2005-2015 Alexander Batishchev (abatishchev at gmail.com)

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace Reg2Run
{
    static class ManualConsole
    {
        #region DllImport
        /*
        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool AllocConsole();
        */

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr handle);

        /*
        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        private static extern IntPtr CreateFile([MarshalAs(UnmanagedType.LPStr)]string fileName, [MarshalAs(UnmanagedType.I4)]int desiredAccess, [MarshalAs(UnmanagedType.I4)]int shareMode, IntPtr securityAttributes, [MarshalAs(UnmanagedType.I4)]int creationDisposition, [MarshalAs(UnmanagedType.I4)]int flagsAndAttributes, IntPtr templateFile);
        */

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool FreeConsole();

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        private static extern IntPtr GetStdHandle([MarshalAs(UnmanagedType.I4)]int nStdHandle);

        /*
        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool SetStdHandle(int nStdHandle, IntPtr handle);
        */
        #endregion

        #region Methods
        /*
        public static void Create()
        {
            var ptr = GetStdHandle(-11);
            if (!AllocConsole())
            {
                throw new Win32Exception("AllocConsole");
            }
            ptr = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, 3, 0, IntPtr.Zero);
            if (!SetStdHandle(-11, ptr))
            {
                throw new Win32Exception("SetStdHandle");
            }
            var newOut = new StreamWriter(Console.OpenStandardOutput());
            newOut.AutoFlush = true;
            Console.SetOut(newOut);
            Console.SetError(newOut);
        }
        */

        public static void Hide()
        {
            var ptr = GetStdHandle(-11);
            if (!CloseHandle(ptr))
            {
                throw new Win32Exception();
            }
            ptr = IntPtr.Zero;
            if (!FreeConsole())
            {
                throw new Win32Exception();
            }
        }
        #endregion
    }
}

2
2018-01-24 23:44



Eigentlich könnte AllocConsole mit SetStdHandle in einer GUI-Anwendung ein sicherer Ansatz sein. Das Problem mit dem bereits erwähnten "Konsolen-Hijacking" ist, dass die Konsole unter Umständen gar kein Vordergrundfenster ist (insbesondere unter Berücksichtigung des Zustroms neuer Fenstermanager in Vista / Windows 7).


1
2018-03-02 20:01



In wind32 sind Konsolenmodusanwendungen ein völlig anderes Beispiel als die üblichen Anwendungen, die Nachrichtenwarteschlangen empfangen. Sie werden deklariert und anders kompiliert. Sie könnten eine Anwendung erstellen, die sowohl einen Konsolenteil als auch ein normales Fenster enthält und das eine oder das andere ausblenden. Aber du verdächtigst, dass du die ganze Sache ein bisschen mehr Arbeit finden wirst, als du gedacht hast.


0
2018-01-23 08:50