본문 바로가기
Program

[Program] (윈도우 시스템 프로그래밍) 프로세스 생성 (with CreateProcess function)

by snwo 2021. 1. 17.

프로세스 생성

windows.h 헤더파일 에서의 CreateProcess 함수로 자식 프로세스를 생성할 수 있다. 프로세스를 생성할 때는 이렇게 CreateProcess 같은 함수로 프로그래밍을 통한 생성방법이 있고, 흔히 바탕화면에서 실행파일을 실행시킴으로서 프로세스를 생성시킬 수도 있다.


Process Explorer 에서 실행중인 프로세스들을 확인한 결과이다. 카톡 실행파일을 실행시킬 때, winlogon.exe 라는 부모프로세스에서 생성된** explorer.exe 라는 자식프로세스가 또 **kakaotalk.exe 라는 자식프로세스를 생성하게 된다.

CreateProcess function

BOOL CreateProcess( 
    LPCSTR     lpApplicationName, 
    LPSTR     lpCommandLine,
    //LPSECURITY_ATTRIBUTES lpProcessAttributes,
    //LPSECURITY_ATTRIBUTES     lpThreadAttributes,
    //BOOL     bInheritHandles,
    DWORD     dwCreationFlags,
    //LPVOID     lpEnvironment,
    //LPCSTR     lpCurrentDirectory,
    LPSTARTUPINFOA lpStartupInfo,
    LPPROCESS_INFORMATION     lpProcessInformation
);

CreateProcess 함수에 대해 간단히 알아보자! 이 함수로 인해 생성되는 프로세스는 자식 프로세스 이고, 생성하는 프로세스는 부모 프로세스 이다.
함수 인자가 많은데, 주석을 치지 않은 부분만 보도록 하자. LPSTARTUPINFO 구조체에 프로세스에 관한 정보들을 저장해 전달하면, lpProcessInformation 에 정보가 반환된다!

LPSTARTUPINFO

typedef  struct _STARTUPINFO { 
    DWORD cb;    //구조체 크기
    LPSTR lpReserved; 
    LPSTR lpDesktop; 
    LPSTR 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;

구조체는 이렇게 생겼다. 중요한 변수는 주석이 달린 변수이다. 첫번째 멤버를 보면 구조체의 크기를 담는 변수인데, 이는 CreateFunction의 9번째 인자 LPSTARTUPINFO 에 다른 구조체도 올 수 있게 확장성을 고려해 만든것이다. 구조체변수의 크기로 다른 구조체를 구별할 수 있게된다.

전체 멤버를 0으로 초기화해도 생성은 되겠지만, 콘솔창이 보이지 않으니 창크기, 위치, 타이틀 정도는 설정하는게 좋을 것같다.

LPPROCESS_INFORMATION

typedef struct _PROCESS_INFORMATION
{
    HANDLE hProcess;    //프로세스 핸들
    HANDLE hThread;        //쓰레드 핸들
    DWORD dwProcessId;    //프로세스 ID
    DWORD dwThreadId;    //쓰레드 ID
}

CreateProcess 함수를 실행시키고 난 뒤, 정보가 입력되는 구조체이다. (마지막인자 lpProcessInformation) 주석친 것들이 반환된다고 한다.
선하나 그어줭!

표준 검색경로

1. 실행중인 프로세스의 실행파일이 존재하는 디렉터리
2. 실행중인 프로세스의 현재 디렉터리
3. Windows의 시스템 디렉터리
4. Windows 디렉터리
5. 환경변수 PATH에 있는 디렉터리

다시 CreateProcess 함수로 돌아와서,

    LPCSTR     lpApplicationName, 
    LPSTR     lpCommandLine,

이 부분을 보자. 주로 CreateProcess(NULL,"a.exe 10 20", ... ); 이런식으로 호출하는데,

첫번째 인자를 NULL 으로 주고 두번째 인자에 프로그램명과 argv 를 써서 실행시킨다. 이때 프로그램명은 위에 말했던 표준 검색경로에서 찾게된다.

 

잘 안쓰이지만 다른 방법도 있다. CreateProcess("C:\\Windows\\System32\\cmd.exe","/c echo helloworld", ... 첫번째에 프로그램경로를, 두번째에 인자를 주는 것이다.

python -c 'print("hello")' 처럼 cmd /c echo hello 이런식으로 이용이 가능하다.

 

두번째 인자TCHAR cmd[]=L"cmd /c echo hello" 처럼 변수에 따로 선언해 전달하는게 좋다고 한다. 읽고 쓸 때가 있기 때문이다.

 

마지막으로, 6번째 인자인 DWORD dwCreationFlagsCREATE_NEW_CONSOLE flag 를 설정하지 않으면, 부모프로세스와 콘솔창을 공유하게 된다. 그래서 자식프로세스의 출력값이 부모프로세스의 콘솔에 출력이 된다.

 

설정을 한다면, 새로운 콘솔창에 출력값을 출력하게 되는데

#include<stdio.h>
#include<windows.h>
int main(void){
	fprintf(stdout,"holymolyholymoly");
}

이때 자식프로세스가 값을 출럭하고 아무런 동작을하지 않기때문에, 바로 닫혀 자식프로세스가 올바르게 출력했는지 확인할 수 없게된다. 그래서 마지막에 getchar(); 같은 함수를 넣어줘서 출력값을 확인할 수 있다.

 

#윤성우 윈도우즈 시스템 프로그래밍 기반으로 작성하였습니다.