양식 응용 프로그램에서 콘솔 출력 / 창을 표시하려면 어떻게합니까?


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"/ forms 출력을 가질 수 있지만 Windows 응용 프로그램에서 콘솔을 표시 할 수 있다는 것을 알고 있습니다.


2
이 둘의 차이점은 무엇입니까? 콘솔로 컴파일하고 양식을 보여주십시오.
— Doggett

7
@Doggett, simple-실제 응용 프로그램에서 사용하지 않더라도 학습하고 왜 / 어떻게하는지 이해하고 싶습니다 .... 현재 추가 명령을 제공하는 옵션을 생각하고 있습니다. VLC와 같은 출력, 그러나 TBH는 필요하지 않습니다. 다시 배우고 이해하고 싶습니다!
— Wil

: 나는이 자습서를 사용하여 수행 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
주요 문제 : 닫으면 모든 응용 프로그램이 닫힙니다.
— Mark

4
Windows 8 및 Windows 10에서 테스트했습니다.-AttachConsole은 cmd 상자에서 작동합니다.-AllocConsole은 Visual Studio에서 작동합니다. alloc이 필요한 경우 AttachConsole은 false를 반환합니다. 콘솔 모드에서 응용 프로그램을 종료하기 전에 FreeConsole ()을 호출해야합니다. 내 프로그램에서 Matthew Strawbridge의 코드 (아래 참조)를 AttachConsole () 줄을 다음과 같이 수정하여 사용했습니다. if (! AttachConsole (-1)) AllocConsole ();
— Berend Engelbrecht

이것은 사용자 컨트롤에서 작동합니까? Granados (예 :)를 사용하여 SSH 컨트롤을 winforms 구성 요소로 만들고 있는데 배경 구성 요소입니다. 구성 요소에서 콘솔을 표시하고 사용하기 위해 멋진 래퍼를 추가하고 싶습니다.
— Kraang Prime

2
이것은 좋지 않습니다. 명령 줄에서 실행할 때 별도의 콘솔 창이 열리고 명령 줄에서 실행 >하고 출력을 리디렉션 하는 데 사용하려고 할 때 별도의 콘솔 창이 생기고 파일에 출력이 없습니다.
— uglycoyote

139

아마도 이것은 지나치게 단순한 것입니다 ...

Windows Form 프로젝트 만들기 ...

그런 다음 프로젝트 특성-> 응용 프로그램-> 출력 유형-> 콘솔 응용 프로그램

그런 다음 콘솔과 양식을 함께 실행할 수 있습니다.


2
가장 간단하고 문제가 해결되었습니다.
— dadude999

2
이것은 확실히 최고의 솔루션입니다! 다른 사람들은 똑똑하지만 복잡합니다
— LM.Croisez

3
간단하고 잘 작동했습니다. 이것이 정답입니다.
— madu

7
기술적으로 이것은 포스터가 요구하는 것을 허용하는 데 사용될 수 있지만 훌륭한 솔루션은 아닙니다. 이렇게하면 GUI로 winforms 응용 프로그램을 시작하면 콘솔 창이 열립니다. 이 경우 Mike de Klerk의 답변과 같은 것이 더 필요합니다.
— 저스틴 그레이 울프

2
이것은 명령 줄에서 실행할 때 콘솔에 출력을 쓰거나으로 명령 줄에서 리디렉션 할 때 파일에 쓸 수있는 Winforms 앱을 얻을 수있는 유일한 솔루션입니다 >. 그러나 나는 "콘솔 응용 프로그램"으로 실행하는 방법을 설명하는 솔루션을 원했습니다. 아무도 이것이 어떻게 작동하는지 알고 있습니까?
— uglycoyote

63

콘솔 명령을 여는 것에 대해 걱정하지 않으면 프로젝트의 속성으로 이동하여 콘솔 응용 프로그램으로 변경할 수 있습니다

프로젝트 유형 변경 스크린 샷.

이것은 콘솔 창을 팝업 할뿐만 아니라 여전히 양식을 보여줍니다. 콘솔 창을 닫을 수는 없지만 디버깅을위한 훌륭한 임시 로거로 작동합니다.

프로그램을 배포하기 전에 다시 끄십시오.


1
좋은. 이렇게하면 양식 응용 프로그램에서 발생하는 문제가 해결되어 출력을 파일로 리디렉션하는 동안 콘솔 창으로 출력 할 수 있어야합니다. 그리고 콘솔을 수동으로 연결할 필요가 없습니다 ...
— Kai Hartmann

2
@JasonHarrison 콘솔 창을 닫으면 프로그램이 닫힙니다. 또한 프로그램이 실행되는 동안 항상 창이 열립니다.
— gunr2171

2
@ gun2171 : 감사합니다. 이 접근 방식의 단점은 답에 나와 있습니다. 응용 프로그램을 두 번 클릭하거나 시작 메뉴 등으로 시작하면 콘솔 창이 나타납니다.
— Jason Harrison

17

AttachConsolepinvoke를 사용하여 호출 하여 WinForms 프로젝트에 연결된 콘솔 창을 얻을 수 있습니다 . http://www.csharp411.com/console-output-from-winforms-application/

다른 구성으로 로그 출력을 구성하기 위해 Log4net ( http://logging.apache.org/log4net/index.html ) 을 고려할 수도 있습니다 .


+1-와우, 나는 콘솔 쇼를 기대하고 있었다! 생각보다 훨씬 더 복잡합니다! 더 나은 / 쉬운 답변이있는 경우를 대비하여 지금 당장 열어 두겠습니다.
— Wil

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에서 실패하는 경우를 제외하고는 훌륭하게 작동합니다. 실패하면 나는 다른 프롬프트와 여분의 프롬프트 (단지 인 경우)가 없다는 것을 의미합니다.
— Simon Heffer

또한 위의 Chaz의 답변을 시도했지만 Windows 7의 새로운 콘솔을 제공합니다 (8 또는 10은 아니지만). 명령 줄에서 리디렉션으로 실행하거나 인수가없는 경우 GUI로 실행하는 옵션이 필요합니다.
— Simon Heffer 2016 년

나는 이것을 시도했지만 작동하지 않았다. 그냥 AttachConsole(ATTACH_PARENT_PROCESS)콘솔 출력을 얻지 만 명령 줄에서 리디렉션하면 >작동하지 않습니다. 이 답변을 시도하면 콘솔이나 파일에서 출력을 얻을 수 없습니다.
— uglycoyote

12

기본적으로 여기서 발생할 수있는 두 가지가 있습니다.

콘솔 출력 winforms 프로그램이 자신을 생성 한 콘솔 창 (또는 다른 콘솔 창 또는 원하는 경우 새 콘솔 창)에 연결될 수 있습니다. 콘솔 창에 연결되면 Console.WriteLine () 등이 예상대로 작동합니다. 이 접근 방식의 한 가지 단점은 프로그램이 즉시 제어를 콘솔 창으로 리턴 한 다음 계속해서 작성하여 사용자가 콘솔 창에 입력 할 수 있다는 것입니다. / wait 매개 변수로 start를 사용하여이 문제를 처리 할 수 ​​있습니다.

명령 구문을 시작하기위한 링크

리디렉션 된 콘솔 출력 누군가가 프로그램의 출력을 다른 곳으로 파이프하는 경우입니다 (예 :

yourapp> file.txt

이 경우 콘솔 창에 부착하면 배관을 효과적으로 무시합니다. 이 작업을 수행하려면 Console.OpenStandardOutput ()을 호출하여 출력을 파이프해야하는 스트림에 대한 핸들을 얻을 수 있습니다. 이것은 출력이 파이프 된 경우에만 작동하므로 두 시나리오를 모두 처리하려면 표준 출력을 열고 출력하고 콘솔 창에 연결해야합니다. 이것은 출력이 콘솔 창과 파이프로 보내지지만 내가 찾을 수있는 최상의 솔루션이라는 것을 의미합니다. 이 작업을 수행하는 데 사용하는 코드 아래.

// 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를 구성하고 있는지 확인하십시오. 그렇지 않으면 신비한 Windows 유형 이유로 작동하지 않습니다. 호출을 캡슐화하는 Console.WriteLine것은 테스트를 수행하고 로그인하는 장소를 쉽게 변경할 수 있기 때문에 좋은 습관 이라고 주장합니다 (예를 들어 PaperTrail과 같은 클라우드 기반 로깅 서비스 또는 기타 )
— cedd

이것은 짝수없이 Win10에서 잘 작동했습니다.StreamWriter _stdOutWriter;
— TS

파이핑이 답이지만 파일 대신에 다음과 같이 MORE를 사용하십시오. yourapp | 더; stackoverflow.com/a/13010823/1845672
— Roland

9

Windows Forms 응용 프로그램을 만들고 출력 유형을 콘솔로 변경하십시오.

그것은 발생합니다 콘솔과 형태를 모두 엽니 다.

여기에 이미지 설명을 입력하십시오


이것이 바로 내가 찾는 것입니다. 간단하고 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
명령 프롬프트에서는 제대로 작동하지만 시작> 실행 또는 Visual Studio에서는 작동하지 않습니다. 모든 경우에 작동하게하려면 AttachConsole 행을 다음과 같이 바꾸십시오. if (! AttachConsole (-1)) AllocConsole (); AllocConsole ()이 호출되면 FreeConsole ()도 호출되어야합니다. 그렇지 않으면 프로그램이 종료 된 후 콘솔 호스트가 계속 실행됩니다.
— Berend Engelbrecht

2
initialiseOut 및 initialiseError는 사용되지 않으므로 의도 된 용도는 무엇입니까?
— Edwin

StandardHandle : uintx86과 x64에서 모두 작동하려면 IntPtr이어야합니다.
— Dmitry Gusarov

1

언제든지 응용 프로그램 유형간에 콘솔 또는 창으로 전환 할 수 있습니다. 따라서 stdout을보기위한 특수 논리를 작성하지 않습니다. 또한 디버거에서 응용 프로그램을 실행하면 모든 stdout이 출력 창에 표시됩니다. 중단 점을 추가하기 만하면 중단 점 속성에서 "히트시 ..."가 변경되면 모든 메시지와 변수를 출력 할 수 있습니다. 또한 "계속 실행"을 체크 / 체크 해제 할 수 있으며 중단 점이 사각형 모양이됩니다. 따라서 디버그 출력 창의 응용 프로그램에서 아무것도 변경하지 않고 중단 점 메시지가 표시됩니다.


0

그냥 Window Forms 앱으로 남겨두고 콘솔을 모방하는 간단한 양식을 만드십시오. 이 양식은 검은 색 콘솔처럼 보이게 만들 수 있으며 키 누르기에 직접 응답하도록 할 수 있습니다. 그런 다음 program.cs 파일에서 기본 양식을 실행해야하는지 ConsoleForm을 실행해야하는지 결정합니다. 예를 들어,이 접근법을 사용하여 program.cs 파일에서 명령 행 인수를 캡처합니다. ConsoleForm을 생성하고 처음에는 숨기고 명령 줄 문자열을 AddCommand 함수에 전달하면 허용되는 명령이 표시됩니다. 마지막으로 사용자가 -h 또는-? 명령, ConsoleForm에서 .Show를 호출하고 사용자가 키를 누르면 프로그램을 종료합니다. 사용자가-?를 제공하지 않으면 숨겨진 콘솔 폼을 닫고 기본 폼을 실행하십시오.


2
안녕하세요, StackOverflow에 오신 것을 환영합니다. 질문으로 답변을 게시하지 말고 의견 섹션을 사용하십시오.
— Pedro Rodrigues
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.