2012. 3. 23. 14:50
프로세스 생성 종결자 (ShellExecute / CreateProcess)
2012. 3. 23. 14:50 in 프로그래밍/Let's Share it
Vista 이상에서 되도록 ShellExecute를 권장하고 있습니다.
그래서 ShellExecute를 그냥 사용하게 되는데,
간혹 Shell 쪽의 COM이 깨져 ShellExecute가 실패하는 경우가 있습니다.
그때는 CreateProcess를 해줘야 합니다.
ShellExecute / CreateProcess 모두 많은 Argument가 있어 사용하기 복잡합니다.
그래서,
- 실행 경로 (lpszExePath)
- 종료때 까지 기다릴지 여부 (bBlock)
- Exit Code (pnExitCode, Optional)
- 실행 파라미터 (lpszParam, Optional)
- 실행 프로세스의 Current Directory (lpszDirectory, Optional)
와 같이 실제 자주 사용되는 Argument로 종합한 함수를 공유합니다.
물론, Optional은 NULL이나 0을 전달해도 무방합니다.
내부에서 ShellExecute가 실패하면 CreateProcess로 연결되니, 걱정않으셔도 됩니다. :)
// TRACELOG는 TRACE로그를 찍는 것일 수 있음 // 각자 정의한 것으로 Replace 요망 // 삭제 가능 // Block이 TRUE이고 ERROR_SUCCESS 리턴일때 pnExitCode 의미 있음 DWORD ExecuteProcess(IN LPCTSTR lpszExePath, IN BOOL bBlock, OPTIONAL OUT PINT pnExitcode, OPTIONAL IN LPCTSTR lpszParam, OPTIONAL IN LPCTSTR lpszDirectory) { DWORD dwRtnValue = ERROR_SUCCESS; DWORD dwResult = 0; SHELLEXECUTEINFO stInfo = {0,}; HANDLE hCreateProcess = NULL; STARTUPINFO si = {0,}; PROCESS_INFORMATION pi = {0,}; LPTSTR lpszCmd = {0,}; CString strCmdLine; if (NULL != pnExitcode) { (*pnExitcode) = -1; } if (NULL == lpszExePath) { dwRtnValue = ERROR_INVALID_PARAMETER; goto FINAL; } TRACELOG(TEXT("[INFO] ExecuteCalled")); TRACELOG(TEXT("[INFO] lpszExePath : %s"), lpszExePath); if (NULL != lpszParam) { TRACELOG(TEXT("[INFO] lpszParam : %s"), lpszParam); } if (NULL != lpszDirectory) { TRACELOG(TEXT("[INFO] lpszDirectory : %s"), lpszDirectory); } TRACELOG(TEXT("[INFO] Block : %d"), bBlock); stInfo.cbSize = sizeof(stInfo); stInfo.lpFile = lpszExePath; stInfo.lpDirectory = lpszDirectory; stInfo.lpParameters = lpszParam; stInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI | SEE_MASK_CLASSNAME; stInfo.nShow = SW_SHOW; stInfo.lpClass = TEXT("exefile"); if (FALSE == ::ShellExecuteEx(&stInfo)) { // ShellExcute가 실패했다. TRACELOG(TEXT("[ERROR] Fail to ShellExecuteEx, %d"), ::GetLastError()); // CreateProcess로 재도전 strCmdLine = lpszExePath; strCmdLine.TrimRight(TEXT("\"")); strCmdLine.TrimLeft (TEXT("\"")); strCmdLine.Insert(0, TEXT("\"")); strCmdLine += TEXT("\""); si.cb = sizeof(si); if (NULL != lpszParam) { strCmdLine += TEXT(" "); strCmdLine += lpszParam; } lpszCmd = new TCHAR[_tcslen(strCmdLine)+1]; if (NULL == lpszCmd) { dwRtnValue = ERROR_NOT_ENOUGH_MEMORY; goto FINAL; } ZeroMemory(lpszCmd, sizeof(TCHAR)*(_tcslen(strCmdLine)+1)); ::StringCchCopy(lpszCmd, _tcslen(strCmdLine)+1, strCmdLine); strCmdLine.Empty(); if (FALSE == ::CreateProcess(NULL, lpszCmd, NULL, NULL, FALSE, 0, NULL, lpszDirectory, &si, &pi)) { dwRtnValue = ::GetLastError(); TRACELOG(TEXT("[INFO] Fail to CreateProcess, %d"), dwRtnValue); goto FINAL; } if (TRUE == bBlock) { TRACELOG(TEXT("[INFO] Try to Wait process(CP) %s"), lpszExePath); dwRtnValue = ::WaitForSingleObject(pi.hProcess, INFINITE); TRACELOG(TEXT("[INFO] Finished to Wait process(CP) %s"), lpszExePath); if (NULL != pnExitcode) { if (FALSE == ::GetExitCodeProcess(pi.hProcess, (DWORD*)pnExitcode)) { dwRtnValue = ::GetLastError(); TRACELOG(TEXT("[ERROR] Fail to GetExitCode(CP), GetLastError=%d"), dwRtnValue); goto FINAL; } TRACELOG(TEXT("[INFO] ExitCode(CP)=%d"), (*pnExitcode)); } } if (NULL != pi.hProcess) { ::CloseHandle(pi.hProcess); pi.hProcess = NULL; } if (NULL != pi.hThread) { ::CloseHandle(pi.hThread); pi.hThread = NULL; } } else { if (NULL != stInfo.hProcess) { if (TRUE == bBlock) { TRACELOG(TEXT("[INFO] Try to Wait process %s"), lpszExePath); dwResult = ::WaitForSingleObject(stInfo.hProcess, INFINITE); TRACELOG(TEXT("[INFO] Finished to Wait process %s"), lpszExePath); if (NULL != pnExitcode) { if (FALSE == ::GetExitCodeProcess(stInfo.hProcess, (DWORD*)pnExitcode)) { dwRtnValue = ::GetLastError(); TRACELOG(TEXT("[ERROR] Fail to GetExitCode, GetLastError=%d"), dwRtnValue); goto FINAL; } TRACELOG(TEXT("[INFO] ExitCode=%d"), (*pnExitcode)); } } ::CloseHandle(stInfo.hProcess); stInfo.hProcess = NULL; } } dwRtnValue = ERROR_SUCCESS; FINAL: if (NULL == lpszCmd) { delete [] lpszCmd; lpszCmd = NULL; } if (NULL != stInfo.hProcess) { ::CloseHandle(stInfo.hProcess); stInfo.hProcess = NULL; } if (NULL != pi.hProcess) { ::CloseHandle(pi.hProcess); pi.hProcess = NULL; } if (NULL != pi.hThread) { ::CloseHandle(pi.hThread); pi.hThread = NULL; } return dwRtnValue; }
'프로그래밍 > Let's Share it' 카테고리의 다른 글
간단하게 SHA256(sha2) 구하기 (1) | 2012.05.25 |
---|---|
PE 포맷 바이너리 파일의 버전을 구하는 함수 (0) | 2012.04.30 |
손쉽게 File을 나열할 수 있는 class 공유(FindFirstFile/FindNextFile Wrapper) (0) | 2012.03.23 |
VC9.0에서 crypto++ library를 이용하여 SHA256(sha2) 구하기 (8) | 2011.12.14 |
비동기(OVERLAPPED I/O, IOCP, Thread Pool) IPC PIPE Class 공유 (0) | 2011.12.14 |