C++

윈도우 시스템 프로그래밍 강의 – 널널한 개발자 TV

 

 

https://www.youtube.com/watch?v=PQ5gqh0p2-c&list=PLXvgR_grOs1ANK0gLpkt6L9v_1xH32caM&index=2

 

  1. 프로세스 생성
  2. WaitForSingleObject 함수에 대해서
  3. Event 객체를 이용한 프로세스 동기화
  4. CreateThread() 함수와 자동 업데이트 구현

 

 


 

 1. 프로세스 생성

 

https://docs.microsoft.com/en-us/windows/win32/procthread/creating-processes

 

# 버튼 1개 만들기
ID : IDC_BUTTON_CreateProcess
캡션 : CreateProcess()

 

# GetLastError() 에서 반환한 오류 번호에 대한 오류 메시지 보기
도구 – 오류 조회 – 오류 번호 입력

 

void CProcessSample01Dlg::OnBnClickedButtonCreateprocess()
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

        // 또는	_T("notepad.exe")
        // 경로를 안적어도 환경 변수를 뒤져서 실행된다.
    TCHAR szBuffer[MAX_PATH + _MAX_FNAME] = { L"notepad.exe" };

    // Start the child process. 
    if (!CreateProcess(NULL,   // No module name (use command line)
        szBuffer,        // Command line
        NULL,           // Process handle not inheritable
        NULL,           // Thread handle not inheritable
        FALSE,          // Set handle inheritance to FALSE
        0,              // No creation flags
        NULL,           // Use parent's environment block
        NULL,           // Use parent's starting directory 
        &si,            // Pointer to STARTUPINFO structure
        &pi)           // Pointer to PROCESS_INFORMATION structure
        )
    {
        CString strTmp;
        strTmp.Format(L"CreateProcess failed (%d).", GetLastError()); 
        AfxMessageBox(strTmp);
        return;
    }

    // Wait until child process exits.
    WaitForSingleObject(pi.hProcess, INFINITE);

    // Close process and thread handles. 
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

 

# [Win32/MFC] “”, L””, TEXT(“”), _T(“”) 차이점
http://x108zero.blogspot.com/2013/12/text-t-l.html

멀티바이트(MBCS) : 영어는 1바이트, 그 외 문자는 2바이트
유니코드(WBCS) : 모든 문자를 2바이트로 처리

멀티바이트 : “aaaaa”
유니코드 : L”aaaaa”

TEXT(“aaaaa”) 또는 _T(“aaaaa”) 를 쓰면
멀티바이트면 “aaaaa”
유니코드면 L”aaaaa”
으로 자동 변환됨
MFC는 _T(“aaaaa”) 를 써라.

 

# TCHAR,  char,  wchar_t
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=dkdaf&logNo=90156336556

TCHAR 매크로는
멀티바이트면 char (1바이트)
유니코드면 wchar_t (2바이트)
로 변환해주는 매크로

 


 

2. WaitForSingleObject 함수에 대해서

 

WaitForSingleObject function
DWORD WaitForSingleObject([in] HANDLE hHandle, [in] DWORD dwMilliseconds);

 

– HANDLE
1. void * (거의 void * 이다.)
2. 값

– dwMilliseconds
밀리초. 예) 3000 (3초)

– HANDLE (포인터) 가 가리키는 주소의 변화를 감지하는 함수
– non-signaled 상태에서 signaled 상태가 될 때까지 wait 한다. 밀리세컨드만큼
– 함수를 호출하는 순간 호출한 쓰레드는 wait 상태가 된다. 응답없음 상태

 

void CProcessSample01Dlg::OnBnClickedButtonCreateprocess()
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    TCHAR szBuffer[MAX_PATH + _MAX_FNAME] = { L"notepad.exe" }; // 또는 	_T("notepad.exe")  // 경로를 안적어도 환경 변수를 뒤져서 실행된다.

    // Start the child process. 
    if (!CreateProcess(NULL,   // No module name (use command line)
        szBuffer,        // Command line
        NULL,           // Process handle not inheritable
        NULL,           // Thread handle not inheritable
        FALSE,          // Set handle inheritance to FALSE
        0,              // No creation flags
        NULL,           // Use parent's environment block
        NULL,           // Use parent's starting directory 
        &si,            // Pointer to STARTUPINFO structure
        &pi)           // Pointer to PROCESS_INFORMATION structure
        )
    {
        CString strTmp;
        strTmp.Format(L"CreateProcess failed (%d).", GetLastError()); 
        AfxMessageBox(strTmp);
        return;
    }

    // Wait until child process exits.
    DWORD dwResult = WaitForSingleObject(pi.hProcess, INFINITE);
    if (dwResult == WAIT_OBJECT_0) {
        AfxMessageBox(L"메모장이 종료됐습니다.");
    }
    else if (dwResult == WAIT_TIMEOUT) {
        AfxMessageBox(L"타임아웃 발생!");
    }
    else {
        AfxMessageBox(L"ERROR: 심각한 오류가 발생했습니다!");
    }

    // Close process and thread handles. 
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

 


 

3. Event 객체를 이용한 프로세스 동기화

 

// linux unix : signal
// windows : Event (set, reset)

 

# 버튼 4개 만들기

ID : IDC_BUTTON_CreateProcess  // 1편 강의에서 만든 것
캡션 : CreateProcess()

IDC_BUTTON_CreateEvent
캡션 : CreateEvent()

IDC_BUTTON_WaitEvent
캡션 : Wait Event

IDC_BUTTON_SetEvent
캡션 : Set Event

 

# CloseHandle(핸들)

  1. null 체크 안해도 그냥 넘어간다. 널 체크 안해도됨.
  2. 프로세스가 종료되면 자동으로 핸들을 닫으므로 굳이 안해줘도 된다.
  3. 그래도 원칙상 CloseHandle(핸들)을 해준다.

 

 

 

//  ProcessSample01Dlg.h
protected:
        HANDLE m_hEvent = NULL;

// ProcessSample01Dlg.cpp
void CProcessSample01Dlg::OnBnClickedButtonCreateprocess()
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    TCHAR szBuffer[MAX_PATH + _MAX_FNAME] = { L"notepad.exe" }; // 또는 	_T("notepad.exe")  // 경로를 안적어도 환경 변수를 뒤져서 실행된다.

    // Start the child process. 
    if (!CreateProcess(NULL,   // No module name (use command line)
        szBuffer,        // Command line
        NULL,           // Process handle not inheritable
        NULL,           // Thread handle not inheritable
        FALSE,          // Set handle inheritance to FALSE
        0,              // No creation flags
        NULL,           // Use parent's environment block
        NULL,           // Use parent's starting directory 
        &si,            // Pointer to STARTUPINFO structure
        &pi)           // Pointer to PROCESS_INFORMATION structure
        )
    {
        CString strTmp;
        strTmp.Format(L"CreateProcess failed (%d).", GetLastError()); 
        AfxMessageBox(strTmp);
        return;
    }

    // Wait until child process exits.
    DWORD dwResult = WaitForSingleObject(pi.hProcess, INFINITE);
    if (dwResult == WAIT_OBJECT_0) {
        AfxMessageBox(L"메모장이 종료됐습니다.");
    }
    else if (dwResult == WAIT_TIMEOUT) {
        AfxMessageBox(L"타임아웃 발생!");
    }
    else {
        AfxMessageBox(L"ERROR: 심각한 오류가 발생했습니다!");
    }

    // Close process and thread handles. 
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}


void CProcessSample01Dlg::OnBnClickedButtonCreateevent()
{
    ::CloseHandle(m_hEvent);  // 널체크 안해도 됨. null 이면 자동으로 넘어감.

    m_hEvent = ::CreateEvent(NULL, TRUE, FALSE, L"PROCESS_SYNC_TEST_EVENT");  // 매뉴얼 리셋
    if (m_hEvent == NULL)
    {
        //AfxMessageBox(L"ERROR: Failed to create event object!");
        if (::GetLastError() == ERROR_ALREADY_EXISTS)
        {
            m_hEvent = ::OpenEvent(EVENT_ALL_ACCESS, FALSE, L"PROCESS_SYNC_TEST_EVENT");
            if (m_hEvent == NULL)
            {
                AfxMessageBox(L"ERROR: Failed to open event object!");
                return;
            }
        }
        return;
    }
}


void CProcessSample01Dlg::OnBnClickedButtonWaitevent()
{
    if (::WaitForSingleObject(m_hEvent, INFINITE) == WAIT_OBJECT_0)
        AfxMessageBox(L"Event가 세트 됐습니다.");	
}


void CProcessSample01Dlg::OnBnClickedButtonSetevent()
{
    ::SetEvent(m_hEvent);

    // 어떠한 이유로 한 프로세스가 리셋이벤트를 못받는 경우를 대비. Sleep()은 해결책이 아님
    // Event를 하나 더 만들거나 카운터를 만들어서 해결.
    ::Sleep(300);

    ::ResetEvent(m_hEvent);
}

 


 

4. CreateThread() 함수와 자동 업데이트 구현

 

# 버튼 3개 만들기

# IDC_BUTTON_CreateUpdateEvent
캡션 : Create Update Event

# IDC_BUTTON_UpdateEventSet
캡션 : Set Update Event

# IDC_BUTTON_WaitUpdateEvent
캡션 : Wait Update Event

 

# CreateThread 로 쓰레드를 만들고 return 하면 자동으로 종료됨
굳이 Terminate 하지 말고 return 하도록 유도해라.

 

# 버튼으로 이벤트 생성, Set, Wait 하기

// CProcessSample01Dlg.h
protected:
    virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support

    HANDLE m_hEventUpdate = NULL;

// CProcessSample01Dlg.cpp
void CProcessSample01Dlg::OnBnClickedButtonCreateupdateevent()
{
    ::CloseHandle(m_hEventUpdate);  // 널체크 안해도 됨. null 이면 자동으로 넘어감.

    m_hEventUpdate = ::CreateEvent(NULL, TRUE, FALSE, L"PROCESS_UPDATE_EVENT");  // 매뉴얼 리셋
    if (m_hEventUpdate == NULL)
    {
        //AfxMessageBox(L"ERROR: Failed to create event object!");
        if (::GetLastError() == ERROR_ALREADY_EXISTS)
        {
            m_hEventUpdate = ::OpenEvent(EVENT_ALL_ACCESS, FALSE, L"PROCESS_UPDATE_EVENT");
            if (m_hEventUpdate == NULL)
            {
                AfxMessageBox(L"ERROR: Failed to open update event object!");
                return;
            }
        }
        return;
    }
}


void CProcessSample01Dlg::OnBnClickedButtonUpdateeventset()
{
    ::SetEvent(m_hEventUpdate);
}

DWORD WINAPI ThreadWaitForUpdate(LPVOID pParam)
{
    HANDLE hEvent = pParam;
    if (::WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0)
    {
        //AfxMessageBox(L"UPDATE EVENT!");
        theApp.m_pMainWnd->PostMessage(WM_CLOSE);
    }
    //AfxMessageBox(L"Thread return");
    return 0;
}


void CProcessSample01Dlg::OnBnClickedButtonWaitupdateevent()
{
    ::CreateThread(NULL, 0, ThreadWaitForUpdate, m_hEventUpdate, 0, NULL);
}

 

 

# 자동으로 시작하는 업데이트 구현

DWORD WINAPI ThreadWaitForUpdate(LPVOID pParam)
{
    HANDLE hEvent = pParam;
    if (::WaitForSingleObject(hEvent, INFINITE) == WAIT_OBJECT_0)
    {
        //AfxMessageBox(L"UPDATE EVENT!");
        theApp.m_pMainWnd->PostMessage(WM_CLOSE);
    }
    //AfxMessageBox(L"Thread return");
    return 0;
}


// 프로그램 시작시 자동 업데이트 실행

BOOL CProcessSample01Dlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    ::CloseHandle(m_hEventUpdate);  // 널체크 안해도 됨. null 이면 자동으로 넘어감.

        m_hEventUpdate = ::CreateEvent(NULL, TRUE, FALSE, L"PROCESS_UPDATE_EVENT");  // 매뉴얼 리셋
    if (m_hEventUpdate == NULL)
    {		
        //AfxMessageBox(L"ERROR: Failed to create event object!");
        if (::GetLastError() == ERROR_ALREADY_EXISTS)
        {
            m_hEventUpdate = ::OpenEvent(EVENT_ALL_ACCESS, FALSE, L"PROCESS_UPDATE_EVENT");
            if (m_hEventUpdate == NULL)
            {
                AfxMessageBox(L"ERROR: Failed to open update event object!");
                return FALSE;
            }
        }		
        return FALSE;
    }

    ::CreateThread(NULL, 0, ThreadWaitForUpdate, m_hEventUpdate, 0, NULL);

    return TRUE;  // return TRUE  unless you set the focus to a control
}

 

 

Related posts

Leave a Comment