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

时间:2009-10-19 21:52:46

标签: c++ windows process

这与Windows XP进程有关。

我正在运行一个进程,我们称之为Process1。 Process1创建一个新进程Process2,并保存其id。

现在,在某些时候Process1希望Process2做一些事情,所以它首先需要确保Process2仍然存在并且用户还没有杀死它。

如何检查此进程是否仍在运行? 自从我创建它以来,我有进程ID,我认为有一些库函数沿着IsProcessIDValid(id)但我在MSDN上找不到它

13 个答案:

答案 0 :(得分:65)

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

答案 1 :(得分:34)

如果进程句柄退出,将发出信号。

因此以下内容将起作用(为简洁起见,删除了错误处理):

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

请注意,进程ID可以回收 - 最好缓存从CreateProcess调用返回的句柄。

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

编辑:我错过了原来问题的“想要对过程做点什么”的一部分。如果可以为某个小窗口提供可能过时的数据,或者如果您想在没有尝试的情况下使操作失败,则可以使用此技术。您仍然需要处理操作失败的情况,因为该进程已退出。

答案 2 :(得分:18)

#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;
}

答案 3 :(得分:6)

监视子进程的另一种方法是创建一个工作线程:

  1. 调用CreateProcess()
  2. 调用WaitForSingleObject()//工作线程现在将等待,直到子进程完成执行。也可以获取返回代码(来自main()函数)。

答案 4 :(得分:5)

我今天发现了这一点,它是从2003年开始的。它按名称找到了一个进程,你甚至不需要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, i.e. "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;

}

答案 5 :(得分:3)

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

最好的方法是只执行所需的操作并捕获在进程未运行时将引发的异常。

答案 6 :(得分:1)

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

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

答案 7 :(得分:1)

JaredPar是正确的,你不知道该进程是否正在运行。您只能在检查时知道进程是否正在运行。它可能已经在同一时间内死亡。

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

让进程共享GUID。 (进程1可以生成GUID并将其传递给命令行上的进程2.)进程2应该使用该GUID创建一个命名的互斥锁。当进程1要检查时,它可以在互斥锁上执行WaitForSingleObject并超时0。如果进程2消失,返回代码将告诉您该互斥锁已被放弃,否则您将超时。

答案 8 :(得分:1)

在编写监控工具时,我采用了略微不同的方法。

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

我正在使用GetProcessTimes():

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

只有进程实际退出时,GetProcessTimes()才会返回进程的ExitTime的FILETIME结构。因此,只需检查是否填充了ExitTime结构,以及时间是否为0;

这个解决方案应该考虑到一个进程被杀死但是它的PID被另一个进程重用的情况。 GetProcessTimes需要一个进程句柄,而不是PID。所以操作系统应该知道句柄是针对某个时刻正在运行的进程,而不是更多,并且给你退出时间。

依赖于ExitCode感觉很脏:/

答案 9 :(得分:1)

TL; DR使用GetProcessVersion

所有这些功能都可以在Windows XP中使用。 UWP应用]。

GetProcessVersion使用进程ID,如果给定ID的进程未运行,则返回0。

GetExitCodeProcess使用Process句柄并为您提供进程退出代码,如果该代码是STILL_ACTIVE(259),则该进程仍在运行,因此您可以检查它是否不是STILL_ACTIVE(259),这意味着该进程正在运行。没有运行。除非该过程以代码259退出,否则这基本上可能在每种情况下都有效。

WaitForSingleObject使用具有SYNCHRONIZE访问权限的Process句柄,如果该进程未运行,则返回0。您不应该为dwMilliseconds参数指定INFINITE,因为该功能只有在发出过程状态信号(过程终止)后才会返回。

答案 10 :(得分:0)

您可以通过迭代正在运行的进程来查找进程(给定其名称或PID)是否正在运行,只需通过CreateToolhelp32Snapshot获取正在运行的进程的快照,并使用Process32First和Process32Next调用快照。

然后,您可以使用生成的PROCESSENTRY32结构的th32ProcessID字段或szExeFile字段,具体取决于您是要按PID还是可执行名称进行搜索。可以找到一个简单的实现here

答案 11 :(得分:0)

这是我过去使用的解决方案。虽然这里的例子是在VB.net中 - 我已经将这种技术用于c和c ++。它绕过了Process ID&amp ;;的所有问题。处理句柄和返回代码。无论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

答案 12 :(得分:0)

如评论中所述,solution provided by @user152949将跳过第一个过程,并且在将“ exists”设置为true时不会中断。让我提供一个固定版本:

#include <windows.h>
#include <tlhelp32.h>

bool IsProcessRunning(const wchar_t* const processName) {
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);

    const auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

    if (!Process32First(snapshot, &entry)) {
        CloseHandle(snapshot);
        return false;
    }

    do {
        if (!_wcsicmp(entry.szExeFile, processName)) {
            CloseHandle(snapshot);
            return true;
        }
    } while (Process32Next(snapshot, &entry));

    CloseHandle(snapshot);
    return false;
}