MFC 다른 콘솔 프로그램 출력값 가져오기: 간편 가이드

이 글에서는 MFC 를 이용하여 다른 콘솔 프로그램 출력값을 획득하는 과정에 대해 설명합니다.
기본적으로 MFC 에서 다른 콘솔프로그램을 실행하고 프로그램이 닫히기그 출력값을

순서

1. 파이프 생성

MFC에서는 CreatePipe 함수를 사용하여 프로세스 간 통신을 위한 파이프를 생성합니다. 이 파이프는 데이터를 주고받을 수 있는 통로 역할을 합니다.

2. 프로세스 실행

CreateProcess 함수를 활용하여 다른 콘솔 프로그램을 실행합니다. 실행할 프로그램의 경로를 지정하고, 필요한 경우 인자를 전달할 수 있습니다.
이 함수는 다른 프로그램을 실행하고, 새로운 프로세스의 주소 공간을 만들며, 새로운 프로세스에 대한 핸들을 반환합니다.

BOOL CreateProcess(
  LPCTSTR               lpApplicationName,
  LPTSTR                lpCommandLine,
  LPSECURITY_ATTRIBUTES lpProcessAttributes,
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  BOOL                  bInheritHandles,
  DWORD                 dwCreationFlags,
  LPVOID                lpEnvironment,
  LPCTSTR               lpCurrentDirectory,
  LPSTARTUPINFO         lpStartupInfo,
  LPPROCESS_INFORMATION lpProcessInformation
);
  • lpApplicationName: 실행할 응용 프로그램의 이름입니다.
  • lpCommandLine: 응용 프로그램에 전달할 명령줄 인수입니다.
  • lpProcessAttributes: 프로세스 보안 특성입니다.
  • lpThreadAttributes: 스레드 보안 특성입니다.
  • bInheritHandles: 부모 프로세스의 핸들을 새로운 프로세스에 상속할지 여부를 지정합니다.
  • dwCreationFlags: 프로세스의 생성 옵션을 지정합니다.
  • lpEnvironment: 새로운 프로세스에 전달할 환경 변수입니다.
  • lpCurrentDirectory: 새로운 프로세스의 현재 작업 디렉터리입니다.
  • lpStartupInfo: STARTUPINFO 구조체에 대한 포인터로, 새로운 프로세스의 메인 윈도우를 설정하는 데 사용됩니다.
  • lpProcessInformation: PROCESS_INFORMATION 구조체에 대한 포인터로, 새로운 프로세스 및 스레드의 정보를 반환합니다.

3. 파이프 핸들 설정

CreatePipe 생성된 파이프의 핸들을 표준 출력(STDOUT)으로 설정합니다. 이를 통해 실행된 프로세스의 출력이 파이프를 통해 전달될 수 있습니다.

4. 출력값 읽기

ReadFile 함수를 사용하여 파이프로부터 출력값을 읽어옵니다. 이를 통해 실행된 프로세스의 출력을 캡처할 수 있습니다.

예제

예제 1

위 과정을 구현한 예제 코드는 다음과 같습니다.

#include <iostream>
#include <Windows.h>

int main() {
    HANDLE hReadPipe, hWritePipe;
    SECURITY_ATTRIBUTES saAttr;
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    // 파이프 생성
    ZeroMemory(&saAttr, sizeof(SECURITY_ATTRIBUTES));
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;
    CreatePipe(&hReadPipe, &hWritePipe, &saAttr, 0);

    // 표준 출력을 파이프로 설정
    GetStartupInfo(&si);
    si.hStdOutput = hWritePipe;
    si.dwFlags |= STARTF_USESTDHANDLES;

    // 프로세스 실행
    CreateProcess(NULL, "your_console_program.exe", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);

    // 파이프로부터 출력값 읽기
    char buffer[1024];
    DWORD bytesRead;
    ReadFile(hReadPipe, buffer, sizeof(buffer), &bytesRead, NULL);
    buffer[bytesRead] = '\0';

    // 출력값 출력
    std::cout << "다른 콘솔 프로그램의 출력값: " << buffer << std::endl;

    // 핸들 닫기
    CloseHandle(hReadPipe);
    CloseHandle(hWritePipe);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    return 0;
}

이 예제 코드를 통해 MFC를 사용하여 다른 콘솔 프로그램의 출력값을 쉽게 가져올 수 있습니다. 필요한 콘솔 프로그램의 실행 파일명을 "your_console_program.exe" 부분에 넣어주시면 됩니다.

예제 2

다음 예제는 다른 콘솔 프로그램을 숨겨서 실행시키고 출력값을 받아옵니다.

void RunShellCommand(CString process_path, char *output)
{
    char szBuff[4096];
    DWORD dwRead = 0, dwOut = 0, dwErr = 0;
    HANDLE hStdOutWrite = NULL, hStdOutRead = NULL;

    STARTUPINFO si;
    SECURITY_ATTRIBUTES sa;
    PROCESS_INFORMATION pi;
    CString m_csOutput, csTemp;

    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;

    CreatePipe(&hStdOutRead, &hStdOutWrite, &sa, 0);  
    /* 실행될 콘솔 프로그램에 넘길 stdout */

    SetHandleInformation(hStdOutRead, HANDLE_FLAG_INHERIT, 0);

    ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    si.hStdOutput = hStdOutWrite;
    si.hStdInput = NULL;
    si.hStdError = NULL;
    si.wShowWindow = SW_HIDE;       /* 눈에 보이지 않는 상태로 프로세스 시작 */

    BOOL bsuccess = CreateProcess(NULL, (LPSTR)(LPCTSTR)process_path, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);

    if(bsuccess)
    {
        while (PeekNamedPipe(hStdOutRead, NULL, 0, NULL, &dwOut, NULL) )
        {
            if (dwOut <= 0 && dwErr <= 0 && WaitForSingleObject(pi.hProcess, 0) != WAIT_TIMEOUT)
                break;  /* 실행되어진 콘솔 응용프로그램이 종료된 경우 */

            while (PeekNamedPipe(hStdOutRead, NULL, 0, NULL, &dwOut, NULL) && dwOut > 0)
            {
                ReadFile(hStdOutRead, szBuff, sizeof(szBuff), &dwRead, NULL);
                szBuff[dwRead] = 0;
                m_csOutput += szBuff;
            }
        }

        if (output != NULL)
        {
            sprintf(output, "%s", (LPCTSTR)m_csOutput);
        }

    }
    CloseHandle(hStdOutRead);
    CloseHandle(hStdOutWrite);
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
}

결론

위 코드로 다른 콘솔 프로그램을 실행시키고 그 출력값을 문자열로 얻어 올 수 있습니다. 대단위 프로젝트라면 기능을 적당히 쪼개서 실행 파일로 만들고 그 출력값을 받아오도록 설계하는 방식도 좋은 방법일 수 있습니다.

Leave a Comment