Programmieren mit C++

Borland C++

32-Bit-Programmierung

Auflisten von Prozessen

Wie kann man laufende Prozesse unter Windows 95 bzw. NT auflisten?

Frage

Das Auflisten von Prozessen läuft unter Windows 95 und NT unterschiedlich. Für Windows 95 wird zunächst ein Systemschnappschuß erzeugt, der den aktuellen Systemzustand festhält.

Win95_enumerator::Win95_enumerator(display &d) :
  process_enumerator(d),
  kernel(GetModuleHandle("KERNEL32.DLL")) 
{
  if ( NULL == kernel )
    return;
 
  CreateToolhelp32Snapshot = 
      (CREATESNAPSHOT)GetProcAddress((HINSTANCE)kernel, 
      "CreateToolhelp32Snapshot"); 
  Process32First = (PROCESSWALK)GetProcAddress((HINSTANCE)kernel, 
      "Process32First"); 
  Process32Next  = (PROCESSWALK)GetProcAddress((HINSTANCE)kernel, 
      "Process32Next");
 
  if (NULL == CreateToolhelp32Snapshot || 
      NULL == Process32First ||
      NULL == Process32Next)
    return;
 
  proc.dwSize = sizeof(proc);
}

Process32First() und Process32Next() sind die Adressen zweier Funktionen, mit deren Hilfe der im Schnappschuß gespeicherte Systemzustand durchlaufen werden kann. Das Auflisten über die Methode real_show() basiert auf der Methode show_task() einer separaten Hilfsklasse, die zum Verständnis hier nichts weiter beiträgt, auf der Begleit-CD jedoch komplett mit dem Beispielprogramm enthalten ist.

bool Win95_enumerator::real_show() 
{
 
 if (NULL == CreateToolhelp32Snapshot || 
     NULL == Process32First  ||
     NULL == Process32Next)
  return false;
 
  snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

Für das Auswerten der einzelnen Einträge der Prozeßliste deklariert die Klasse ein Member

PROCESSENTRY32 proc;

das die Informationen aufnimmt. Mit Hilfe des Funktionenpaars Precess32First(), das den ersten Eintrag liefert, und Process32Next(), mit der die nachfolgenden Einträge ermittelt werden, kann nun die gesamte Liste durchlaufen und individuell verarbeitet werden.

  Process32First(snapshot, &proc);
  show_task(proc.szExeFile, proc.th32ProcessID);
 
  while (TRUE == Process32Next(snapshot, &proc))
    show_task(proc.szExeFile, proc.th32ProcessID);

Das Member proc liefert im Feld szExeFile den Dateinamen des Prozesses und in th32ProcessID die ID des betroffenen Prozesses, so daß beide Informationen angezeigt bzw. verarbeitet werden können. Abschließend kann der Speicher freigegeben werden, was zwar automatisch erfolgen sollte, aber sicherlich nicht schadet, wenn man es selbst erledigt.

  CloseHandle(snapshot);
 
  return true;
}

Unter Windows NT werden zunächst zwei Hilfsbibliotheken benötigt, deren Existenz sicherzustellen ist:

NT_process_enumerator::NT_process_enumerator(display &d) :
    process_enumerator(d)
{
  psapi = LoadLibrary("PSAPI.DLL");
  vdmdbg = LoadLibrary("VDMDBG.DLL");
 
  if ( NULL == psapi || NULL == vdmdbg )
    return;

Des weiteren werden die Adressen der nachfolgenden Funktionen benötigt, auf die in der Anzeige Methode real_show() zurückgegriffen wird.

  VDMEnumTaskWOWEx = (VDMENUMTASKWOWEX)GetProcAddress(
        (HINSTANCE)vdmdbg, "VDMEnumTaskWOWEx");
 
  EnumProcesses =(ENUMPROCESSES)GetProcAddress(
        (HINSTANCE)psapi, "EnumProcesses");
 
  GetModuleFileName = (GETMODULEFILENAME)GetProcAddress(
        (HINSTANCE)psapi, "GetModuleFileNameExA");
 
  GetModuleBaseName = (GETMODULEBASENAME)GetProcAddress(
        (HINSTANCE)psapi, "GetModuleBaseNameA");
 
  EnumProcessModules = (ENUMPROCESSMODULES)GetProcAddress(
        (HINSTANCE)psapi, "EnumProcessModules");
}

Die Methode real_show() stellt zunächst sicher, daß die Funktionszeiger korrekt ermittelt wurden.

Lösung

bool NT_process_enumerator::real_show() 
{
  DWORD process_ids[max_num];
  DWORD num_processes;
 
  if (NULL == VDMEnumTaskWOWEx ||
      NULL == EnumProcesses || 
      NULL == GetModuleFileName || 
      NULL == GetModuleBaseName ||
      NULL == EnumProcessModules)
   return false;

Im nächsten Schritt werden die Prozeßinformationen ermittelt über die Funktion EnumProcesses(), die alle laufenden Prozesse zunächst in einem Buffer ablegt, aus dem dann die Anzahl der gefundenen Prozesse ermittelt werden kann.

   int success = EnumProcesses(process_ids, 
                               sizeof(process_ids), 
                               &num_processes);
 
   num_processes /= sizeof(process_ids[0]);
 
   if ( !success ) {
     disp.system_error("Prozeßenumeration fehlgeschlagen!");
 
     return false;
   }  

Für die Anzahl der gefundenen Prozesse kann nun die Anzeige erfolgen. Hierzu wird über OpenProcess() der Prozeß mit dem Abfrageflag PROCESS_QUERY_INFORMATION geöffnet und die einzelnen Module des Prozesses enumeriert, deren Modulnamen und Prozeß-IDs anschließend angezeigt werden können.

Die Anzahl der Module pro Prozeß ergibt sich aus:

  for ( unsigned i=0; i

Unter Rückgriff auf process ergibt sich der Name des Moduls wie folgt:

    if (GetModuleFileName(process, modules[0], 
                          file_name, sizeof(file_name))) 
    {
      show_task(file_name, process_ids[i]);
 
      GetModuleBaseName(process, modules[0],
                        file_name, sizeof(file_name));

Der gefundene Modulname wird auf „NTVDM.EXE“ abgetestet, um zu prüfen, ob nicht ein NT VDM vorliegt, für den dann die Prozesse zu enumerieren sind, die der VDM enthält.

      if ( 0 == _stricmp(file_name, "NTVDM.EXE "))
        VDMEnumTaskWOWEx(process_ids[i], show_task, (long)&disp);
    }

Am Ende der FOR-Schleife ist der Prozeß über sein Handle wieder zu schließen.

  CloseHandle(process);
  }

Nach dem Durchlaufen aller Prozesse sind abschließend die Bibliotheken wieder freizugeben.

  FreeLibrary((HINSTANCE)vdmdbg);
  FreeLibrary((HINSTANCE)psapi);
 
  return true;
}

Beispielprogramm

Für den Einsatz der hier gezeigten Klassen und Techniken ist ein Beispielprogramm auf der Begleit-CD enthalten, das mit VC++ 5.0 kompiliert.

Wird dieses Programm ohne Parameter gestartet, gibt es die laufenden Prozesse auf der Console aus. Wird hingegen ein Parameter spezifiziert - egal welcher auch immer - erfolgt die Anzeige in einem Fenster.

Funktion real_show()





Sachgebiet


© 2009-2012 by Alojado Publishing. Alle Rechte vorbehalten. Ausgewiesene Marken gehören ihren jeweiligen Eigentümern.
Mit der Benutzung dieser Seite erkennen Sie die Nutzungsbedingungen und die Datenschutzerklärung an. Der Betreiber übernimmt keine Haftung für den Inhalt verlinkter externer Internetseiten.
Seite erzeugt 2012-05-20 01:11:39 von textarchiv.alojado.de