사용자 도구

사이트 도구


kb:windowsconsoleapp

차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

kb:windowsconsoleapp [2014/11/09 21:05] (현재)
줄 1: 줄 1:
 +====== Windows Consone ======
 +콘솔 프로그램 관련 팁들
 +
 +====== Ctrl+C, Ctrl+Break, Close 버튼 막기 ======
 +SetConsoleCtrlHandler 함수를 통해 컨트롤 핸들러를 등록한 다음 무시하기 원하는 이벤트일 경우 TRUE를 반환하면 된다.
 +<code cpp>
 +BOOL WINAPI DisableConsoleWindowClose(DWORD event)
 +{
 +    BOOL handled = FALSE;
 +    ​
 +    switch (event)
 +    {
 +    case CTRL_C_EVENT:​ handled = TRUE; break;
 +    case CTRL_BREAK_EVENT:​ handled = TRUE; break;
 +    case CTRL_CLOSE_EVENT:​ handled = TRUE; break;
 +    default: break;
 +    }
 +    ​
 +    return handled;
 +}
 +
 +SetConsoleCtrlHandler(DisableConsoleWindowClose,​ TRUE);
 +</​code>​
 +세 이벤트를 모두 막아버릴 경우, 윈도우를 정상적으로 닫을 방법이 없어지기 때문에 유의. 강제 종료해야 한다.
 +
 +====== 콘솔창 입력 ======
 +GetNumberOfConsoleInputEvents 함수와 ReadConsoleInput 함수를 사용하면 간단히 처리할 수 있다. ReadConsoleInput 함수가 입력이 들어오기 전까지 블로킹되는 함수이기 때문에, GetNumberOfConsoleInputEvents 함수를 이용해 이미 들어와있는 입력이 있는지 체크해야 한다. ​
 +
 +커서 위치 처리가 좀 난감한데,​ [[http://​www.adrianxw.dk/​SoftwareSite/​index.html]] 페이지의 '​Working with Windows Consoles'​ 부분을 참고하기 바란다. 라이브러리 잘 만들어주면 예전 도스에서 콘솔 출력하듯이 UI를 구성할 수 있을 것 같기도 한데, 왠지 일이 너무 많을 것 같다.
 +
 +<code cpp>
 +void ReadConsoleInput()
 +{
 +    HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);​
 +    INPUT_RECORD inRecord = {0, };
 +    TCHAR readChar[2] = {0, };
 +    DWORD eventCount = 0;
 +    DWORD numRecordsRead = 0;
 +
 +    GetNumberOfConsoleInputEvents(hIn,​ &​eventCount);​
 +    while (eventCount > 0)
 +    {
 +        if (ReadConsoleInput(hIn,​ &​inRecord,​ 1, &​numRecordsRead) && numRecordsRead == 1)
 +        {
 +            if (inRecord.EventType == KEY_EVENT && inRecord.Event.KeyEvent.bKeyDown)
 +            {
 +                if (inRecord.Event.KeyEvent.wVirtualKeyCode != VK_RETURN)
 +                {
 +                    readChar[0] = inRecord.Event.KeyEvent.uChar.AsciiChar;​
 +                    std::cout << readChar << std::endl;
 +                }
 +                else
 +                {
 +                    std::cout << _T("​\r\n"​) << std::endl;
 +                }
 +            }
 +
 +            --eventCount;​
 +        }
 +        else
 +        {
 +            break;
 +        }
 +    }
 +}
 +
 +int main(int argc, TCHAR** argv)
 +{
 +    while (true)
 +    {
 +        ...do something else...
 +        ReadConsoleInput();​
 +    }
 +}
 +</​code>​
 +
 +====== 콘솔창 출력 ======
 +**콘솔창 열기**
 +<code cpp>
 +bool OpenConsole()
 +{
 +    if (!::​AllocConsole()) { return false; }
 +
 +    HANDLE hConsole = ::​GetStdHandle(STD_OUTPUT_HANDLE);​
 +    if (INVALID_HANDLE_VALUE == hConsole) ​
 +    {
 +        ::​FreeConsole();​
 +        return false;
 +    }
 +
 +    return true;
 +}
 +</​code> ​
 +
 +**콘솔창 닫기**
 +<code cpp>
 +void CloseConsole()
 +{
 +    ::​FreeConsole();​
 +    ::​CloseHandle(hConsole);​
 +    hConsole = INVALID_HANDLE_VALUE;​
 +}
 +</​code> ​
 +
 +**콘솔창에다 출력하기**
 +<code cpp>
 +void WriteConsole(const char* szMsg)
 +{
 +    DWORD dwBytes = 0;
 +    ::​WriteFile(m_hConsole,​ szMsg, ::​strlen(szMsg),​ &​dwBytes,​ NULL);
 +    ::​WriteFile(m_hConsole,​ "​\n",​ ::​strlen("​\n"​),​ &​dwBytes,​ NULL);
 +}
 +</​code> ​
 +
 +**STDOUT, STDIN, STDERR 리다이렉션**
 +<code cpp>
 +#include <​fcntl.h>​
 +#include <​io.h>​
 +#include <​iostream>​
 +#include <​fstream>​
 +
 +// STDOUT, STDIN, STDERR redirection
 +void RedirectStandardIo(HANDLE hConsole)
 +{
 +    long  StdHandle = 0;
 +    int   ​ConHandle = 0;
 +    FILE* fp        = NULL;
 +
 +    // STDOUT redirection
 +    StdHandle = PtrToLong(hConsole);​
 +    ConHandle = _open_osfhandle(StdHandle,​ _O_TEXT);
 +    fp = _fdopen(ConHandle,​ "​w"​);​
 +    *stdout = *fp;
 +    setvbuf(stdout,​ NULL, _IONBF, 0);
 +
 +    // STDIN redirection
 +    StdHandle = PtrToLong(::​GetStdHandle(STD_INPUT_HANDLE));​
 +    ConHandle = _open_osfhandle(StdHandle,​ _O_TEXT);
 +    fp = _fdopen(ConHandle,​ "​r"​);​
 +    *stdin = *fp;
 +    setvbuf(stdin,​ NULL, _IONBF, 0);
 +
 +    // STDERR redirection
 +    StdHandle = PtrToLong(::​GetStdHandle(STD_ERROR_HANDLE));​
 +    ConHandle = _open_osfhandle(StdHandle,​ _O_TEXT);
 +    fp = _fdopen( ConHandle, "​w"​ );
 +    *stderr = *fp;
 +    setvbuf(stderr,​ NULL, _IONBF, 0);
 +
 +    // cout, wcout, cin, wcin, wcerr, cerr, wclog, clog sync
 +    std::​ios::​sync_with_stdio();​
 +}
 +</​code>​
 +
 +**듀얼 모니터일때 옆모니터에 콘솔창 띄우기 by 쑥갓**
 +<code cpp>
 +#define _WIN32_WINNT 0x0500
 +
 +...
 +
 +bool bDualMonitor = GetSystemMetrics( SM_CMONITORS ) > 1;
 +if ( bDualMonitor == true )
 +{
 +    HWND hConsoleWindow = GetConsoleWindow();​
 +    const int screenWidth = GetSystemMetrics( SM_CXSCREEN );
 +
 +    RECT rect;
 +    GetWindowRect( hConsoleWindow,​ &rect );
 +
 +    // 아래의 +- 코드는 주모니터가 어느 쪽에 있느냐에 따라 변경해줘야한다.
 +    // 주모니터가 어느 쪽에 있는지 알아내는 방법이 있을 듯 한데...
 +    int windowX = rect.left;
 +    if( windowX > screenWidth )
 +    {
 +        windowX -= screenWidth;​ // 주모니터가 왼쪽에 있는 경우
 +        //windowX += screenWidth;​ // 주모니터가 오른쪽에 있는 경우
 +    }
 +    else
 +    {
 +        windowX += screenWidth;​ // 주모니터가 왼쪽에 있는 경우
 +        //windowX -= screenWidth;​ // 주모니터가 오른쪽에 있는 경우
 +    }
 +
 +    SetWindowPos( hConsoleWindow,​ NULL, windowX, rect.top, 0, 0, SWP_NOSIZE );
 +
 +    // 콘솔 윈도우를 최대화해주기 위해서는 위의 SetWindowPos 대신에 아래를 사용한다.
 +    //const int screenHeight = GetSystemMetrics( SM_CYSCREEN );
 +    //​SetWindowPos( hConsoleWindow,​ NULL, windowX, 0, screenWidth,​ screenHeight,​ 0 );
 +}
 +</​code>​
 +
 +====== 콘솔창을 띄우지 않은 상태에서 콘솔 프로그램을 실행하고,​ 그 결과를 파일에다 쓰기 ======
 +<code cpp>
 +void CTttDlg::​OnOK() ​
 +{
 +    // TODO: Add extra validation here
 +    PROCESS_INFORMATION pInfo;
 +    STARTUPINFO ​        ​sInfo;​
 +    DWORD               ​exitCode;​
 +    ​
 +    HANDLE hOut = CreateFile("​stdinout.txt", ​
 +        GENERIC_WRITE,​ NULL, NULL,
 +        CREATE_ALWAYS,​ FILE_ATTRIBUTE_NORMAL,​ NULL);
 +    ​
 +    sInfo.cb ​             = sizeof(STARTUPINFO);​
 +    sInfo.lpReserved ​     = NULL;
 +    sInfo.lpReserved2 ​    = NULL;
 +    sInfo.cbReserved2 ​    = 0;
 +    sInfo.lpDesktop ​      = NULL;
 +    sInfo.lpTitle ​        = NULL;
 +    sInfo.dwFlags ​        = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;​
 +    sInfo.dwX ​            = 0;
 +    sInfo.dwY ​            = 0;
 +    sInfo.dwFillAttribute = 0;
 +    sInfo.wShowWindow ​    = SW_HIDE;
 +    sInfo.hStdOutput ​     = hOut;
 +    ​
 +    if (!CreateProcess(NULL,​ "​command.com /c lha a tt",
 +        NULL, NULL, TRUE, 0, NULL, "​c:​\\",​ &sInfo, &​pInfo)) ​
 +    {
 +        printf("​ERROR:​ Cannot launch child process\n"​);​
 +        exit(1);
 +    }
 +    ​
 +    // Give the process time to execute and finish
 +    WaitForSingleObject(pInfo.hProcess,​ INFINITE);
 +    ​
 +    if (GetExitCodeProcess(pInfo.hProcess,​ &​exitCode)) ​
 +    {
 +        switch(exitCode) ​
 +        {
 +            case STILL_ACTIVE: ​
 +                printf("​Process is still active\n"​);​
 +                break;
 +    ​
 +            default:
 +                printf("​Exit code = %d\n", exitCode);
 +                break;
 +        }
 +    } 
 +    else 
 +    {
 +        printf("​GetExitCodeProcess() failed\n"​);​
 +    }
 +    ​
 +    CloseHandle(hOut);​
 +}
 +</​code>​
 +
 +위의 CreateProcess를 호출하는 부분에서 "​Command.com /c"를 호출하는 부분이 있는데 이렇게 해주지 않으면, 호출하는 프로그램이 DOS 프로그램인 경우 자동으로 창이 닫히지 않는 문제가 발생하기 때문.
 +
 +
 +====== 링크 ======
 +  * [[http://​www.codeproject.com/​win32/​console_event_handling.asp | Console Event Handling]]
 +  * [[http://​www.codeproject.com/​threads/​redir.asp | Redirecting An Arbitrary Console'​s Input/​Output]]
 +  * [[http://​dslweb.nwnexus.com/​~ast/​dload/​guicon.htm | Adding Console I/O to a Win32 GUI App]]
 +  * [[http://​support.microsoft.com/​default.aspx?​scid=http://​support.microsoft.com:​80/​support/​kb/​articles/​q190/​3/​51.asp&​NoWebContent=1 | HOWTO: Spawn Console Processes with Redirected Standard Handles]]
 +  * [[http://​www.adrianxw.dk/​SoftwareSite/​index.html]]
  
kb/windowsconsoleapp.txt · 마지막으로 수정됨: 2014/11/09 21:05 (바깥 편집)