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 |

Rss Feed