2

그래픽 또는 순수 명령 줄 인터페이스를 모두 사용할 수있는 도구를 구축 중입니다. 명령 줄 옵션 "--command_line_only"로 결정하는 것은 사용자의 몫입니다. 내 IDE는 비주얼 스튜디오를하다 2008 년명령 줄 인터페이스로 그래픽 도구를 만들려면 어떻게해야합니까?

내가 할 수있는 권한 프로젝트 속성을 찾을 수 없습니다 확인

명령 줄 인터페이스 모드
  • 없는 명령 줄 상자를 사용하는 경우
  • 표준 출력 인쇄가 표시됩니다
      그래픽 모드에서 도구를 사용할 때 열림

    이렇게 할 수있는 방법이 있습니까? Visual Studio의 devenv는 이와 같이 작동하는 것처럼 보입니다. 따라서이 작업을 수행 할 수 있다고 확신합니다!

  • 답변

    1

    편집 : 제목에 대한 답변이있는 것 같습니다. 그러나 질문을 다시 읽으면서 귀하가 묻고있는 것이 확실하지 않습니다. 나는 당신의 제목을 검색하는 누군가에게 유용 할 수 있기 때문에 여기에 답을 남겨둔다.

    네, 이렇게 할 수는 있지만 일반적으로 시각적 인 연구는 코드를 GUI에서 분리하는 것을 아주 쉽게 만들어주지 않습니다 (특히 안녕하세요. 매우 바운드). 입력을 섞고 싶다면 처음부터 매우 잘 수행되고 있는지 확인하고 싶습니다.

    제 조언은 명령 줄 옵션으로 시작하는 것입니다. 부스트를 사용하도록 허용 된 경우 (이유를 설명하기 위해) boost::program_options을 사용하십시오.

    그런 다음 일단 GUI를 추가 할 수 있습니다. 또한, 크로스 플랫폼이기 때문에 gtk ++와 같은 GUI 라이브러리를 사용하는 것이 좋습니다.

    1

    응용 프로그램을 콘솔 응용 프로그램이 아닌 Win32 응용 프로그램으로 빌드하고 매개 변수를 검사하여 콘솔 창을 사용할지 여부를 결정하십시오.

    다음 코드는 based on this입니다.

    콘솔을 사용하려면; CConsoleAttacher라는 클래스를 만듭니다. 기본적으로 인수가있는 경우 다음과 같이 사용하십시오. 그런 다음 시작한 경우 CMD 창에 연결할 콘솔을 엽니 다. 물론이 앱 창을 만들기 전에 초기에 처리 할 필요가 있도록 콘솔에서 분리 메인 창 시작 Win32 응용 프로그램 (어쨌든 수행 할 작업 인을 ...)와

    CConsoleAttacher ca; 
        if (ca.hasArguments()) 
        { 
         ca.ConnectToConsole(); 
        } 
        printf ("Test output \n"); 
    

    클래스를 만듭니다 CConsoleAttacher라고합니다.

    CConsoleAttacher.cpp

    #include "StdAfx.h" 
    
    #include <windows.h> 
    #include <stdio.h> 
    #include <fcntl.h> 
    #include <io.h> 
    #include <iostream> 
    #include <fstream> 
    #include "ConsoleAttacher.h" 
    
    #ifndef _USE_OLD_IOSTREAMS 
    using namespace std; 
    #endif 
    static const WORD MAX_CONSOLE_LINES = 500; 
    
    CConsoleAttacher::CConsoleAttacher(void) 
    { 
        argv = CommandLineToArgvW(GetCommandLineW(), &argc); 
    
    } 
    
    
    CConsoleAttacher::~CConsoleAttacher(void) 
    { 
        LocalFree(argv); 
    } 
    
    
    int CConsoleAttacher::getArgumentCount(void) 
    { 
        return argc; 
    } 
    
    
    CString CConsoleAttacher::getArgument(int id) 
    { 
        CString arg ; 
        if (id < argc) 
        { 
         arg = argv[id]; 
        } 
        return arg; 
    } 
    
    bool CConsoleAttacher::hasArguments(void) 
    { 
        return argc > 1; 
    } 
    
    void CConsoleAttacher::ConnectToConsole(void) 
    { 
        int hConHandle; 
        HANDLE lStdHandle; 
        CONSOLE_SCREEN_BUFFER_INFO coninfo; 
        FILE *fp; 
    
        // allocate a console for this app 
        if (!AttachConsole(ATTACH_PARENT_PROCESS)) 
        { 
         if (!AllocConsole()) 
          return; 
        } 
    
        // set the screen buffer to be big enough to let us scroll text 
        GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&coninfo); 
        coninfo.dwSize.Y = MAX_CONSOLE_LINES; 
    
        SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),coninfo.dwSize); 
    
        // redirect unbuffered STDOUT to the console 
        lStdHandle = GetStdHandle(STD_OUTPUT_HANDLE); 
        hConHandle = _open_osfhandle((intptr_t)lStdHandle, _O_TEXT); 
        fp = _fdopen(hConHandle, "w"); 
    
        *stdout = *fp; 
        setvbuf(stdout, NULL, _IONBF, 0); 
    
        // redirect unbuffered STDIN to the console 
        lStdHandle = GetStdHandle(STD_INPUT_HANDLE); 
        hConHandle = _open_osfhandle((intptr_t)lStdHandle, _O_TEXT); 
        fp = _fdopen(hConHandle, "r"); 
    
        *stdin = *fp; 
        setvbuf(stdin, NULL, _IONBF, 0); 
    
        // redirect unbuffered STDERR to the console 
        lStdHandle = GetStdHandle(STD_ERROR_HANDLE); 
        hConHandle = _open_osfhandle((intptr_t)lStdHandle, _O_TEXT); 
        fp = _fdopen(hConHandle, "w"); 
    
        *stderr = *fp; 
        setvbuf(stderr, NULL, _IONBF, 0); 
    
        // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog 
        // point to console as well 
        ios::sync_with_stdio(); 
    } 
    

    CConsoleAttacher.h

    #pragma once 
    class CConsoleAttacher 
    { 
    private: 
        int argc; 
        wchar_t** argv; 
    
    public: 
        CConsoleAttacher(void); 
        ~CConsoleAttacher(void); 
        int getArgumentCount(void); 
        CString CConsoleAttacher::getArgument(int id); 
        void ConnectToConsole(void); 
        bool hasArguments(void); 
    }; 
    
    +0

    당신의 대답은 재미있는 것, 내가 을 포함해야했다 그러나 충분하지 않는 것 같습니다. _O_TEXT는 아직 정의되지 않았습니다. 어떤 파일을 포함시켜야합니까? –

    +0

    포함 할 올바른 파일을 찾았지만 작동하지 않습니다. cmd 상자에서 시작할 때, 새 상자를 생성하고 (아마 거기에 내용을 인쇄 한 다음) 닫습니다. –

    +0

    이것은 다소 이상하게 보입니다. 'HANDLE '은 8 바이트 너비 일 수 있지만 4 바이트 길이로 변환합니다. 확실합니까? –

    1

    이, IIRC을 할 수있는 쉬운 일이 아니다. 문제는 Windows에서 실행 파일 자체가 GUI 응용 프로그램이든 콘솔 응용 프로그램이든 플래그를 가지고 있다는 것입니다. cmd.exe은 둘 중 하나를 실행할 때 다르게 동작합니다. 응용 프로그램의 핵심 기능을 라이브러리로 분할하고 별도의 CLI 및 GUI 프론트 엔드를 구축하는 것이 좋습니다.

    EDIT : 정말로 주장한다면, 이것은 목표를 향해 먼 길을 간다.goto 그것이 지금 if로 대체 될 수있는 역사적 이유가있다 :

    static 
    bool 
    usable_handle (HANDLE h) 
    { 
        return h && h != INVALID_HANDLE_VALUE; 
    } 
    
    
    static 
    bool 
    try_reopen_std_handle (int dest_handle, DWORD os_handle_num, HANDLE os_handle, 
        int flags) 
    { 
        if (! usable_handle (os_handle)) 
         return false; 
    
        int ret = SetStdHandle (os_handle_num, os_handle); 
        assert (ret); 
        if (! ret) 
         return false; 
    
        int base_flags = 0; 
    #if defined (UNICODE) 
        //base_flags = _O_WTEXT; 
    #endif 
    
        int opened_handle = _open_osfhandle (reinterpret_cast<intptr_t>(os_handle), 
         flags | base_flags); 
        assert (opened_handle != -1 && "_open_osfhandle"); 
        if (opened_handle == -1) 
         return false; 
    
        int dupd_handle = _dup2 (opened_handle, dest_handle); 
        assert (dupd_handle != -1 && "_dup2"); 
    
        return dupd_handle == 0; 
    } 
    
    
    static 
    bool 
    try_fdopen (FILE * f, int handle, char const * mode) 
    { 
        FILE * tmp = _fdopen (handle, mode); 
        if (tmp && f) 
         *f = *tmp; 
        return !! tmp; 
    } 
    
    
    static 
    HANDLE 
    try_dup_os_handle (HANDLE src) 
    { 
        if (! usable_handle (src)) 
         return INVALID_HANDLE_VALUE; 
    
        HANDLE dest = INVALID_HANDLE_VALUE; 
        HANDLE const process = GetCurrentProcess(); 
        if (DuplicateHandle (process, src, process, &dest, 0, TRUE, 
         DUPLICATE_SAME_ACCESS)) 
         return dest; 
        else 
         return INVALID_HANDLE_VALUE; 
    } 
    
    
    static 
    void 
    init_std_io() 
    { 
        // Retrieve inherited standard handles. AttachConsole() will close 
        // the existing standard handles, so we duplicate them here first 
        // to keep them alive. 
    
        HANDLE os_stdin = try_dup_os_handle (GetStdHandle (STD_INPUT_HANDLE)); 
        HANDLE os_stdout = try_dup_os_handle (GetStdHandle (STD_OUTPUT_HANDLE)); 
        HANDLE os_stderr = try_dup_os_handle (GetStdHandle (STD_ERROR_HANDLE)); 
    
        // Attach existing console or allocate a new one. 
    
        int ret = AttachConsole (ATTACH_PARENT_PROCESS); 
        if (ret) 
         OutputDebugString (_T("Attached existing console.\n")); 
        else 
        { 
         ret = AllocConsole(); 
         if (ret) 
          OutputDebugString (_T("Allocated new console.\n")); 
         else 
          OutputDebugString (_T("Failed to allocate new console.\n")); 
         assert (ret); 
        } 
    
        // Open a "POSIX" handle for each OS handle and then fdopen() a C stream 
        // for each such "POSIX" handle. 
        // 
        // Only use the standard handle provided by AttachConsole() if the standard 
        // handle from before AttachConsole() is not usable. 
        // 
        // Finally, re-open standard C stream. 
    
        if (! usable_handle (os_stdin)) 
         os_stdin = GetStdHandle (STD_INPUT_HANDLE); 
        ret = try_reopen_std_handle (0, STD_INPUT_HANDLE, os_stdin, _O_RDONLY); 
        if (! ret) 
         goto do_stdout; 
        try_fdopen (stdin, 0, "r"); 
    
    do_stdout: 
        if (! usable_handle (os_stdout)) 
         os_stdout = GetStdHandle (STD_OUTPUT_HANDLE); 
        ret = try_reopen_std_handle (1, STD_OUTPUT_HANDLE, os_stdout, _O_WRONLY); 
        if (! ret) 
         goto do_stderr; 
        try_fdopen (stdout, 1, "w"); 
    
    do_stderr: 
        if (! usable_handle (os_stderr)) 
         os_stderr = GetStdHandle (STD_ERROR_HANDLE); 
        ret = try_reopen_std_handle (2, STD_ERROR_HANDLE, os_stderr, _O_WRONLY); 
        if (! ret) 
         goto done_stderr; 
        try_fdopen (stderr, 2, "w"); 
    
    done_stderr:; 
    } 
    
    +0

    내가해야만한다면 꽤 쉽게 할 수 있습니다. 나는 실행 파일의 두 가지 버전을 컴파일하기 만하면된다. 첫 번째는 플래그 콘솔이고, 두 번째 버전은 플래그 윈도우이다. 하지만 분명히 하나만 갖고 싶습니다. 그러므로 내 질문. –

    +0

    @ Benoît : IIRC, 문제는 GUI 실행 파일로 표시됩니다. cmd.exe는 반환되기를 기다리지 않습니다. – wilx

    관련 문제