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

前端 未结 13 1069
清酒与你
清酒与你 2020-11-27 15:27

This is concerning Windows XP processes.

I have a process running, let\'s call it Process1. Process1 creates a new process, Process2, and saves its id.

Now,

相关标签:
13条回答
  • 2020-11-27 16:06

    You may find if a process (given its name or PID) is running or not by iterating over the running processes simply by taking a snapshot of running processes via CreateToolhelp32Snapshot, and by using Process32First and Process32Next calls on that snapshot.

    Then you may use th32ProcessID field or szExeFile field of the resulting PROCESSENTRY32 struct depending on whether you want to search by PID or executable name. A simple implementation can be found here.

    0 讨论(0)
  • 2020-11-27 16:07

    While writing a monitoring tool, i took a slightly different approach.

    It felt a bit wasteful to spin up an extra thread just to use WaitForSingleObject or even the RegisterWaitForSingleObject (which does that for you). Since in my case i don't need to know the exact instant a process has closed, just that it indeed HAS closed.

    I'm using the GetProcessTimes() instead:

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

    GetProcessTimes() will return a FILETIME struct for the process's ExitTime only if the process has actually exited. So is just a matter of checking if the ExitTime struct is populated and if the time isn't 0;

    This solution SHOULD account the case where a process has been killed but it's PID was reused by another process. GetProcessTimes needs a handle to the process, not the PID. So the OS should know that the handle is to a process that was running at some point, but not any more, and give you the exit time.

    Relying on the ExitCode felt dirty :/

    0 讨论(0)
  • 2020-11-27 16:08
    #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;
    }
    
    0 讨论(0)
  • 2020-11-27 16:21

    The solution provided by @user152949, as it was noted in commentaries, skips the first process and doesn't break when "exists" is set to true. Let me provide a fixed version:

    #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;
    }
    
    0 讨论(0)
  • 2020-11-27 16:22

    I found this today, it is from 2003. It finds a process by name, you don't even need the 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;
    
    }
    
    0 讨论(0)
  • 2020-11-27 16:24

    This is a solution that I've used in the past. Although the example here is in VB.net - I've used this technique with c and c++. It bypasses all the issues with Process IDs & Process handles, and return codes. Windows is very faithful in releasing the mutex no matter how Process2 is terminated. I hope it is helpful to someone...

    **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
    
    0 讨论(0)
提交回复
热议问题