ฉันจะแสดงเอาต์พุต / หน้าต่างคอนโซลในแอปพลิเคชันฟอร์มได้อย่างไร


131

หากต้องการติดอยู่ในทันทีตัวอย่างพื้นฐาน:

using System;
using System.Windows.Forms;

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

หากฉันรวบรวมสิ่งนี้ด้วยตัวเลือกเริ่มต้น (โดยใช้ csc ที่บรรทัดคำสั่ง) ตามที่คาดไว้มันจะคอมไพล์กับแอปพลิเคชันคอนโซล นอกจากนี้เนื่องจากฉันนำเข้าSystem.Windows.Formsมันจะแสดงกล่องข้อความด้วย

ตอนนี้ถ้าฉันใช้ตัวเลือก/target:winexeซึ่งฉันคิดว่าเหมือนกับการเลือกWindows Applicationจากตัวเลือกภายในโครงการตามที่คาดไว้ฉันจะเห็นเฉพาะกล่องข้อความและไม่มีเอาต์พุตคอนโซล

(ในความเป็นจริงเมื่อเปิดใช้งานจากบรรทัดคำสั่งฉันสามารถออกคำสั่งถัดไปก่อนที่แอปพลิเคชันจะเสร็จสมบูรณ์)

ดังนั้นคำถามของฉันคือ - ฉันรู้ว่าคุณสามารถมีเอาต์พุต "windows" / แบบฟอร์มจากแอปพลิเคชันคอนโซลได้ แต่จะมีการแสดงคอนโซลจากแอปพลิเคชัน Windows หรือไม่


2
สิ่งที่คุณเห็นว่าเป็นความแตกต่างระหว่างทั้งสอง? ทำไมไม่เพียงรวบรวมเป็นคอนโซลและแสดงแบบฟอร์ม
Doggett

7
@Doggett ง่าย ๆ - ฉันกำลังเรียนรู้และอยากเข้าใจว่าทำไม / ทำอย่างไรแม้ว่าฉันจะไม่ได้ใช้มันในแอปพลิเคชันจริงก็ตาม .... ในขณะนี้ฉันกำลังคิดถึงตัวเลือกที่ให้คำสั่งพิเศษ / เอาท์พุทเช่นใน VLC อย่างไรก็ตาม TBH ฉันไม่ต้องการ - อีกแล้วเพียงแค่เรียนรู้และต้องการที่จะเข้าใจมัน!
วิล

ฉันทำได้สำเร็จโดยใช้บทช่วยสอนนี้: saezndaree.wordpress.com/2009/03/29/…
vivanov

คำตอบ:


153

อันนี้น่าจะใช้ได้

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

8
น่ากลัวคำถามนี้ดูเหมือนจะถูกถามบ่อยมากนี่เป็นคำตอบที่แท้จริงเพียงข้อเดียวสำหรับคำถามที่ฉันหาได้ +1
RobJohnson

5
ปัญหาหลัก: เมื่อคุณปิดแอปพลิเคชันทั้งหมดจะปิดลง
ทำเครื่องหมาย

4
ฉันทดสอบบน Windows 8 และ Windows 10: - AttachConsole ทำงานจากกล่อง cmd - AllocConsole ทำงานจาก Visual Studio เมื่อจำเป็นต้องจัดสรร AttachConsole จะส่งกลับเท็จ คุณควรเรียก FreeConsole () ก่อนที่จะยุติแอปพลิเคชันในโหมดคอนโซล ในโปรแกรมของฉันฉันใช้รหัสของ Matthew Strawbridge (ดูด้านล่าง) โดยมีการแก้ไขบรรทัด AttachConsole () เป็น: if (! AttachConsole (-1)) AllocConsole ();
Berend Engelbrecht

สิ่งนี้จะทำงานในการควบคุมของผู้ใช้หรือไม่ ฉันกำลังดำเนินการสร้างการควบคุม SSH เป็นส่วนประกอบ winforms โดยใช้ Granados (เป็นต้น) และเป็นส่วนประกอบพื้นหลังเท่านั้น ฉันต้องการเพิ่มกระดาษห่อหุ้มที่ดีเพื่อแสดงและใช้คอนโซลในส่วนประกอบด้วย
Kraang Prime

2
สิ่งนี้ไม่ดีนักเมื่อเรียกใช้จากบรรทัดคำสั่งมันจะเปิดหน้าต่างคอนโซลแยกต่างหากและเมื่อเรียกใช้จากบรรทัดคำสั่งและพยายามใช้>เพื่อเปลี่ยนเส้นทางผลลัพธ์ฉันได้รับหน้าต่างคอนโซลแยกต่างหากและเอาต์พุตเป็นศูนย์ในไฟล์ของฉัน
uglycoyote

140

บางทีนี่อาจจะง่ายเกินไป ...

สร้างโครงการ Windows Form ...

จากนั้น: คุณสมบัติโครงการ -> แอปพลิเคชัน -> ประเภทเอาต์พุต -> แอปพลิเคชันคอนโซล

จากนั้นสามารถให้ Console และ Forms ทำงานร่วมกันได้สำหรับฉัน


2
ดูเหมือนง่ายที่สุดแก้ไขปัญหาของฉันด้วย
dadude999

2
นี่คือทางออกที่ดีที่สุดแน่นอน! คนอื่นฉลาด แต่ก็ซับซ้อน
LM.Croisez

3
เรียบง่ายและใช้งานได้ดี นี่ควรเป็นคำตอบที่ได้รับการยอมรับ
madu

7
ในขณะที่ใช่ในทางเทคนิคแล้วสิ่งนี้สามารถใช้เพื่ออนุญาตสิ่งที่ผู้โพสต์ขอ - ไม่ใช่วิธีแก้ปัญหาที่ดี เมื่อทำเช่นนี้หากคุณเริ่มแอปพลิเคชัน winforms ด้วย GUI คุณจะเปิดหน้าต่างคอนโซลขึ้นมา ในกรณีนี้คุณต้องการอะไรเพิ่มเติมเช่นคำตอบของ Mike de Klerk
Justin Greywolf

2
นี่เป็นทางออกเดียวที่ฉันสามารถรับแอป Winforms ของฉันเพื่อเขียนผลลัพธ์ไปยังคอนโซลเมื่อเรียกใช้จากบรรทัดคำสั่งหรือเขียนลงไฟล์เมื่อเปลี่ยนเส้นทางในบรรทัดคำสั่งด้วย>. อย่างไรก็ตามฉันหวังว่าจะได้วิธีแก้ปัญหาที่จะอธิบายวิธีเรียกใช้เป็น "แอปพลิเคชันคอนโซล" เพียงบางครั้งเท่านั้น (เช่นการเปิดใช้งานทางโปรแกรมทุกอย่างที่เปลี่ยนแปลงการตั้งค่า Visual Studio ลึกลับนี้) ไม่มีใครรู้ว่ามันทำงานอย่างไรภายใต้ประทุน?
uglycoyote

63

หากคุณไม่กังวลเกี่ยวกับการเปิดคอนโซลบนคำสั่งคุณสามารถเข้าไปในคุณสมบัติสำหรับโครงการของคุณและเปลี่ยนเป็นแอปพลิเคชันคอนโซล

ภาพหน้าจอของการเปลี่ยนประเภทโครงการ.

จะยังคงแสดงแบบฟอร์มของคุณเช่นเดียวกับการเปิดหน้าต่างคอนโซล คุณไม่สามารถปิดหน้าต่างคอนโซลได้ แต่ทำงานเป็นตัวบันทึกชั่วคราวที่ยอดเยี่ยมสำหรับการดีบัก

อย่าลืมปิดกลับก่อนที่คุณจะปรับใช้โปรแกรม


1
ดี สิ่งนี้ช่วยแก้ปัญหาที่ฉันมีกับแอปพลิเคชันแบบฟอร์มของฉันที่ฉันต้องสามารถส่งออกไปยังหน้าต่างคอนโซลได้ในขณะที่รองรับการเปลี่ยนเส้นทางผลลัพธ์ไปยังไฟล์ และฉันไม่จำเป็นต้องติดคอนโซลใด ๆ ด้วยตนเอง ...
Kai Hartmann

2
@JasonHarrison ถ้าคุณปิดหน้าต่างคอนโซลโปรแกรมจะปิด นอกจากนี้หน้าต่างยังเปิดอยู่เสมอในขณะที่โปรแกรมทำงาน
gunr2171

2
@ gun2171: ขอบคุณ ข้อเสียของแนวทางนี้ระบุไว้ในคำตอบ: หน้าต่างคอนโซลจะปรากฏขึ้นหากเปิดแอปพลิเคชันด้วยการดับเบิลคลิกเมนูเริ่ม ฯลฯ
Jason Harrison

17

คุณสามารถเรียกAttachConsoleใช้ pinvoke เพื่อรับหน้าต่างคอนโซลที่แนบมากับโครงการ WinForms: http://www.csharp411.com/console-output-from-winforms-application/

คุณอาจต้องการพิจารณา Log4net ( http://logging.apache.org/log4net/index.html ) สำหรับการกำหนดค่าเอาต์พุตบันทึกในการกำหนดค่าต่างๆ


+1 - ว้าวฉันหวังว่าจะได้คอนโซลแสดงหรือคล้ายกัน! ซับซ้อนกว่าที่คิดเยอะ! ฉันจะเปิดทิ้งไว้สักครู่เผื่อว่าจะมีคำตอบที่ดีกว่า / ง่ายกว่านี้
วิล

สิ่งนี้ใช้ได้ผลสำหรับฉัน AllocConsole () ไม่ได้เป็นเพราะมันสร้างหน้าต่างคอนโซลใหม่ (ไม่ได้เจาะลึกลงไปใน AllocConsole บางทีฉันอาจพลาดอะไรบางอย่างที่นั่น)
derFunk

14

สิ่งนี้ใช้ได้ผลสำหรับฉันเพื่อไพพ์เอาต์พุตไปยังไฟล์ เรียกคอนโซลด้วย

cmd / c "C: \ path \ to \ your \ application.exe"> myfile.txt

เพิ่มรหัสนี้ในแอปพลิเคชันของคุณ

    [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"))
            {
#if DEBUG
                String typeOfBuild = "d";
#else
                String 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;
            }
        }
    }

ฉันพบรหัสนี้ที่นี่: http://www.csharp411.com/console-output-from-winforms-application/ ฉันคิดว่ามีค่าพอที่จะโพสต์ไว้ที่นี่เช่นกัน


5
สิ่งนี้ใช้งานได้ดียกเว้นตอนนี้ล้มเหลวใน Windows 8 และ Windows 10 โดยล้มเหลวฉันหมายความว่าไม่มีเอาต์พุตยกเว้นและพรอมต์พิเศษ (หากนั่นเป็นเบาะแส) มีคนแนะนำ AllocConsole แต่เพิ่งกระพริบหน้าต่าง cmd
Simon Heffer

ลองใช้คำตอบของ Chaz ข้างต้นด้วย แต่นั่นให้คอนโซลใหม่ใน Windows 7 (ไม่ได้อยู่ใน 8 หรือ 10) ฉันแค่ต้องการตัวเลือกเพื่อเรียกใช้ด้วยการเปลี่ยนเส้นทางบนบรรทัดคำสั่งหรือเรียกใช้เป็น gui หากไม่มี args
Simon Heffer

ฉันลองสิ่งนี้ แต่ไม่ได้ผล เมื่อAttachConsole(ATTACH_PARENT_PROCESS)ฉันได้รับเอาต์พุตคอนโซล แต่เปลี่ยนเส้นทางไปยังบรรทัดคำสั่งด้วย>ไม่ทำงาน เมื่อฉันลองใช้คำตอบนี้ฉันไม่สามารถรับเอาต์พุตใด ๆ ไม่ว่าจะในคอนโซลหรือในไฟล์
uglycoyote

12

โดยพื้นฐานแล้วมีสองสิ่งที่สามารถเกิดขึ้นได้ที่นี่

เอาต์พุตคอนโซลเป็นไปได้ที่โปรแกรม winforms จะแนบตัวเองเข้ากับหน้าต่างคอนโซลที่สร้างขึ้น (หรือกับหน้าต่างคอนโซลอื่นหรือไปที่หน้าต่างคอนโซลใหม่หากต้องการ) เมื่อติดกับหน้าต่างคอนโซล Console.WriteLine () etc ทำงานตามที่คาดไว้ สิ่งหนึ่งที่เข้าใจในแนวทางนี้คือโปรแกรมจะส่งคืนการควบคุมไปยังหน้าต่างคอนโซลทันทีจากนั้นจึงดำเนินการเขียนต่อไปดังนั้นผู้ใช้จึงสามารถพิมพ์ได้ในหน้าต่างคอนโซล คุณสามารถใช้ start ด้วยพารามิเตอร์ / wait เพื่อจัดการกับสิ่งนี้ที่ฉันคิด

ลิงก์เพื่อเริ่มไวยากรณ์คำสั่ง

เอาต์พุตคอนโซลที่เปลี่ยนเส้นทางนี่คือเมื่อมีคนไปส่งเอาต์พุตจากโปรแกรมของคุณที่อื่นเช่น

yourapp> file.txt

การแนบหน้าต่างคอนโซลในกรณีนี้จะละเว้นการวางท่ออย่างมีประสิทธิภาพ ในการทำงานนี้คุณสามารถเรียก Console.OpenStandardOutput () เพื่อจัดการกับสตรีมที่เอาต์พุตควรถูกส่งไป สิ่งนี้ใช้ได้เฉพาะเมื่อเอาต์พุตถูก piped ดังนั้นหากคุณต้องการจัดการทั้งสองสถานการณ์คุณต้องเปิดเอาต์พุตมาตรฐานแล้วเขียนและแนบไปกับหน้าต่างคอนโซล นี่หมายความว่าเอาต์พุตถูกส่งไปยังหน้าต่างคอนโซลและไปยังไพพ์ แต่เป็นทางออกที่ดีที่สุดที่ฉันสามารถหาได้ ด้านล่างรหัสที่ฉันใช้ทำสิ่งนี้

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

ฉันไม่สามารถเขียนลงคอนโซลได้ การแนบกระบวนการหลักก่อนอื่นเป็นการหลอกลวง ขอบคุณ.
Pupper

ดูเหมือนว่าคำตอบนี้ต้องการให้คุณเขียนการโทรทั้งหมดConsole.WriteLineเพื่อเรียกใหม่ที่WriteLineกำหนดไว้ข้างต้นแทน แม้ว่าฉันจะพยายาม แต่ไม่สามารถใช้รหัสนี้เพื่อรับสิ่งที่เปลี่ยนเส้นทางไปยังไฟล์เมื่อเรียกใช้แอปพลิเคชันบนบรรทัดคำสั่งและเปลี่ยนเส้นทาง>ไปยังไฟล์
uglycoyote

@uglycoyote ตรวจสอบให้แน่ใจว่าคุณได้สร้าง GUIConsoleWriter โดยเร็วที่สุดในแอปพลิเคชันของคุณมิฉะนั้นจะไม่ทำงานด้วยเหตุผลประเภทหน้าต่างลึกลับ ฉันขอยืนยันว่าการสรุปการโทรConsole.WriteLineเป็นเพียงแนวทางปฏิบัติที่ดีเนื่องจากช่วยให้คุณสามารถทดสอบและเปลี่ยนสถานที่ที่คุณเข้าสู่ระบบได้อย่างง่ายดาย (ตัวอย่างเช่นคุณอาจต้องการเริ่มบันทึกไปยังบริการบันทึกบนคลาวด์เช่น PaperTrail หรืออะไรก็ตาม )
cedd

สิ่งนี้ใช้ได้ดีสำหรับฉันใน Win10 โดยไม่ต้องแม้แต่StreamWriter _stdOutWriter;
TS

Piping คือคำตอบ แต่แทนที่จะเป็นไฟล์ให้ใช้ MORE เช่น yourapp | มากกว่า ; โปรดดูที่stackoverflow.com/a/13010823/1845672
Roland

9

สร้าง Windows Forms Application และเปลี่ยนประเภทผลลัพธ์เป็น Console

มันจะส่งผลให้ทั้งคอนโซลและแบบฟอร์มเปิด

ป้อนคำอธิบายภาพที่นี่


นี่คือสิ่งที่ฉันกำลังมองหา ง่ายและไม่ใช้ WINAPI
Michael Coxon

ฉันได้ลองหลายตัวอย่าง แต่ไม่มีตัวอย่างใดที่ให้ผลลัพธ์ที่ตรงตามความคาดหวังของฉัน อย่างไรก็ตามวิธีนี้เป็นสิ่งที่ฉันต้องการและเป็นวิธีที่ง่ายที่สุด
inexcitus

4
//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;
        }
    }
}

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

1
ทำงานได้ดีจากพรอมต์คำสั่ง แต่ไม่ใช่จาก Start> Run หรือใน Visual Studio เพื่อให้ใช้งานได้ในทุกกรณีให้แทนที่ AttachConsole บรรทัดโดย: if (! AttachConsole (-1)) AllocConsole (); ถ้าเรียก AllocConsole () ก็ควรเรียก FreeConsole () ด้วยมิฉะนั้นโฮสต์คอนโซลจะยังคงทำงานต่อไปหลังจากยุติโปรแกรม
Berend Engelbrecht

2
วัตถุประสงค์การใช้ initialiseOut และ initialiseError คืออะไรเนื่องจากไม่ได้ใช้
Edwin

StandardHandle : uintผิดที่นี่ ... ควรเป็น IntPtr เพื่อทำงานทั้งบน x86 และ x64
Dmitry Gusarov

1

คุณสามารถสลับระหว่างประเภทของแอปพลิเคชันคอนโซลหรือหน้าต่างได้ตลอดเวลา ดังนั้นคุณจะไม่เขียนตรรกะพิเศษเพื่อดู stdout นอกจากนี้เมื่อเรียกใช้แอปพลิเคชันในดีบักเกอร์คุณจะเห็น stdout ทั้งหมดในหน้าต่างเอาต์พุต คุณอาจเพิ่มเบรกพอยต์และในคุณสมบัติเบรกพอยต์เปลี่ยน "เมื่อ Hit ... " คุณสามารถแสดงข้อความและตัวแปรใด ๆ นอกจากนี้คุณสามารถเลือก / ยกเลิกการเลือก "ดำเนินการต่อ" และเบรกพอยต์ของคุณจะกลายเป็นรูปสี่เหลี่ยมจัตุรัส ดังนั้นข้อความเบรกพอยต์โดยไม่เปลี่ยนแปลงอะไรในแอปพลิเคชันในหน้าต่างเอาต์พุตการดีบัก


0

ทำไมไม่ปล่อยให้เป็นแอป Window Forms แล้วสร้างแบบฟอร์มง่ายๆเพื่อเลียนแบบคอนโซล แบบฟอร์มสามารถทำให้ดูเหมือนคอนโซลหน้าจอสีดำและให้มันตอบสนองโดยตรงกับการกดปุ่ม จากนั้นในไฟล์ program.cs คุณจะตัดสินใจว่าคุณต้องเรียกใช้ฟอร์มหลักหรือ ConsoleForm ตัวอย่างเช่นฉันใช้วิธีนี้เพื่อจับอาร์กิวเมนต์บรรทัดคำสั่งในไฟล์ program.cs ฉันสร้าง ConsoleForm ในขั้นต้นซ่อนมันจากนั้นส่งสตริงบรรทัดคำสั่งไปยังฟังก์ชัน AddCommand ในนั้นซึ่งจะแสดงคำสั่งที่อนุญาต สุดท้ายหากผู้ใช้ให้ -h หรือ -? ฉันเรียกว่า. แสดงบน ConsoleForm และเมื่อผู้ใช้กดปุ่มใด ๆ บนนั้นฉันจะปิดโปรแกรม หากผู้ใช้ไม่ให้ -? คำสั่งฉันปิด ConsoleForm ที่ซ่อนอยู่และเรียกใช้แบบฟอร์มหลัก


2
สวัสดีและยินดีต้อนรับสู่ StackOverflow หลีกเลี่ยงการโพสต์คำถามเป็นคำตอบใช้ส่วนความคิดเห็น
Pedro Rodrigues
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.