본문 바로가기
Windows/MFC 강좌 & Tips

[Widget] CreateProcess & 프로세스 중복 방지

by 미티치 2016. 12. 21.

이전 글에서 MFC Dialog로 위젯을 만들어서 버튼 클릭하면 메모장 실행되는 소스를 만들었다.

 

ShellExecute 함수를 CreateProcess로 바꿨고, 버튼을 클릭해서 메모장을 실행하고나서 또 버튼을 클릭하면 이미 실행되고 있다고 메세지 박스를 띄우는 소스이다.

 

 

1. 다이얼로그 >> 버튼 >> 더블클릭 해서 자동생성된 메소드 ( 이전 글에서 ShellExecute 함수 썼던 곳 )

 

void CwTest4Dlg::OnBnClickedNotepad()
{
     HANDLE hEvent;
     hEvent = CreateEvent(NULL, FALSE, TRUE, AfxGetAppName());
     
      // 프로세스가 이미 실행중인지 검사

if(GetLastError() == ERROR_ALREADY_EXISTS){
    AfxMessageBox(_T("이미 프로그램이 실행중입니다"));             //메세지박스
    //PostQuitMessage(WM_QUIT);                                        //-> 실행중인 프로세스(부모프로세스) 종료
}else{

    // 여기부터 CreateProcess로 프로세스 실행
    STARTUPINFO si = {0,};
    PROCESS_INFORMATION pi;
    si.cb = sizeof( si);
    ::CreateProcess(_T("C:\\windows\\system32\\notepad.exe"), NULL, NULL, NULL, FALSE, 0 , NULL, NULL, &si, &pi);
}

 

}

 

 

 

위의 소스코드로하면 프로세스를 한 번 실행 시키고, 실행된 상태에서 다시 실행시키면 이미 실행중이라고 메세지박스가 뜬다.

하지만 문제점은, 프로세스를 종료시킨 후 다시 실행시키려고 하면 다시 실행되지 않고 메세지 박스가 뜬다.

 

아마 핸들을 제대로 종료시켜주지 않아서인지, 내부적으로는 프로세스와 연결된 핸들이 계속 있어서인지 정확하게는 모르겠지만 어쨌든 안된다.

 

 

 

 

 

CreateProcess 함수

 

CreateProcessW(

    __in_opt    LPCWSTR lpApplicationName,

    __inout_opt LPWSTR lpCommandLine,

    __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes,

    __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes,

    __in        BOOL bInheritHandles,

    __in        DWORD dwCreationFlags,

    __in_opt    LPVOID lpEnvironment,

    __in_opt    LPCWSTR lpCurrentDirectory,

    __in        LPSTARTUPINFOW lpStartupInfo,

    __out       LPPROCESS_INFORMATION lpProcessInformation

    );

1.     lpApplicationName
생성한 프로세스의 실행파일 이름을 인자로 전달합니다. 경로명을 추가로 지정할 수 있으며 경로명을 지정하지 않을 경우에는 프로그램의 현재 디렉터리에서 찾게 됩니다. 현재 디렉터리에서 찾길 원하면 NULL 값을 지정해 줍니다.

2.     lpCommandLine
main
함수에 argc, argv라는 이름으로 전달되는 것처럼 프로세스에 인자를 전달할 때 이용합니다. 또는 첫 번째 인자에 NULL을 준 다음 이 두 번째 인자에 실행파일의 이름을 더불어 전달할 수도 있습니다. 이 경우엔 실행파일의 이름은 표준 검색경로 기준으로 찾게 됩니다.

3.     lpProcessAttribute
프로세스의 보안 속성을 지정할 때 사용하며 NULL을 전달할 경우 디폴트 보안 속성이 지정됩니다.

4.     lpThreadAttribute
쓰레드의 보안 속성을 지정할 때 사용하며 NULL을 전달할 경우 디폴트 보안 속성이 지정됩니다.

5.     hInheritHandle
전달인자가 TRUE일 경우, 생성되는 자식 프로세스는 부모 프로세스가 소유하는 handle 중 일부를 상속합니다.

6.     dwCreationFlag
생성하는 프로세스의 특성(특히 우선순위)를 결정지을 때 사용하는 옵션입니다. 설정하지 않을 때는 0을 전달합니다.

7.     lpEnvironment
프로세스마다 Environment Block이라는 메모리 블록을 관리합니다. 이 블록을 이용 프로세스가 실행 시 필요로 하는 문자열을 저장할 수 있습니다. 이 전달인자를 통해서 생성하는 Environment Block을 지정합니다. NULL을 전달하면 자식 프로세스는 부모 프로세스의 환경 블록에 저장되어 있는 문자열을 복사하게 됩니다.

8.     lpCurrentDirectory
생성하는 프로세스의 현재 디렉터리를 설정하는 인자입니다. 전달인자는 디렉터리 정보를 포함하는 완전경로로 구성해야 하며 NULL 전달 시 부모 프로세스의 디렉터리를 현재 디렉터리로 합니다.

9.     lpStartInfo
STARTUPINFO
구조체 변수를 초기화 한 다음에 이 변수의 포인터를 인수로 전달합니다.

10.  lpProcessIormation
생성하는 프로세스 정보를 얻기 위해 사용되는 인자입니다. PROCESS_INFORMATION 구조체 변수의 주소 값을 인자로 전달합니다.

 

( 출처 http://robodream.tistory.com/188 )

 

 


 

 

쉽게 말하면 작업관리자에서 볼 수 있는 현재 실행중인 프로세스 목록을 함수 CreateToolhelp32Snapshot을 이용해서 가지고 와서 그 목록에서 내가 찾고자 하는 (예를 들어 여기서 notepad.exe라고 한다면) notepad.exe 가 있는지 검사하고 현재 실행중인 프로세스 목록에 있으면 "이미 실행중인 프로그램입니다."라는 메세지 박스를 띄워주는 것이다.

 

1. 다음 헤더파일과 cpp 파일을 포함시키고

 

 

2. 프로젝트이름Dlg.h 에서 #include "MyCheckProcess.h" 를 포함하고 다음과 같이 변수 선언해준다.

 

            CMyCheckProcess m_MyCheckProcess;

 

3. 프로젝트이름Dlg.h를 구현한 프로젝트이름Dlg.cpp 에 내가 생성한 버튼 클릭 메소드( void CwTest4Dlg::OnBnClickNotepad() )에  아래 소스를 넣는다.

- 위에서 첨부한 클래스를 m_MyCheckProcess로 객체 생성해서 프로세스가 실행중인지 확인하는 메소드 CheckExecute()를 호출한다.

- CheckExecute의 반환형이 TRUE, FALSE인데 이를 이용해서 실행중인지 여부를 m_bCurrent로 받아서 if문으로 처리한다. 

 

void CwTest4Dlg::OnBnClickedNotepad()
{

 BOOL m_bCurrent = FALSE;
 m_bCurrent = m_MyCheckProcess.CheckExecute(_T("notepad.exe"));

 

// 실행중이면
 if( m_bCurrent == TRUE){
  AfxMessageBox(_T("이미 프로그램이 실행중입니다")); //메세지박스
 }
 // 실행중이지 않으면
 else if( m_bCurrent == FALSE ){
  STARTUPINFO si = {0,};
  PROCESS_INFORMATION pi;
  si.cb = sizeof( si);
  ::CreateProcess(_T("C:\\windows\\system32\\notepad.exe"), NULL, NULL, NULL, FALSE, 0 , NULL, NULL, &si, &pi);
 }

}

 

 

 

이렇게 하면 다이얼로그에서 버튼을 눌러서 notepad.exe 를 실행할 수 있고, notepad.exe가 이미 실행중일 땐 중복실행을 방지하기 위해 이미 프로그램이 실행중이라는 메세지 박스를 띄울 수 있다.

 

( 소스 출처는 http://egloos.zum.com/swain/v/2291652 인데, 해당 소스를 조금 수정했다. )

 

 

 

 


 

첨부한 소스를 분석하다가 Handle 객체에 대해 궁금했다. 핸들은 MFC에서 굉장히 중요하다.

핸들에 대한 설명은 다음에! 다시 정리해야지