C ++,如何确定Windows进程正在运行?

这与Windows XP进程有关。

我有一个进程正在运行,我们称之为Process1。 Process1创build一个新的进程Process2,并保存其ID。

现在,Process1需要Process2做某件事情,所以首先需要确保Process2仍然活着,并且用户还没有把它杀死。

我如何检查这个过程是否仍在运行? 自从我创build它,我有进程ID,我会认为有一些库函数沿着IsProcessIDValid(id)的行,但我无法find它在MSDN

您可以使用GetExitCodeProcess 。 如果进程仍在运行(或者如果它以退出代码:()退出,它将返回STILL_ACTIVE259 )。

进程句柄将在退出时发出信号。

因此,以下将工作(error handling删除简洁):

 BOOL IsProcessRunning(DWORD pid) { HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid); DWORD ret = WaitForSingleObject(process, 0); CloseHandle(process); return ret == WAIT_TIMEOUT; } 

请注意,进程ID可以被回收 – 最好是caching从CreateProcess调用返回的句柄。

您还可以使用线程池API(Vista +上的SetThreadpoolWait,旧版平台上的RegisterWaitForSingleObject)在进程退出时接收callback。

编辑:我错过了“想做一些事情的过程”原来的问题的一部分。 如果某些小窗口可能有陈旧的数据,或者如果您甚至不尝试操作,就可以使用这种技术。 您将仍然需要处理由于stream程已经退出而导致操作失败的情况。

 #include <cstdio> #include <windows.h> #include <tlhelp32.h> /*! \brief Check if a process is running \param [in] processName Name of process to check if is running \returns \c True if the process is running, or \c False if the process is not running */ bool IsProcessRunning(const wchar_t *processName) { bool exists = false; PROCESSENTRY32 entry; entry.dwSize = sizeof(PROCESSENTRY32); HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); if (Process32First(snapshot, &entry)) while (Process32Next(snapshot, &entry)) if (!wcsicmp(entry.szExeFile, processName)) exists = true; CloseHandle(snapshot); return exists; } 

监视subprocess的另一种方法是创build一个工作线程,该线程将:

  1. 调用CreateProcess()
  2. 调用WaitForSingleObject()//工作线程现在将等待subprocess完成执行。 也可以从main()函数中获取返回码。

我今天发现这个,从2003年开始,它find了一个名字的过程,你甚至不需要这个PID。

 \#include windows.h \#include tlhelp32.h \#include iostream.h int FIND_PROC_BY_NAME(const char *); int main(int argc, char *argv[]) { // Check whether a process is currently running, or not char szName[100]="notepad.exe"; // Name of process to find int isRunning; isRunning=FIND_PROC_BY_NAME(szName); // Note: isRunning=0 means process not found, =1 means yes, it is found in memor return isRunning; } int FIND_PROC_BY_NAME(const char *szToFind) // Created: 12/29/2000 (RK) // Last modified: 6/16/2003 (RK) // Please report any problems or bugs to kochhar@physiology.wisc.edu // The latest version of this routine can be found at: // http://www.neurophys.wisc.edu/ravi/software/killproc/ // Check whether the process "szToFind" is currently running in memory // This works for Win/95/98/ME and also Win/NT/2000/XP // The process name is case-insensitive, ie "notepad.exe" and "NOTEPAD.EXE" // will both work (for szToFind) // Return codes are as follows: // 0 = Process was not found // 1 = Process was found // 605 = Unable to search for process // 606 = Unable to identify system type // 607 = Unsupported OS // 632 = Process name is invalid // Change history: // 3/10/2002 - Fixed memory leak in some cases (hSnapShot and // and hSnapShotm were not being closed sometimes) // 6/13/2003 - Removed iFound (was not being used, as pointed out // by John Emmas) { BOOL bResult,bResultm; DWORD aiPID[1000],iCb=1000,iNumProc,iV2000=0; DWORD iCbneeded,i; char szName[MAX_PATH],szToFindUpper[MAX_PATH]; HANDLE hProc,hSnapShot,hSnapShotm; OSVERSIONINFO osvi; HINSTANCE hInstLib; int iLen,iLenP,indx; HMODULE hMod; PROCESSENTRY32 procentry; MODULEENTRY32 modentry; // PSAPI Function Pointers. BOOL (WINAPI *lpfEnumProcesses)( DWORD *, DWORD cb, DWORD * ); BOOL (WINAPI *lpfEnumProcessModules)( HANDLE, HMODULE *, DWORD, LPDWORD ); DWORD (WINAPI *lpfGetModuleBaseName)( HANDLE, HMODULE, LPTSTR, DWORD ); // ToolHelp Function Pointers. HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD) ; BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32) ; BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32) ; BOOL (WINAPI *lpfModule32First)(HANDLE,LPMODULEENTRY32) ; BOOL (WINAPI *lpfModule32Next)(HANDLE,LPMODULEENTRY32) ; // Transfer Process name into "szToFindUpper" and // convert it to upper case iLenP=strlen(szToFind); if(iLenP<1 || iLenP>MAX_PATH) return 632; for(indx=0;indx<iLenP;indx++) szToFindUpper[indx]=toupper(szToFind[indx]); szToFindUpper[iLenP]=0; // First check what version of Windows we're in osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); bResult=GetVersionEx(&osvi); if(!bResult) // Unable to identify system version return 606; // At Present we only support Win/NT/2000 or Win/9x/ME if((osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) && (osvi.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)) return 607; if(osvi.dwPlatformId==VER_PLATFORM_WIN32_NT) { // Win/NT or 2000 or XP // Load library and get the procedures explicitly. We do // this so that we don't have to worry about modules using // this code failing to load under Windows 95, because // it can't resolve references to the PSAPI.DLL. hInstLib = LoadLibraryA("PSAPI.DLL"); if(hInstLib == NULL) return 605; // Get procedure addresses. lpfEnumProcesses = (BOOL(WINAPI *)(DWORD *,DWORD,DWORD*)) GetProcAddress( hInstLib, "EnumProcesses" ) ; lpfEnumProcessModules = (BOOL(WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( hInstLib, "EnumProcessModules" ) ; lpfGetModuleBaseName =(DWORD (WINAPI *)(HANDLE, HMODULE, LPTSTR, DWORD )) GetProcAddress( hInstLib, "GetModuleBaseNameA" ) ; if( lpfEnumProcesses == NULL || lpfEnumProcessModules == NULL || lpfGetModuleBaseName == NULL) { FreeLibrary(hInstLib); return 605; } bResult=lpfEnumProcesses(aiPID,iCb,&iCbneeded); if(!bResult) { // Unable to get process list, EnumProcesses failed FreeLibrary(hInstLib); return 605; } // How many processes are there? iNumProc=iCbneeded/sizeof(DWORD); // Get and match the name of each process for(i=0;i<iNumProc;i++) { // Get the (module) name for this process strcpy(szName,"Unknown"); // First, get a handle to the process hProc=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE, aiPID[i]); // Now, get the process name if(hProc) { if(lpfEnumProcessModules(hProc,&hMod,sizeof(hMod),&iCbneeded) ) { iLen=lpfGetModuleBaseName(hProc,hMod,szName,MAX_PATH); } } CloseHandle(hProc); // Match regardless of lower or upper case if(strcmp(_strupr(szName),szToFindUpper)==0) { // Process found FreeLibrary(hInstLib); return 1; } } } if(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS) { // Win/95 or 98 or ME hInstLib = LoadLibraryA("Kernel32.DLL"); if( hInstLib == NULL ) return FALSE ; // Get procedure addresses. // We are linking to these functions of Kernel32 // explicitly, because otherwise a module using // this code would fail to load under Windows NT, // which does not have the Toolhelp32 // functions in the Kernel 32. lpfCreateToolhelp32Snapshot= (HANDLE(WINAPI *)(DWORD,DWORD)) GetProcAddress( hInstLib, "CreateToolhelp32Snapshot" ) ; lpfProcess32First= (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32)) GetProcAddress( hInstLib, "Process32First" ) ; lpfProcess32Next= (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32)) GetProcAddress( hInstLib, "Process32Next" ) ; lpfModule32First= (BOOL(WINAPI *)(HANDLE,LPMODULEENTRY32)) GetProcAddress( hInstLib, "Module32First" ) ; lpfModule32Next= (BOOL(WINAPI *)(HANDLE,LPMODULEENTRY32)) GetProcAddress( hInstLib, "Module32Next" ) ; if( lpfProcess32Next == NULL || lpfProcess32First == NULL || lpfModule32Next == NULL || lpfModule32First == NULL || lpfCreateToolhelp32Snapshot == NULL ) { FreeLibrary(hInstLib); return 605; } // The Process32.. and Module32.. routines return names in all uppercase // Get a handle to a Toolhelp snapshot of all the systems processes. hSnapShot = lpfCreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ) ; if( hSnapShot == INVALID_HANDLE_VALUE ) { FreeLibrary(hInstLib); return 605; } // Get the first process' information. procentry.dwSize = sizeof(PROCESSENTRY32); bResult=lpfProcess32First(hSnapShot,&procentry); // While there are processes, keep looping and checking. while(bResult) { // Get a handle to a Toolhelp snapshot of this process. hSnapShotm = lpfCreateToolhelp32Snapshot( TH32CS_SNAPMODULE, procentry.th32ProcessID) ; if( hSnapShotm == INVALID_HANDLE_VALUE ) { CloseHandle(hSnapShot); FreeLibrary(hInstLib); return 605; } // Get the module list for this process modentry.dwSize=sizeof(MODULEENTRY32); bResultm=lpfModule32First(hSnapShotm,&modentry); // While there are modules, keep looping and checking while(bResultm) { if(strcmp(modentry.szModule,szToFindUpper)==0) { // Process found CloseHandle(hSnapShotm); CloseHandle(hSnapShot); FreeLibrary(hInstLib); return 1; } else { // Look for next modules for this process modentry.dwSize=sizeof(MODULEENTRY32); bResultm=lpfModule32Next(hSnapShotm,&modentry); } } //Keep looking CloseHandle(hSnapShotm); procentry.dwSize = sizeof(PROCESSENTRY32); bResult = lpfProcess32Next(hSnapShot,&procentry); } CloseHandle(hSnapShot); } FreeLibrary(hInstLib); return 0; } 

您无法检查并查看进程是否正在运行,您只能检查最近过去某个进程是否正在运行。 进程是一个不受应用程序控制的实体,可以随时退出。 没有办法保证一个进程不会在检查之间退出,看它是否正在运行以及相应的操作。

最好的方法是只做需要的操作,并捕获如果进程没有运行就会抛出的exception。

调用EnumProcesses()并检查PID是否在列表中。

http://msdn.microsoft.com/en-us/library/ms682629%28VS.85%29.aspx

JaredPar是正确的,你不知道这个过程是否正在运行。 你只能知道你检查的时候进程是否正在运行。 它可能同时死亡。

您也必须意识到PID可以很快回收。 所以只是因为你的PID有一个过程,并不意味着它是你的过程。

让进程共享一个GUID。 (进程1可以生成GUID并将它传递给进程2在命令行上。)进程2应该创build一个具有该GUID的已命名互斥体。 当进程1想要检查时,它可以在一个0超时的互斥体上执行WaitForSingleObject 。 如果进程2没有了,返回代码会告诉你这个互斥体被放弃了,否则你会得到一个超时。

在编写监测工具时,我采取了一种稍微不同的方法。

为了使用WaitForSingleObject或者甚至使用RegisterWaitForSingleObject(这样做对你来说),启动一个额外的线程感觉有点浪费。 因为在我的情况下,我不需要知道一个过程已经结束的确切时刻,只是它已经closures了。

我正在使用GetProcessTimes()来代替:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms683223(v=vs.85).aspx

只有在进程已经退出时,GetProcessTimes()才会为进程的ExitTime返回一个FILETIME结构体。 所以只需要检查ExitTime结构是否被填充,如果时间不是0;

这个解决scheme应该说明一个进程已经被杀死的情况,但是PID被另一个进程重用。 GetProcessTimes需要一个进程的句柄,而不是PID。 所以操作系统应该知道句柄是在某个时刻运行的进程,但不再是这个进程,并且给你退出的时间。

依靠ExitCode感觉脏:/

您可以通过简单地通过CreateToolhelp32Snapshot获取正在运行的进程的快照,以及在该快照上使用Process32First和Process32Next调用来遍历正在运行的进程,从而发现进程(给定其名称或PID)是否正在运行。

然后,您可以使用生成的PROCESSENTRY32结构体的th32ProcessID字段或szExeFile字段,具体取决于是否要按PID或可执行文件名进行search。 一个简单的实现可以在这里find。

这是我过去使用的解决scheme。 虽然这里的例子是在VB.net中 – 我用这个技术与C和C + +。 它绕过进程ID和进程句柄的所有问题,并返回代码。 无论Process2如何终止,Windows都非常忠实地释放互斥锁。 我希望对某个人有帮助

 **PROCESS1 :-** Randomize() mutexname = "myprocess" & Mid(Format(CDbl(Long.MaxValue) * Rnd(), "00000000000000000000"), 1, 16) hnd = CreateMutex(0, False, mutexname) ' pass this name to Process2 File.WriteAllText("mutexname.txt", mutexname) <start Process2> <wait for Process2 to start> pr = WaitForSingleObject(hnd, 0) ReleaseMutex(hnd) If pr = WAIT_OBJECT_0 Then <Process2 not running> Else <Process2 is running> End If ... CloseHandle(hnd) EXIT **PROCESS2 :-** mutexname = File.ReadAllText("mutexname.txt") hnd = OpenMutex(MUTEX_ALL_ACCESS Or SYNCHRONIZE, True, mutexname) ... ReleaseMutex(hnd) CloseHandle(hnd) EXIT