www.pudn.com > vc中得到所有进程.zip > Win32Process.cpp


// Win32Process.cpp: implementation of the Win32Process class. 
// 
////////////////////////////////////////////////////////////////////// 
 
/******************************************************************************\ 
		Win32Process: a Win95/NT-compatible class for acquiring the list 
		of currently active processes. 
		Copyright (C) 1998 Tomer Petel 
		You may modify and/or integrate this code into your commercial software 
		for free in exchange for a small e-mail, just so I can know 
		if this code ever became useful to someone else but me. 
		email to: tomerp@eng2.uconn.edu 
\******************************************************************************/ 
 
#include "stdafx.h" 
#include "Win32Process.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
Win32Process::Win32Process() 
{ 
	m_p_fnProcess32Next=NULL; 
	m_p_fnProcess32First=NULL; 
	m_p_fnCreateToolhelp32Snapshot=NULL; 
} 
 
Win32Process::~Win32Process() 
{ 
	m_strArray.RemoveAll(); 
} 
 
bool Win32Process::Init() 
{ 
	DWORD dwVersion = ::GetVersion(); 
 
   // Windows NT? 
   if(dwVersion < 0x80000000)  
       // Yes, Windows NT 
	   m_bIsNt=true; 
    // Windows 95? 
   else if(LOBYTE(LOWORD(dwVersion)) >= 4)  
	   m_bIsNt=false; 
   else 
   { 
	   m_strLastError=_T("Unsupported OS version"); 
	   return false;  // Win16, 32s or NT3.x. 
   } 
   ////if its Win95, we must get the appropriate function pointers... 
   ////This esnures that we dont tie up to a specific Compiler option, and that we can run on 
   ////both 95 or NT (because NT does not have the following procedures in its kernel32.dll) 
  
   if (!m_bIsNt) 
   {  
		//// If here, We are running on Win95. Must use the tool help functions.... 
 
		m_hWin95Kernel=GetModuleHandle(_T("kernel32.dll")); 
		if(!m_hWin95Kernel) 
		{ 
			m_strLastError=_T("Could not get kernel32 handle"); 
			return false; 
		} 
		m_p_fnCreateToolhelp32Snapshot=(PFN_CREATETHELP32SNPSHT)GetProcAddress(m_hWin95Kernel,"CreateToolhelp32Snapshot"); 
		if (!m_p_fnCreateToolhelp32Snapshot) 
		{ 
			m_strLastError=_T("Could not get CreateToolhelp32Snapshot pointer"); 
			return false; 
		} 
 
		m_p_fnProcess32First=(PFN_PROCESS32FIRST)GetProcAddress(m_hWin95Kernel,"Process32First"); 
		if (!m_p_fnProcess32First) 
		{ 
			m_strLastError=_T("Could not get Process32First pointer"); 
			return false; 
		} 
 
		m_p_fnProcess32Next=(PFN_PROCESS32NEXT)GetProcAddress(m_hWin95Kernel,"Process32Next"); 
		if (!m_p_fnProcess32Next) 
		{ 
			m_strLastError=_T("Could not get Process32Next pointer"); 
			return false; 
		} 
 
   } 
   return true; 
 
} 
 
bool Win32Process::GetProcessStatus(CString* procname, bool* status) 
{ 
	/// On exit from this pprocedure, status will be true if the process under question is alive... 
	if (m_bIsNt) 
	{ 
		if(FindProcessesNT(procname,true)) 
		{ 
			*status=m_bActive; 
			return true; 
		} 
		else  
			return false; 
	} 
	else 
	{ 
		//we are on Win95... 
		//make the process name lower case, since we anyway cannot deal with case differences in Win95 ToolHelp functions... 
		procname->MakeLower(); 
		if (FindProcesses95(procname,true)) 
		{ 
			*status=m_bActive; 
			return true; 
		} 
		else  
			return false; 
	} 
 
		 
} 
 
bool Win32Process::EnumAllProcesses() 
{ 
	if (m_bIsNt) 
		//we are on NT 
		return FindProcessesNT(NULL,false); 
	else		 
		//we are on Win95... 
		return FindProcesses95(NULL,false); 
	 
} 
 
CString Win32Process::GetLastError() 
{ 
	return m_strLastError; 
} 
 
CStringArray* Win32Process::GetAllProcessesNames() 
{ 
	//returns an MFC string array pointer, containint all the processes names... 
	return &m_strArray; 
} 
 
 
bool Win32Process::FindProcessesNT(CString* ProcessName, bool bJustCheckingOne) 
{ 
	///This function gets all the running process, the winNT way, using the 
	///registry. If you simply are checking if a process is active 
	///pass its name as a parameter and make the second parameter false. 
	///Otherwise, the function will ignore the ProcessName param and add to the array 
	///all the currently active processes... 
	 
	if (!bJustCheckingOne) 
	{ 
		m_strArray.RemoveAll(); 
	} 
	else 
	{ 
		m_bActive=false; 
		ASSERT ((*ProcessName)!=""); ///If just checking if a process is alive, this must be the process' name 
	} 
  
	//This following was coded using the tlist example, but is it optimized,  
	//to only search for processes names. 
 
	bool						 bErrorOccured=false; 
	DWORD                        rc; 
    HKEY                         hKeyNames; 
    DWORD                        dwType; 
    DWORD                        dwSize; 
    LPBYTE                       buf = NULL; 
    TCHAR                        szSubKey[1024]; 
    LANGID                       lid; 
    LPSTR                        p; 
    LPSTR                        p2; 
    PPERF_DATA_BLOCK             pPerf; 
    PPERF_OBJECT_TYPE            pObj; 
    PPERF_INSTANCE_DEFINITION    pInst; 
    PPERF_COUNTER_BLOCK          pCounter; 
    DWORD                        i; 
    TCHAR                         szProcessName[MAX_PATH]; 
    DWORD                        dwLimit = 256; 
	DWORD dwNumTasks; 
    lid = MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL); 
    _stprintf( szSubKey, _T("%s\\%03x"), REGKEY_PERF, lid ); 
    rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
                       szSubKey, 
                       0, 
                       KEY_READ, 
                       &hKeyNames 
                     ); 
    if (rc != ERROR_SUCCESS) 
	{ 
		bErrorOccured=true; 
		m_strLastError=_T("Could not open performance registry key"); 
        goto exit; 
 
    } 
 
    // 
    // get the buffer size for the counter names 
    // 
    rc = RegQueryValueEx(hKeyNames, 
                          REGSUBKEY_COUNTERS, 
                          NULL, 
                          &dwType, 
                          NULL, 
                          &dwSize 
                        ); 
 
    if (rc != ERROR_SUCCESS) 
	{ 
		bErrorOccured=true; 
		m_strLastError=_T("Could not open counter registry key"); 
        goto exit; 
    } 
 
    // 
    // allocate the counter names buffer 
    // 
    buf = (LPBYTE) malloc(dwSize); 
    if (buf == NULL) 
	{ 
		bErrorOccured=true; 
		m_strLastError=_T("Out of Memory"); 
        goto exit; 
    } 
    memset(buf, 0, dwSize); 
 
    // 
    // read the counter names from the registry 
    // 
    rc = RegQueryValueEx( hKeyNames, 
                          REGSUBKEY_COUNTERS, 
                          NULL, 
                          &dwType, 
                          buf, 
                          &dwSize 
                        ); 
 
    if (rc != ERROR_SUCCESS)  
	{ 
		bErrorOccured=true; 
		m_strLastError=_T("Could Not Read the counter Names"); 
        goto exit; 
    } 
 
    // 
    // now loop thru the counter names looking for the "Process" counters: 
    // the buffer contains multiple null terminated strings and then 
    // finally null terminated at the end.  the strings are in pairs of 
    // counter number and counter name. 
    // 
 
    p =(LPSTR) buf; 
    while (*p)  
	{ 
        if (p > (LPSTR)buf)  
		{ 
            for( p2=p-2; _istdigit(*p2); p2--) 
						; 
        } 
        if (_tcsicmp(p, PROCESS_COUNTER) == 0) 
		{ 
            // look backwards for the counter number 
            for(p2=p-2; _istdigit(*p2); p2--)  
						; 
            _tcscpy(szSubKey, p2+1); 
        } 
        p += (_tcslen(p) + 1); 
    } 
 
 
    // free the counter names buffer 
    free(buf); 
 
 
    // allocate the initial buffer for the performance data 
 
    dwSize = INITIAL_SIZE; 
    buf = (LPBYTE)malloc( dwSize ); 
    if (buf == NULL) 
	{ 
		bErrorOccured=true; 
		m_strLastError=_T("Out of Memory"); 
        goto exit; 
    } 
    memset(buf, 0, dwSize); 
    while (true) 
	{ 
 
        rc = RegQueryValueEx( HKEY_PERFORMANCE_DATA, 
                              szSubKey, 
                              NULL, 
                              &dwType, 
                              buf, 
                              &dwSize 
                            ); 
 
        pPerf = (PPERF_DATA_BLOCK) buf; 
 
        // check for success and valid perf data block signature 
 
        if ((rc == ERROR_SUCCESS) && 
            (dwSize > 0) && 
            (pPerf)->Signature[0] == (WCHAR)'P' && 
            (pPerf)->Signature[1] == (WCHAR)'E' && 
            (pPerf)->Signature[2] == (WCHAR)'R' && 
            (pPerf)->Signature[3] == (WCHAR)'F' ) 
		{ 
            break; 
        } 
 
        // if buffer is not big enough, reallocate and try again 
 
        if (rc == ERROR_MORE_DATA) 
		{ 
            dwSize += EXTEND_SIZE; 
            buf = (LPBYTE)realloc( buf, dwSize ); 
            memset( buf, 0, dwSize ); 
        } 
        else  
		{ 
			bErrorOccured=true; 
			m_strLastError=_T("Could Not Obtain Performance Data"); 
			goto exit; 
        } 
    } 
 
    // set the perf_object_type pointer 
 
    pObj = (PPERF_OBJECT_TYPE) ((DWORD)pPerf + pPerf->HeaderLength); 
    dwNumTasks = min( dwLimit, (DWORD)pObj->NumInstances ); 
    pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD)pObj + pObj->DefinitionLength); 
 
    // loop thru the performance instance data extracting each process name 
 
    for (i=0; iNameOffset); 
 
        // 
        // convert it to ascii 
        // 
        rc = WideCharToMultiByte( CP_ACP, 
                                  0, 
                                  (LPCWSTR)p, 
                                  -1, 
                                  szProcessName, 
                                  sizeof(szProcessName), 
                                  NULL, 
                                  NULL 
                                ); 
 
		if (rc) 
		{ 
			if (bJustCheckingOne) 
			{ 
				if (ProcessName->CompareNoCase(szProcessName)==0) 
				{	//found the process. It is running! 
					m_bActive=true; 
					goto exit; 
				} 
			} 
			else 
   				m_strArray.Add(szProcessName); 
		} 
        // get the process id 
        pCounter = (PPERF_COUNTER_BLOCK) ((DWORD)pInst + pInst->ByteLength); 
        // next process 
        pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD)pCounter + pCounter->ByteLength); 
    } 
 
exit: 
    if (buf)  
	{ 
        free(buf); 
    } 
 
    RegCloseKey(hKeyNames); 
    RegCloseKey(HKEY_PERFORMANCE_DATA); 
	return !bErrorOccured; 
 
} 
 
 
bool Win32Process::FindProcesses95(CString* ProcessName, bool bJustCheckingOne) 
{ 
	///This function gets all the running process, the win95 way, using the 
	///ToolHelp functions. If you simply are checking if a process is active 
	///pass its name as a parameter and make the second parameter false. 
	///Otherwise, the function will ignore the ProcessName param and add to the array 
	///all the currently active processes... 
	ASSERT(m_p_fnProcess32Next); 
	ASSERT(m_p_fnProcess32First); 
	ASSERT(m_p_fnCreateToolhelp32Snapshot);	   ///must have successfully called Init() first 
 
	 
	if (!bJustCheckingOne) 
	{ 
		m_strArray.RemoveAll(); 
	} 
	else 
	{ 
		m_bActive=false; 
		ASSERT ((*ProcessName)!=""); ///If just checking if a process is alive, this must be the process' name 
	} 
	HANDLE handle; 
	handle=m_p_fnCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); 
	if ((const int)handle==-1) 
	{ 
		m_strLastError=_T("Failed in creating snapshot"); 
		return false; 
	} 
 
	PROCESSENTRY32 process; 
	process.dwSize=sizeof(PROCESSENTRY32); 
 
	BOOL bContinue=m_p_fnProcess32First(handle,&process); 
 
	while(bContinue) 
	{ 
		if (!bJustCheckingOne) //do we want to enumerate all processes, or do we just wanna check if one is active? 
			m_strArray.Add(ExtractProcessName(process.szExeFile)); 
		else 
		{ 
			///if here, then we are just looking to see if a certain process is alive... 
			if ((*ProcessName)==ExtractProcessName(process.szExeFile)) 
			{ 
				///found the process, it is active.... 
				CloseHandle(handle);	 
				m_bActive=true; 
				return true; 
			} 
		} 
		bContinue=m_p_fnProcess32Next(handle,&process); 
	} 
 
	CloseHandle(handle);		 
	return true; 
} 
 
bool Win32Process::IsWinNT() 
{ 
	return m_bIsNt; 
} 
 
TCHAR * Win32Process::ExtractProcessName(TCHAR * path) 
{ 
	//gets the process name out of the whole path name and makes it lower case. 
	//this is only necessary in WIN95 since the ToolHelp functions return  
	//the entire path of the executable, in upper case... 
 
	ASSERT (path); 
	TCHAR *p, *tmp=_tcsrchr (path, '\\'); 
	if (tmp) 
	{	 
		tmp++; //get after the backslash 
		p=_tcsrchr (tmp, '.'); 
		*p=0;				  //get rid of the .exe extension 
		return (_tcslwr(tmp)); //make it lower case and return it. 
	} 
	else	 //couldnt find the backslash: just deal with the .exe: 
	{ 
		p=_tcsrchr (path, '.'); 
		*p=0;				  //get rid of the .exe extension 
		return (_tcslwr(path)); //make it lower case and return it. 
	} 
}