//Самопальный класс для несложных работ с процессами
class ProcessezWork
{
public:
///////////////////////////////////////////////////////////////////////////////////////
// это две возможности получить ProcessID: какую использовать - каждый решает сам:
///////////////////////////////////////////////////////////////////////////////////////
//
// возвращает ID процесса
static bool getProcessId(
const char *pProgrName_in,
DWORD *pth32ProcessID_out,
bool bWithTraces=true
);
// возвращает ID процесса и ID thread-a
static bool GetProcessByExeName(
CString& ExeName,
DWORD& dwThreadId,
DWORD& dProcId
);
//------------------------------
// разные возможности убить запущенный процесс
//используется taskkill.exe
static void KillProcess_taskkill(const char* const pExeName);
//используется отправка сообщения WM_CLOSE главному окну процесса
static void KillProcess_sendMsg(CString& sProcessName);
//вызовом TerminateProcess
static void KillProcess_terminateProc(const CString& sProcessName);
//создать и тут же убить процесс (зачем - другое дело :) )
static void KillProcess_createTerminateProc(const CString& sProcessName);
//запустить процесс и дождаться, пока он не завершится сам
//(аналог "start /wait" из пакетного файла)
static bool RunProcessAndWaitWhenDone(
const char* szApplicationName,
const char* szCommandLine_i = 0,
const char* szCurrentDirectory = 0,
DWORD dwdTimeOut_i = -1
);
//получить путь к system32 (со слешем на конце)
static CString GetSystemPATH__();
};
/////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////
// варианты для kill process:
///////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
// с помощью taskkill.exe
///////////////////////////////////////////////////////////////
void ProcessezWork::KillProcess_taskkill(const char* const pExeName)
{
DWORD dwThreadId, dProcId;
CString ExeName = pExeName;
if(!GetProcessByExeName( ExeName, dwThreadId, dProcId ) ) return;
HANDLE hpr=0;
hpr=::OpenProcess( PROCESS_TERMINATE, 0, dProcId );
if( hpr )
{
CString txt, sTaskKill("taskkill.exe");
// не всегда taskkill.exe находится в C:\\windows\\system32, поэтому для гибкости
// нашей программы системный путь находим программным путем
CString sSysPath = GetSystemPATH__();
// убиваем сам процесс и все его Children-Процессы
txt.Format( " /c %s\%s /pid %d /f /t",sSysPath, sTaskKill, dProcId );
RunProcessAndWaitWhenDone(sSysPath + "cmd.exe", txt);
}
else
{
DWORD nErr = GetLastError();
}
::TerminateProcess(hpr,0);
::CloseHandle(hpr);
return;
}
////////////////////////////////////////
// kill a process with taskkill.exe
////////////////////////////////////////
bool ProcessezWork::RunProcessAndWaitWhenDone(
const char* szApplicationName,
const char* szCommandLine_i,
const char* szCurrentDirectory,
DWORD dwdTimeOut_i
)
{
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInfo;
DWORD dwRetValue;
::memset( &StartupInfo, 0, sizeof(StartupInfo) );
StartupInfo.cb = sizeof( StartupInfo );
CString csCommandLine = szCommandLine_i; // это обязательно, иначе испортится содержимое строки szCommandLine_i!!!
if( !::CreateProcess(
szApplicationName,(char*)(const char*)csCommandLine,
0, 0, 0, NORMAL_PRIORITY_CLASS, 0, szCurrentDirectory,
&StartupInfo, &ProcessInfo))
{
// oshibka - proverjaem
DWORD dwdErr=GetLastError();
return false;
}
else
{
::CloseHandle( ProcessInfo.hThread );
::WaitForSingleObject( ProcessInfo.hProcess, dwdTimeOut_i );
::GetExitCodeProcess( ProcessInfo.hProcess, &dwRetValue );
::CloseHandle( ProcessInfo.hProcess);
}
return true;
}
///////////////////////////////////////////////////////////////
// terminate process. the process was created in other program
///////////////////////////////////////////////////////////////
void ProcessezWork::KillProcess_sendMsg( CString& sProcessName)
{
DWORD dwThreadId, dProcId;
CWnd* pWnd = FindWindow( NULL, sProcessName);
// ищем ID процесса
GetProcessByExeName( sProcessName, dwThreadId, dProcId );
// получаем handle процесса
HANDLE hProc = ::OpenProcess(PROCESS_ALL_ACCESS, false, dProcId);
if( hProc )
{
UINT uExitCode = NO_ERROR;
// это не очень корректный способ завершения процесса
//BOOL bIsTerminated = TerminateProcess(hProc, uExitCode );
// поэтому так лучше (хотя в принципе оба имеют место быть)
::SendMessage(pWnd->m_hWnd, WM_CLOSE, 0, 0);
CloseHandle(hProc);
}
}
///////////////////////////////////////////////////////////////
// terminate process. the process was created in other program (application)
///////////////////////////////////////////////////////////////
void ProcessezWork::KillProcess_terminateProc( const CString& sProcessName)
{
DWORD nProcessId = 0;
getProcessId( "FS.exe", &nProcessId, false);
HANDLE hProc = ::OpenProcess(PROCESS_ALL_ACCESS, false, nProcessId);
if( hProc )
{
UINT uExitCode = NO_ERROR;
BOOL bIsTerminated = TerminateProcess(hProc, uExitCode );
CloseHandle(hProc);
}
}
/////////////////////////////////////////////////
// create and terminate process in one program
/////////////////////////////////////////////////
void ProcessezWork::KillProcess_createTerminateProc( const CString& sProcessName)
{
STARTUPINFO cif;
ZeroMemory(&cif,sizeof(STARTUPINFO) );
PROCESS_INFORMATION pi;
if( CreateProcess(sProcessName,NULL,NULL,NULL,FALSE,NULL,NULL,NULL,&cif,&pi) )
{
TerminateProcess(pi.hProcess,NO_ERROR);
}
}
CString ProcessezWork::GetSystemPATH__()
{
CString result = "";
int len = MAX_PATH + 1;
char* chSys = new char [len];
::memset( chSys, 0, len );
if( !::GetSystemDirectory(chSys, len) ) return "";
result = chSys;
result += "\\";
delete [] chSys;
chSys=0;
return result;
}
////////////////////////////////////////
// get process id and thread id
////////////////////////////////////////
bool ProcessezWork::GetProcessByExeName(
CString& ExeName,
DWORD& dwThreadId,
DWORD& dProcId
)
{
CWnd* pWnd = FindWindow( NULL, ExeName);
dwThreadId = GetWindowThreadProcessId(pWnd->m_hWnd, &dProcId);
return true;
}
////////////////////////////////////////
// get process id (other way)
////////////////////////////////////////
// эта функция ищет не только process id, но и все его подмодули. А возвращает только processId ( она была просто быстро подогнана для этого примера )
// и еще - здесь закомментированы все вызовы GetDlgItem(), т.к. они не будут работать из-за отсутствия полного проекта с ресурсами.
bool ProcessezWork::getProcessId(
const char *pProgrName_in,
DWORD *pth32ProcessID_out,
bool bWithTraces
)
{
HANDLE hProcessSnap = NULL;
BOOL bRet = FALSE;
PROCESSENTRY32 pe32 = {0};
char sBuf[10000], sText[10000] ;
CString sEditText = "";
char buf[100];
DWORD th32ProcessID = 0;
// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(hProcessSnap == INVALID_HANDLE_VALUE)
return(FALSE);
// Fill in the size of the structure before using it.
pe32.dwSize = sizeof(PROCESSENTRY32);
// Walk the snapshot of the processes, and for each process,
// display information.
if(Process32First(hProcessSnap, &pe32))
{
//DWORD dwPriorityClass;
BOOL bGotModule = FALSE;
MODULEENTRY32 me32 = {0};
HANDLE hModSnap = NULL;
//GUITHREADINFO guiThr = {0};
BOOL bGotGuiThread = FALSE;
THREADENTRY32 thr32 = {0};
HANDLE hThrSnap = NULL;
BOOL bGotThread = FALSE;
do
{
strcpy(buf, pe32.szExeFile);
th32ProcessID = pe32.th32ProcessID;
// test the name of the process
if(0 == strcmp(buf, pProgrName_in))
{
// only for test!
if( bWithTraces )
{
sprintf(sBuf, "ProcessName = %s processID = %d \r\n", buf, th32ProcessID);
//GetDlgItem(IDC_PROC_LIST_LIST)->GetWindowText(sEditText);
strcpy(sText, sEditText);
strcat(sText, sBuf);
//GetDlgItem(IDC_PROC_LIST_LIST)->SetWindowText(sText);
}
*pth32ProcessID_out = th32ProcessID;
// only for test !
if( bWithTraces )
{
// hold all modules (dlls usw.)
hModSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pe32.th32ProcessID);
me32.dwSize = sizeof(MODULEENTRY32);
bGotModule = Module32First(hModSnap, &me32);
while(bGotModule)
{
bGotModule = Module32Next(hModSnap, &me32);
}
// hold all threads
hThrSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, pe32.th32ProcessID);
thr32.dwSize = sizeof(THREADENTRY32);
bGotThread = Thread32First(hThrSnap, &thr32);
while(bGotThread)
{
bGotThread = Thread32Next(hThrSnap, &thr32);
}
} //if( bWithTraces )
break;
}
else
{
// only for test !
if( bWithTraces )
{
sprintf(sBuf, "ProcessName = %s \r\n ", buf);
//GetDlgItem(IDC_PROC_LIST_LIST)->GetWindowText(sEditText);
strcpy(sText, sEditText);
strcat(sText, sBuf);
//GetDlgItem(IDC_PROC_LIST_LIST)->SetWindowText(sText);
}
} // if(0 == strcmp(buf, pProgrName_in))
}
while(Process32Next(hProcessSnap, &pe32));
bRet = TRUE;
}
else
{
bRet = FALSE; // could not walk the list of processes
}
// Do not forget to clean up the snapshot object.
CloseHandle(hProcessSnap);
return (bool)bRet;
}
//----------------------------------------------------
//пример использования
// все перечисленные вызовы функций работают, просто
// соответственно в функции может использоваться только один из способов;-)
// поэтому остальные закомментированы
void Example1()
{
// так можно в одном процессе сначала стартовать, а затем убить другой процесс
CString sProcessName1("E:\\irina\\fs.exe");
ProcessezWork::KillProcess_createTerminateProc( sProcessName1 );
// так можно убить процесс, который был запущен из другого приложения
// вариант 1:
CString sProcessName_msg( "FS" );
ProcessezWork::KillProcess_terminateProc(sProcessName_msg);
// вариант 2:
CString sProcessName( "FS" );
ProcessezWork::KillProcess_sendMsg(sProcessName);
// вариант 3
ProcessezWork::KillProcess_taskkill( sProcessName );
}