이 글에서는 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);
}
결론
위 코드로 다른 콘솔 프로그램을 실행시키고 그 출력값을 문자열로 얻어 올 수 있습니다. 대단위 프로젝트라면 기능을 적당히 쪼개서 실행 파일로 만들고 그 출력값을 받아오도록 설계하는 방식도 좋은 방법일 수 있습니다.