Подтвердить что ты не робот

С++, Как определить, работает ли Windows-процесс?

Это касается процессов Windows XP.

У меня есть процесс, позвольте ему обработать Process1. Process1 создает новый процесс Process2 и сохраняет его идентификатор.

Теперь, в какой-то момент Process1 хочет, чтобы Process2 что-то сделал, поэтому сначала нужно убедиться, что Process2 все еще жив и что пользователь его не убил.

Как я могу проверить, что этот процесс все еще запущен? Поскольку я создал его, у меня есть идентификатор процесса, я бы подумал, что есть некоторая функция библиотеки по строкам IsProcessIDValid (id), но я не могу найти ее на MSDN

4b9b3361

Ответ 1

Вы можете использовать GetExitCodeProcess. Он вернет STILL_ACTIVE (259), если процесс все еще работает (или если он завершил работу с этим кодом выхода:().

Ответ 2

Обработчик процесса будет сигнализирован, если он выйдет.

Итак, будет выполнено следующее (обработка ошибок удалена для краткости):

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

Обратите внимание, что идентификатор процесса может быть переработан - лучше кэшировать дескриптор, который возвращается из вызова CreateProcess.

Вы также можете использовать API-интерфейс threadpool (SetThreadpoolWait в Vista +, RegisterWaitForSingleObject на более старых платформах) для получения обратного вызова, когда процесс завершается.

РЕДАКТИРОВАТЬ: Я пропустил часть исходного вопроса "хочу что-то сделать". Вы можете использовать эту технику, если нормально иметь потенциально устаревшие данные для небольшого окна или если вы хотите выполнить операцию, даже не пытаясь ее выполнить. Вам все равно придется обрабатывать случай, когда действие выходит из строя, потому что процесс завершился.

Ответ 3

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

Ответ 4

Другим способом мониторинга дочернего процесса является создание рабочего потока, который будет:

  • вызов CreateProcess()
  • call WaitForSingleObject()//рабочий поток теперь ожидает завершения дочернего процесса. возможно также получить код возврата (от функции main()).

Ответ 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 [email protected]

// 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;

}

Ответ 6

Вы никогда не сможете проверить и проверить, запущен ли процесс, вы можете проверить, не работает ли процесс в какой-то момент в недавнем прошлом. Процесс - это объект, который не контролируется вашим приложением и может выйти в любой момент времени. Невозможно гарантировать, что процесс не выйдет между проверкой, чтобы убедиться, что он работает, и соответствующее действие.

Лучший подход - просто выполнить требуемое действие и уловить исключение, которое будет выбрано, если процесс не был запущен.

Ответ 8

JaredPar прав, поскольку вы не можете знать, запущен ли процесс. Вы можете знать только, выполнялся ли процесс в момент проверки. Возможно, он умер в среднем.

Вы также должны знать, что PID могут быть переработаны довольно быстро. Поэтому просто потому, что там есть процесс с вашим PID, это не значит, что это ваш процесс.

У процессов есть общий идентификатор GUID. (Процесс 1 может генерировать GUID и передать его процессу 2 в командной строке.) Процесс 2 должен создать именованный мьютекс с этим GUID. Когда Process 1 хочет проверить, он может сделать WaitForSingleObject в мьютексе с таймаутом 0. Если процесс 2 ушел, код возврата скажет вам, что мьютекс был оставлен, иначе вы получите тайм-аут.

Ответ 9

При написании инструмента мониторинга я принял несколько иной подход.

Было немного расточительно развернуть дополнительный поток, чтобы использовать WaitForSingleObject или даже RegisterWaitForSingleObject (что делает это для вас). Поскольку в моем случае мне не нужно знать точное мгновение, которое процесс закрыл, просто он действительно закрыт.

Вместо этого я использую GetProcessTimes():

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

GetProcessTimes() вернет структуру FILETIME для процесса ExitTime только в том случае, если процесс действительно вышел. Так что просто проверяйте, заполнена ли структура ExitTime, и если время не равно 0;

Это решение СЛЕДУЕТ учитывать случай, когда процесс был убит, но он был повторно использован другим процессом. GetProcessTimes нуждается в дескрипторе процесса, а не в PID. Поэтому ОС должна знать, что дескриптор относится к процессу, который выполнялся в какой-то момент, но не более, и дает вам время выхода.

Полагаясь на ExitCode, он был грязным:/

Ответ 10

Вы можете найти, работает ли процесс (с его именем или PID), итерируя поверх запущенных процессов, просто сделав снимок запущенных процессов через CreateToolhelp32Snapshot, и используя вызовы Process32First и Process32Next для этого моментального снимка.

Затем вы можете использовать поле th32ProcessID или szExeFile в полученной структуре PROCESSENTRY32 в зависимости от того, хотите ли вы искать по PID или исполняемому имени. Простую реализацию можно найти здесь.

Ответ 11

Это решение, которое я использовал в прошлом. Хотя пример здесь находится в VB.net - я использовал эту технику с c и С++. Он обходит все проблемы с идентификаторами процесса и обработчиками процессов, а также возвращает коды. Windows очень верна в выпуске мьютекса независимо от того, как завершится процесс2. Надеюсь, кому-то это поможет...

**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

Решение, предоставленное пользователем @user152949, как было отмечено в комментариях, пропускает первый процесс и не прерывается, когда для "существует" задано значение "истина". Позвольте мне предоставить исправленную версию:

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