Pertanyaan Tampilkan Konsol di Aplikasi Windows?


Apakah ada cara untuk menampilkan konsol dalam aplikasi Windows?

Saya ingin melakukan sesuatu seperti ini:

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


asal


Jawaban:


Apa yang ingin Anda lakukan tidak mungkin dengan cara yang waras. Ada pertanyaan serupa jadi lihatlah jawabannya.

Lalu ada juga sebuah pendekatan gila (situs turun - cadangan tersedia di sini.) ditulis oleh Jeffrey Knight:

Pertanyaan: Bagaimana cara membuat aplikasi yang dapat dijalankan di GUI   (windows) mode atau mode command line / console?

Di permukaannya, ini akan tampak mudah: Anda membuat Konsol   aplikasi, tambahkan formulir jendela ke sana, dan Anda mulai berjalan.   Namun, ada masalah:

Masalah: Jika Anda menjalankan dalam mode GUI, Anda berakhir dengan jendela dan a   konsol sial bersembunyi di latar belakang, dan Anda tidak memiliki cara apa pun   Sembunyikan itu.

Apa yang tampaknya orang-orang inginkan adalah aplikasi amfibi sejati yang dapat berjalan   lancar dalam mode baik.

Jika Anda memecahnya, sebenarnya ada empat kasus penggunaan di sini:

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.

Saya memposting kode untuk melakukan ini, tetapi dengan peringatan.

Saya benar-benar berpikir pendekatan semacam ini akan membawa Anda ke lebih banyak lagi   masalah di jalan daripada nilainya. Misalnya, Anda harus melakukannya   memiliki dua UI berbeda '- satu untuk GUI dan satu lagi untuk perintah /   kulit. Anda harus membangun beberapa logika sentral yang aneh   mesin yang abstrak dari GUI vs baris perintah, dan itu hanya terjadi   untuk menjadi aneh. Jika itu aku, aku akan mundur dan berpikir tentang bagaimana ini   akan digunakan dalam praktik, dan apakah jenis mode-switching ini   sepadan dengan pekerjaan. Jadi, kecuali ada kasus khusus yang menyerukannya, saya   tidak akan menggunakan kode ini sendiri, karena begitu saya bertemu   situasi di mana saya perlu panggilan API untuk menyelesaikan sesuatu, saya cenderung   berhenti dan bertanya pada diri sendiri "apakah saya terlalu banyak mengerjakan sesuatu?".

Jenis keluaran = Aplikasi Windows

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



Ini agak tua (OK, itu SANGAT tua), tapi aku melakukan hal yang sama persis sekarang. Inilah solusi yang sangat sederhana yang bekerja untuk saya:

    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



Cara termudah adalah untuk memulai aplikasi WinForms, masuk ke pengaturan dan mengubah jenis ke aplikasi konsol.


17
2018-01-23 10:12



Penolakan

Ada cara untuk mencapai ini yang cukup sederhana, tetapi saya tidak akan menyarankan itu adalah pendekatan yang baik untuk aplikasi yang Anda akan membiarkan orang lain melihat. Tetapi jika Anda memiliki beberapa pengembang perlu menunjukkan bentuk konsol dan jendela pada saat yang sama, itu bisa dilakukan dengan mudah.

Metode ini juga mendukung hanya menampilkan jendela Konsol, tetapi tidak mendukung hanya menampilkan Formulir Windows - yaitu Konsol akan selalu ditampilkan. Anda hanya dapat berinteraksi (mis. Menerima data - Console.ReadLine(), Console.Read()) dengan jendela konsol jika Anda tidak menunjukkan bentuk jendela; keluaran ke Konsol - Console.WriteLine() - berfungsi dalam kedua mode.

Ini disediakan sebagaimana adanya; tidak ada jaminan ini tidak akan melakukan sesuatu yang mengerikan di kemudian hari, tetapi itu berhasil.

Langkah-langkah proyek

Mulai dari standar Aplikasi konsol.

tandai Main metode sebagai [STAThread]

Tambahkan referensi dalam proyek Anda ke System.Windows.Forms

Tambahkan Windows Bentuk ke proyek Anda.

Tambahkan kode standar Windows start ke Anda Main metode:

Hasil akhir

Anda akan memiliki aplikasi yang menunjukkan Konsol dan bentuk jendela opsional.

Kode sampel

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



Membangkitkan kembali utas yang sangat lama, karena tidak ada jawaban di sini yang bekerja dengan sangat baik untuk saya.

Saya menemukan cara sederhana yang tampaknya cukup kuat dan sederhana. Itu berhasil bagi saya. Ide:

  • Kompilasi proyek Anda sebagai Aplikasi Windows. Mungkin ada konsol orang tua ketika eksekusi Anda dimulai, tetapi mungkin tidak. Tujuannya adalah untuk menggunakan kembali konsol yang ada jika ada, atau membuat yang baru jika tidak.
  • AttachConsole (-1) akan mencari konsol proses induk. Jika ada, menempel padanya dan Anda selesai. (Saya mencoba ini dan itu bekerja dengan baik ketika memanggil aplikasi saya dari cmd)
  • Jika AttachConsole mengembalikan kesalahan, tidak ada konsol induk. Buat satu dengan AllocConsole.

Contoh:

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());
        }
    }
}

Sebuah kata peringatan: tampaknya jika Anda mencoba menulis ke konsol sebelum melampirkan atau mengalokasikan konsol, pendekatan ini tidak berfungsi. Tebakan saya adalah pertama kalinya Anda memanggil Console.Write / WriteLine, jika belum ada konsol maka Windows secara otomatis membuat konsol tersembunyi di suatu tempat untuk Anda. (Jadi mungkin jawaban Anthony's ShowConsoleWindow lebih baik setelah Anda menulis ke konsol, dan jawaban saya lebih baik jika Anda belum menulis ke konsol). Yang penting untuk diperhatikan adalah ini tidak berhasil:

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



Apa yang berhasil bagi saya adalah menulis aplikasi konsol secara terpisah yang melakukan apa yang saya ingin lakukan, mengkompilasi ke exe, dan kemudian melakukan Process.Start("MyConsoleapp.exe","Arguments")


3
2017-09-18 18:47



Periksa kode sumber ini. Semua kode yang dikomentari - digunakan untuk membuat konsol di aplikasi Windows. Tanpa komentar - untuk menyembunyikan konsol di aplikasi konsol. Dari sini. (Sebelumnya sini.) Proyek 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



Sebenarnya AllocConsole dengan SetStdHandle dalam aplikasi GUI mungkin merupakan pendekatan yang lebih aman. Masalah dengan "pembajakan konsol" sudah disebutkan, adalah bahwa konsol mungkin tidak menjadi jendela latar depan sama sekali, (terutama mengingat masuknya jendela manajer baru di Vista / Windows 7) di antara hal-hal lain.


1
2018-03-02 20:01



Pada wind32, aplikasi konsol-mode adalah makhluk yang benar-benar berbeda dari aplikasi penerima pesan-antrian yang biasanya. Mereka dideklarasikan dan dikompilasi secara berbeda. Anda dapat membuat aplikasi yang memiliki bagian konsol dan jendela normal dan menyembunyikan satu atau yang lain. Tetapi curiga Anda akan menemukan semuanya sedikit lebih banyak dari yang Anda kira.


0
2018-01-23 08:50