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


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.