繁体   English   中英

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

[英]C++, How to determine if a Windows Process is running?

这与 Windows XP 进程有关。

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

现在,在某些时候 Process1 想要 Process2 做某事,所以它首先需要确保 Process2 还活着并且用户没有杀死它。

如何检查此进程是否仍在运行? 由于我创建了它,我有进程 ID,我认为有一些库 function 沿着 IsProcessIDValid(id) 的行,但我在 MSDN 上找不到它

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

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

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

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)在进程退出时接收回调。

编辑:我错过了原始问题的“想要对流程做些什么”部分。 如果可以为某个小窗口保留潜在的陈旧数据,或者如果您想在不尝试的情况下使操作失败,则可以使用此技术。 您仍然需要处理由于进程已退出而导致操作失败的情况。

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

正如评论中所指出的, @user152949 提供解决方案会跳过第一个过程,并且在“exists”设置为 true 时不会中断。 让我提供一个固定版本:

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

bool IsProcessRunning(const TCHAR* const executableName) {
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);

    const auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

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

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

    CloseHandle(snapshot);
    return false;
}

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

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

我今天发现了这个,它是 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;

}

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

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

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

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

JaredPar 是对的,因为您无法知道进程是否正在运行。 您只能知道在您检查时该进程是否正在运行。 在此期间它可能已经死亡。

您还必须意识到 PID 可以很快被回收。 因此,仅仅因为有一个带有您的 PID 的进程,并不意味着它是您的进程。

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

您可以通过简单地通过CreateToolhelp32Snapshot 获取正在运行的进程的快照并在该快照上使用 Process32First 和 Process32Next 对正在运行的进程进行迭代来确定进程(给定其名称或 PID)是否正在运行。

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

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

仅仅为了使用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 感觉很脏:/

这是我过去使用过的解决方案。 虽然这里的例子是在 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
char tmp[200] = "taskkill /f /im chrome.exe && \"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe\"

while (1)
{
    FILE* f;
    f = _popen("tasklist", "r");

    char b[512];
    bzero(b, 512);

    while (fgets(b, 512, f) != NULL)
    {
        if (strncmp(b, "chrome.exe", 8) == 0)
        {
            printf("Chrome running!\n");
            system(tmp);
        }
        else
        {
            printf("Chrome NOT running!\n");
        }
    }
    Sleep(1000);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM