it-swarm.com.de

C++, So stellen Sie fest, ob ein Windows-Prozess ausgeführt wird?

Dies betrifft Windows XP - Prozesse.

Ich habe einen Prozess, nennen wir es Process1. Process1 erstellt einen neuen Prozess, Process2, und speichert seine ID.

Nun, zu einem bestimmten Zeitpunkt möchte Process1, dass Process2 etwas tut, und es muss zuerst sichergestellt werden, dass Process2 noch aktiv ist und der Benutzer es nicht beendet hat.

Wie kann ich überprüfen, ob dieser Prozess noch läuft? Seit ich ihn erstellt habe, habe ich die Prozess-ID. Ich denke, es gibt einige Bibliotheksfunktionen im Sinne von IsProcessIDValid (id), aber ich kann sie nicht in MSDN finden

52
Pedro

Sie können GetExitCodeProcess verwenden. Es wird STILL_ACTIVE (259) zurückgegeben, wenn der Prozess noch läuft (oder der Exit-Code beendet wurde: ()).

63
Dolphin

Das Prozess-Handle wird signalisiert, wenn es beendet wird.

Folgendes wird also funktionieren (Fehlerbehandlung aus Gründen der Kürze entfernt):

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

Beachten Sie, dass Prozess-IDs wiederverwendet werden können. Es ist besser, das Handle zwischenzuspeichern, das vom CreateProcess-Aufruf zurückgegeben wird.

Sie können auch die Threadpool-APIs (SetThreadpoolWait unter Vista +, RegisterWaitForSingleObject auf älteren Plattformen) verwenden, um einen Rückruf zu erhalten, wenn der Prozess beendet wird.

EDIT: Ich habe den Teil der ursprünglichen Frage "Ich möchte etwas für den Prozess tun" vermisst. Sie können diese Technik verwenden, wenn potenziell veraltete Daten für ein kleines Fenster vorhanden sind oder wenn Sie einen Vorgang fehlschlagen lassen möchten, ohne es zu versuchen. Sie müssen immer noch den Fall behandeln, bei dem die Aktion fehlschlägt, weil der Prozess beendet wurde.

34
Michael
#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;
}
17
user152949

Eine andere Möglichkeit, einen untergeordneten Prozess zu überwachen, besteht darin, einen Arbeitsthread zu erstellen, der Folgendes ermöglicht:

  1. aufruf CreateProcess ()
  2. call WaitForSingleObject () // Der Worker-Thread wartet jetzt, bis die Ausführung des untergeordneten Prozesses abgeschlossen ist. Es ist auch möglich, den Rückkehrcode (von der Funktion main ()) zu übernehmen.
6
Maciek

Ich habe das heute gefunden, es ist von 2003. Es findet einen Prozess mit Namen, Sie brauchen nicht einmal die 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;

}
5
Motes

Sie können niemals prüfen, ob ein Prozess ausgeführt wird. Sie können nur prüfen, ob ein Prozess war ausgeführt wurde, der zu einem früheren Zeitpunkt ausgeführt wurde. Ein Prozess ist eine Einheit, die nicht von Ihrer Anwendung gesteuert wird und jederzeit beendet werden kann. Es gibt keine Möglichkeit sicherzustellen, dass ein Prozess nicht zwischen der Überprüfung, ob er ausgeführt wird, und der entsprechenden Aktion beendet wird.

Der beste Ansatz besteht darin, die erforderliche Aktion auszuführen und die Ausnahme abzufangen, die ausgelöst wird, wenn der Prozess nicht ausgeführt wird. 

3
JaredPar

Beim Schreiben eines Monitoring-Tools bin ich etwas anders vorgegangen.

Es war ein wenig verschwenderisch, einen zusätzlichen Thread hochzuschleudern, nur um WaitForSingleObject oder sogar das RegisterWaitForSingleObject (das tut das für Sie) zu verwenden. In meinem Fall muss ich nicht genau wissen, wann ein Prozess geschlossen wurde, nur dass er tatsächlich geschlossen wurde. 

Ich verwende stattdessen GetProcessTimes ():

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

GetProcessTimes () gibt eine FILETIME-Struktur für die ExitTime des Prozesses nur zurück, wenn der Prozess tatsächlich beendet wurde. Es ist also nur eine Frage der Überprüfung, ob die ExitTime-Struktur gefüllt ist und ob die Zeit nicht 0 ist.

Diese Lösung SOLLTE den Fall berücksichtigen, in dem ein Prozess beendet wurde, dessen PID jedoch von einem anderen Prozess wiederverwendet wurde. GetProcessTimes benötigt einen Handle für den Prozess, nicht die PID. Das Betriebssystem sollte also wissen, dass es sich um einen Punkt handelt, der zu einem bestimmten Zeitpunkt ausgeführt wurde, aber nicht mehr, und Ihnen die Beendigungszeit angibt.

Sich auf den ExitCode zu verlassen, fühlte sich schmutzig an: /

1
Andrew

Die von @ user152949 bereitgestellte Lösung überspringt, wie in Kommentaren erwähnt, den ersten Prozess und bricht nicht ab, wenn "exists" auf "true" gesetzt ist. Lassen Sie mich eine feste Version bereitstellen:

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

rufen Sie EnumProcesses() auf und prüfen Sie, ob die PID in der Liste enthalten ist.

http://msdn.Microsoft.com/de-de/library/ms682629%28VS.85%29.aspx

1
Lance Rushing

JaredPar hat recht, man kann nicht wissen, ob der Prozess läuft. Sie können nur wissen, ob der Prozess zu dem Zeitpunkt ausgeführt wurde, zu dem Sie die Überprüfung durchgeführt haben. Es könnte inzwischen gestorben sein.

Sie müssen auch wissen, dass die PIDs ziemlich schnell recycelt werden können. Nur weil es da draußen einen Prozess mit Ihrer PID gibt, heißt das nicht, dass es Ihr Prozess ist.

Haben die Prozesse eine GUID gemeinsam. (Prozess 1 könnte die GUID generieren und in der Befehlszeile an Prozess 2 übergeben.) Prozess 2 sollte einen benannten Mutex mit dieser GUID erstellen. Wenn Prozess 1 überprüfen möchte, kann er eine WaitForSingleObject auf dem Mutex mit einem Timeout von 0 durchführen. Wenn Prozess 2 nicht mehr vorhanden ist, wird der Rückgabewert Ihnen mitteilen, dass der Mutex aufgegeben wurde. Andernfalls erhalten Sie ein Timeout.

1
Adrian McCarthy

Dies ist eine Lösung, die ich in der Vergangenheit verwendet habe. Obwohl das Beispiel hier in VB.net ist - ich habe diese Technik mit c und c ++ verwendet. Es umgeht alle Probleme mit Prozess-IDs und Prozess-Handles und Rückkehrcodes. Windows ist sehr treu bei der Freigabe des Mutex, unabhängig davon, wie Process2 beendet wird. Ich hoffe es ist hilfreich für jemanden ...

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

Sie können feststellen, ob ein Prozess (mit Namen oder PID) ausgeführt wird oder nicht, indem Sie die laufenden Prozesse durchlaufen, indem Sie einfach einen Snapshot der laufenden Prozesse über CreateToolhelp32Snapshot erstellen und für diesen Snapshot Process32First- und Process32Next-Aufrufe verwenden.

Dann können Sie das th32ProcessID-Feld oder das szExeFile-Feld der resultierenden PROCESSENTRY32-Struktur verwenden, je nachdem, ob Sie nach PID oder dem Namen der ausführbaren Datei suchen möchten. Eine einfache Implementierung finden Sie hier .

0
user2001885