[Windows/C] CreateProcess, CreatePipe 함수로 CMD COMMAND 실행하고 결과읽기
Process A ---------------> Process B
(부모 프로세스) CreateProcess에 의한 생성 (자식 프로세스)
CreateProcess의 구조
Reference : http://msdn.microsoft.com/en-us/library/ms682425(VS.85).aspx
BOOL CreateProcess (
LPCTSTR lpApplicationName, // 생성될 프로세스의 이름
LPTSTR lpCommandLine, // 생성될 프로세스에 인자 전달(변수만 가능)
LPSECURITY_ATTRIBUTES lpProcessAttributes, // 프로세스의 보안 속성 지정
LPSECURITY_ATTRIBUTES lpThreadAttributes, // 쓰레드의 보안 속성 지정
BOOL bInheritHandles, // TRUE : 부모 프로세스가 소유하는 상속 가능한 핸들을 상속한다.
DWORD dwCreationFlags, // 생성하는 프로세스의 특성을 결정짓는 옵션(우선순위)
LPVOID lpEnvironment, // 생성하는 프로세스의 Environment Block 지정 NULL : 부모 프로세스의 환경 블록 복사
LPCTSTR lpCurrentDirectory, // 생성하는 프로세스의 현재 디렉터리 설정 NULL : 부모 프로세스의 현재 디렉터리
LPSTARTUPINFO lpStartupInfo, // STARTUPINFO 구조체 변수 초기화한 후 변수의 포인터를 인자로 전달
LPPROCESS_INFORMATION lpProcessInformation
// 생성하는 프로세스의 정보를 얻기 위한 인자
// PROCESS_INFORMATION 구조체 변수의 주소값을 인자로 전달);
STARTUPINFO의 구조
Reference : http://msdn.microsoft.com/en-us/library/ms686331(VS.85).aspx
typedef struct _STARTUPINFO {
DWORD cb; // 구조체 변수의 크기
LPTSTR lpReserved;
LPTSTR lpDesktop;
LPTSTR lpTitle; // 콘솔 윈도우의 타이틀 바 제목
DWORD dwX; // 프로세스 윈도우의 x좌표
DWORD dwY; // y 좌표
DWORD dwXSize; // 프로세스 윈도우의 가로길이
DWORD dwYSize; // 세로길이
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags; // 설정된 멤버의 정보
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
}; STARTUPINFO, *LPSTARTUPINFO;
- 첫번째 인자 cb가 중요한 이유는 CreateProcess함수의 9번째 들어갈 프로세스 정보 구조체에 들어가는 구조체가 혹시나 바뀔 수 있고, 다양한 구조체가 들어가기 위해서 둔 것인데 정보를 전달하는 구조체가 무엇인기 구분짓겠다는 의도로 해석.
- 현재 디렉터리(Current Directory)의 설정
현재 디렉터리 확인 함수(GetCurrentDirectory)
DWORD GetCurrentDirectory(
DWORD nBufferLength, // 현재 디렉터리 정보가 저장될 메모리 버퍼 크기
LPTSTR lpBuffer // 현재 디렉터리 정보가 저장될 메모리 버퍼의 pointer
);
BOOL SetCurrentDirectory(
LPCTSTR lpPathName // 변경하고자 하는 현재 디렉터리 경로명
1. 표준 검색경로 : 실행 중인 프로세스의 실행파일이 존재하는 디렉터리
2. 표준 검색경로 : 실행 중인 프로세스의 현재 디렉터리(Current Directory)
3. 표준 검색경로 : Windows의 시스템 디렉터리(System Directory)
4. 표준 검색경로 : Windows의 디렉터리(Windows Directory)
5. 표준 검색경로 : 환경변수 PATH에 의해 지정되어 있는 디렉터리
소스코드를 보시겠습니다.
#include <stdio.h>
#include <Windows.h>
#define COMMAND "C:\\Windows\\system32\\ping.exe"
int main(int argc, char *argv[])
{
char szBuff[256];
DWORD dwRead = 0, dwOut = 0, dwErr = 0;
HANDLE hStdOutWrite = NULL, hStdOutRead = NULL;
HANDLE hStdErrWrite = NULL, hStdErrRead = NULL;
STARTUPINFO si;
SECURITY_ATTRIBUTES sa;
PROCESS_INFORMATION pi;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
CreatePipe(&hStdOutRead, &hStdOutWrite, &sa, 0); // 실행될 콘솔 프로그램에 넘길 stdout
CreatePipe(&hStdErrRead, &hStdErrWrite, &sa, 0); // 실행될 콘솔 프로그램에 넘길 stderr
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.hStdOutput = hStdOutWrite;
si.hStdInput = NULL;
si.hStdError = hStdErrWrite;
si.wShowWindow = SW_HIDE; // 눈에 보이지 않는 상태로 프로세스 시작
CreateProcess(NULL, COMMAND, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
CloseHandle(pi.hThread);
while (PeekNamedPipe(hStdOutRead, NULL, 0, NULL, &dwOut, NULL) ||
PeekNamedPipe(hStdErrRead, NULL, 0, NULL, &dwErr, 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;
printf("%s", szBuff);
}
while (PeekNamedPipe(hStdErrRead, NULL, 0, NULL, &dwErr, NULL) && dwErr > 0)
{
ReadFile(hStdErrRead, szBuff, sizeof(szBuff), &dwRead, NULL);
szBuff[dwRead] = 0;
printf("%s", szBuff);
}
}
CloseHandle(pi.hProcess);
CloseHandle(hStdOutRead);
CloseHandle(hStdOutWrite);
CloseHandle(hStdErrRead);
CloseHandle(hStdErrWrite);
return 0;
}
부모프로세스(작성된 프로그램)와 생성된 child process사이에 파이프통신을 연결합니다.
이 파이프를 통하여 부모프로세스는 child process인 cmd.exe(ipconfig,ping등)를 내릴수 있게 됩니다.