//Самопальный класс для несложных работ с процессами
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 );
}