Lista procesów

Ostatania modyfikacja: 28 września 2017, kategoria: C++

Podczas pisania różnego typu trainerów do gier lub programów monitorujących system, zachodzi potrzeba wyświetlania listy procesów uruchomionych w systemie. Lista procesów dostarcza nam wielu informacji takich  jak np nazwa, identyfikator czy ID. Istnieje kilka metod na wyświetlenie uruchomionych procesów. Przedstawię wszystkie metody które znam i opiszę jedną której zawsze używam.

Funkcje wyświetlające procesy

Znam 3 sposoby umożliwiające wyświetlenie listy procesów w systemie Windows. Jeden jest funkcją konsolową, dlatego go nie używam. Pozostaje dwa to funkcje API.

  • Qprocess – jest to funkcja konsolowa, która wyświetla pełną listę uruchomionych procesów. Nie używam jej ponieważ przechwycenie strumienia wyjścia z konsoli na pewno nie jest optymalnym czasowo rozwiązaniem.
  • EnumProcesses() – nie używam tej funkcji i nie wiem o niej zbyt dużo. Kiedyś miałem z nią problem i program ciągle się sypał, gdy przepisałem wszystko na CreateToolhelp32Snapshot program zadziałał. Od tego czasu funkcja odeszła na drugi plan. Czasem występują w niej problemy związane z różnicą w systemamach 32-bit oraz 64-bit.
  • CreateToolhelp32Snapshot() – moja ulubiona funkcja. Jest prosta i skuteczna. Zapisuje wszystkie informacje o procesach do struktury PROCESSENTRY32. Strukturę można dowolnie przeglądać uzyskując odpowiednie informacje.

Działanie CreateToolhelp32Snapshot

Funkcja CreateToolhelp32Snapshot listuje wszystkie uruchomione procesy wraz ze wszystkimi informacjami. Ich obraz zostaje zapisany do specjalnej struktury PROCESSENTRY32. Strukturę można przeglądać za pomocą funkcji Process32First i Process32Next.

lista-procesów

W artykule opisuję w jaki sposób uzyskać listę procesów systemu. Jeżeli użyjemy odpowiednich argumentów podczas wywoływania CreateToolhelp32Snapshot, możemy uzyskać nie tylko listę procesów, ale także listę wątków i modułów.

Listowanie procesów

Aby móc użyć funkcji, musisz zaimportować bibliotekę tlhelp32.h i windows.h. Po zadeklarowaniu struktury PROCESSENTRY32 oraz uchwytu dla CreateToolhelp32Snapshot, wywołujemy funkcję z parametrem TH32CS_SNAPPROCESS, aby uzyskać listę procesów. Następnym krokiem jest ustawienie pola struktury PROCESSENTRY32 o nazwie dwSizeOkreśla ono rozmiar struktury. Należy to zrobić przed wywołaniem Process32First, inaczej program się wykrzaczy.

Za pierwszym razem wywołujemy funkcję Process32First, zwraca ona nazwę pierwszego procesu na liście. Z mojego doświadczenia wynika że zawsze jest to tytuł „[System Process]„. Dobrym nawykiem jest wywołanie tej funkcji w instrukcji warunkowej. Jeżeli wszystko przebiegnie pomyślnie możemy wywoływać Process32Next w pętli while, po spełnieniu warunku.

Argumentami Process32First i Process32Next są w pierwszej kolejności: uchwyt zwrócony przez CreateToolhelp32Snapshot zawierający obraz procesów, oraz wskaźnik na strukturę PROCESSENTRY32.

W pętli możemy w dowolny sposób przetwarzać rekordy struktury.

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

using namespace std;

int main()
{
    PROCESSENTRY32 proc32;  //deklaracja struktury
    HANDLE hSnapshot;       //uchwyt na CreateToolhelp32Snapshot

    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    //ustawiamy rozmiar struktury
    proc32.dwSize = sizeof(PROCESSENTRY32);

    //pierwsze wywolanie Process32First
    if(Process32First(hSnapshot, &proc32))
    {
        //wyświetlamy Process32First, czyli napis "[System Process]"
        cout << proc32.szExeFile << endl;

        //glowna petla wyświetlająca procesy przez Process32Next
        while(Process32Next(hSnapshot, &proc32))
        {
            cout << proc32.szExeFile << endl;
        }
    }

    CloseHandle(hSnapshot);

    system ("pause >nul");
    return 0;
}

Powyższy przykład wyświetli nazwy plików wykonywalnych wszystkich procesów, czyli na dobrą sprawę ich nazwy. Jest za to odpowiedzialne pole szExeFile. Oto wszystkie dostępne pola w strukturze PROCESSENTRY32:

  • dwSize – rozmiar struktury, zawsze ustawimy na sizeof(PROCESSENTRY32), jeszcze przed użyciem jakiejkolwiek funkcji, inaczej nie odpali Process32First.
  • th32ProcessID – ID procesu czyli jego unikalny identyfikator. Przy każdym uruchomieniu procesu zmienia się.
  • cntThreads – ilość wątków używanych przez dany proces.
  • th32ParentProcessID – ID procesu macierzystego, czyli tego który uruchomił aktualny proces. Dla programów, które uruchamiasz kliknięciem myszką przeważnie będzie to ID procesu explorera.
  • pcPriClassBase – priorytet procesu. Priorytety można ustawiać np. w Menedżerze Zadań Windows klikając na proces prawym klawiszem myszy.
  • szExeFile – nazwa pliku wykonywalnego procesu (użyte w przykładzie powyżej).

Jak widać bardzo prosto jest stworzyć swój menadżer procesów podobny jak w Windowsie. Musisz pamiętać, że struktura zawierająca informacje o procesach jest tylko do odczytu, nie możesz zmieniać jej zawartości.

Użytkownik Maniek napisał:

20 października 2013


Witaj , żeby sprawdzić czy dany proces jest aktualnie uruchomiony trzeba zmienić typ (proc32.szExeFile) na jakiś inny , bo jak porównuje go do normalnego stringu to nic się nie pojawia.

Użytkownik Maniek napisał:

20 października 2013


Już sobie poradziłem , wystarczyło przypisać proc32.szExeFile to zmiennej typu string.

Użytkownik Karol napisał:

20 października 2013


Sprawdzanie, czy proces jest uruchomiony bazując tylko na fladze szExeFile może okazać się niedokładne i łatwe do podrobienia, ponieważ każdy może zmienić nazwe pliku przed uruchomieniem.

Można zbadać nazwę klasy oraz użyć MUTEX’ów, jeżeli chcesz mieć pewność, że chodzi o konkretny proces.

Użytkownik Maniek napisał:

21 października 2013


Program, który pisze polega na instalowaniu programów typu firefox bez ingerencji użytkownika i do celów prywatnych, więc wystarczy jak będzie sprawdzał po nazwie pliku. Tylko teraz czy istnieje jakaś inna ciekawa funkcja do sprawdzania czy proces istnieje , czy musi zostać tak jak pisałem wcześniej ??

Użytkownik Karol napisał:

21 października 2013


Problem nie jest tak łatwy jak by się wydawało. Możesz skorzystać ze Snapshot lub FindWindow, albo obu jednocześnie. Zależnie od koncepcji Twojego projektu.

Innych rozwiązań nie widzę.

Ps. Korzystając z FindWindow musiał byś sobie przygotować listę nazwy klas dla poszczególnych aplikacji.

Użytkownik Maniek napisał:

21 października 2013


Listę nazwy klas można zrobić łatwo w języku programowania AutoIT bo jest tam narzędzie, które po najechaniu na dane okienko, pokazuje wszystkie informacje o nim. Tylko, że podczas instalacji programów, okienka danego instalatora np. firefox-a nie będzie wyświetlane (czyli instalacja silent)

Tutaj przesyłam Ci screen z zastosowaniem tego narzędzia z języka AutoIT

http://img13.imageshack.us/img13/3891/xsaz.png

@Edit
Chyba przez nazwy klas nie dam rady bo bardzo często w instalatorach wyskakuje Class : #32770

Użytkownik Karol napisał:

21 października 2013


Rzeczywiście, pozostaje użyć Snapshot. #327.. jest klasą systemową, często spotykaną np. w Menadżerze Zadań Windows.

Użytkownik Maniek napisał:

21 października 2013


Mógłbyś podesłać jakiś przykład z użyciem Snapshot ??

Użytkownik Karol napisał:

21 października 2013


Przecież jest w artykule. Chodziło mi o CreateToolhelp32Snapshot() :D

Zachęcam Cię do zostawienia komentarza!

Ilość znaków: 0