Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi EnumProcesses (https://www.delphipraxis.net/35225-enumprocesses.html)

Luckie 4. Dez 2004 03:13


EnumProcesses
 
Ich versuche gerade eine Prozessliste mit EnumProcesses zu bekommen. Ich habe da schon eine funktionierden Version auf meiner HP, wollte es aber besser machen:
Delphi-Quellcode:
function GetProcessList(out ProcessList: TProcessList): DWORD;

  function GetOSVersionInfo(var Info: TOSVersionInfo): Boolean;
  begin
    FillChar(Info, SizeOf(TOSVersionInfo), 0);
    Info.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
    Result := GetVersionEx(TOSVersionInfo(Addr(Info)^));
    if (not Result) then
    begin
      FillChar(Info, SizeOf(TOSVersionInfo), 0);
      Info.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
      Result := GetVersionEx(TOSVersionInfo(Addr(Info)^));
      if (not Result) then
        Info.dwOSVersionInfoSize := 0;
    end;
  end;

var
  OSInfo      : TOSVersionInfo;
  PidProcesses : PDWORD;
  PidWork     : PDWORD;
  BufferSize  : Cardinal;
  cbNeeded    : Cardinal;
  cntProcesses : Cardinal;
  i           : Cardinal;

begin
  result := 0;

  // What OS are we running on?
  if GetOSVersionInfo(OSInfo) then
  begin
    if (OSInfo.dwPlatformId = VER_PLATFORM_WIN32_NT) and (OSInfo.dwMajorVersion =
      5) then
    // WinNT and higher
    begin
      cbNeeded := 0;
      BufferSize := 0;
      // how much memory do we need
      if EnumProcesses(nil, BufferSize, cbNeeded) then
      begin
        cntProcesses := cbNeeded div sizeof(DWORD);
        GetMem(PidProcesses, cntProcesses);
        if EnumProcesses(PidProcesses, cntProcesses, cbNeeded) then
        begin
          PidWork := PidProcesses;
          setlength(ProcessList, cntProcesses);
          for i := 0 to cntProcesses - 1 do
          begin
            ProcessList[i] := PidWork^;
            Inc(PidWork, sizeof(PDWORD));
          end;
        end;
        FreeMem(PidProcesses, cntProcesses);
      end;
    end
    // Win 9x and higher except WinNT
    else
    begin
    end;
  end;
end;
Im PSDK steht:
Zitat:

To determine how many processes were enumerated by the call to EnumProcesses, divide the resulting value in the cbNeeded parameter by sizeof(DWORD).
Ich dachte mit dem ersten Aufruf füllt er mir cbNeeded. Tut er aber nicht, ist immer null.

Mache ich es so:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  pdwResult : PDWORD; // für den Buffer
  pdwWork   : PDWORD; // um dem Buffer verarbeiten zu können
  dwCountIn : DWORD; // Grösse des Buffers in Byte
  dwCountOut : DWORD; // Zurückgelieferte Anzahl Byte
  i         : integer;
begin
  dwCountOut := 0;   // Sicherheitshalber initialisieren, muss nicht sein
  dwCountIn := 1024; // Willkürlich gewählt, genügt für 256 Prozesse
  pdwResult := AllocMem(dwCountIn);
  try
    if not EnumProcesses(pdwResult,dwCountIn,dwCountOut) then begin
      RaiselastOSError();
    end else begin
      pdwWork := pdwResult; // zur Verarbeitung übergeben, damit FreeMem funktioniert
      for i := 1 to (dwCountOut shr 2) do begin // shr 2 = / 4, da 4 Byte je DWORD
        // Prozess Id ausgeben
        //ShowMessage('ProzessId# '+IntToStr(i)+': '+IntToStr(pdwWork^));
        ListBox1.Items.Add(GetProcessName(pdwWork^));
        // auf nächste addressieren (inc erhöht automatisch um 4, da es ein typisierter Pointer ist
        inc(pdwWork);
      end;
    end;
  finally
    FreeMem(pdwResult,dwCountIn);
  end;
end;
Dann geht es. Nur finde ich es etwas blöd unnötig Speicher zu reservieren.

Sprint 4. Dez 2004 03:50

Re: EnumProcesses
 
Es steht aber auch so in der Hilfe, das du keine Möglichkeit hast zu ermitteln wieviel Speicher du wirklich brauchst. Sondern das du ausreichend Speicher reservieren sollst. Von daher finde ich das C Beispiel in dem Platform SDK ganz gut.

Luckie 4. Dez 2004 03:57

Re: EnumProcesses
 
Gut, wenn sie es nicht anders wollen. :roll:

Luckie 4. Dez 2004 05:13

Re: EnumProcesses
 
OK. So sieht es jetzt aus: http://www.luckie-online.de/Delphi/S...zessliste.html

w3seek 4. Dez 2004 12:33

Re: EnumProcesses
 
Zwei Fehler:
1. Der Versionscheck funktioniert mit NT 4 da es = 4 anstatt >= 4 testet
2. OpenProcess() zu verwenden um den Dateinamen des Prozesses zu verwenden ist nicht zuverlaessig weil man ggf. nicht die noetigen Rechte hat (sieht man an den "unbekannt" eintraegen in der liste

Ich werde ein Beispiel wie M$ diese Funktion implementiert hat mit Hilfe der native API hier posten, denn die liefert eigentlich schon genug Informationen, inkl. der Dateinamen fuer alle Prozesse. Die NAPI funktionen sind zwar undokumentiert von M$, aber sie sind in einigen Buechern gut dokumentiert und haben sich ausserdem seit NT 4 nicht geaendert, unwahrscheinlich also dass sie jemals geaendert werden. Ausserdem gibt es eine Reihe von Programmen wie der TaskManager die auf diese Methode zurueckgreifen.

[edit: ich seh gerade dass das neueste PSDK diese funktionen doch dokumentiert hat]

Luckie 4. Dez 2004 12:49

Re: EnumProcesses
 
Zitat:

Zitat von w3seek
Zwei Fehler:
2. OpenProcess() zu verwenden um den Dateinamen des Prozesses zu verwenden ist nicht zuverlaessig weil man ggf. nicht die noetigen Rechte hat (sieht man an den "unbekannt" eintraegen in der liste

Das würde ich nicht als Fehler sehen. ;)

Zitat:

Die NAPI funktionen sind zwar undokumentiert von M$, aber sie sind in einigen Buechern gut dokumentiert
Diese Bücher habe ich leider nicht.

Zitat:

und haben sich ausserdem seit NT 4 nicht geaendert, unwahrscheinlich also dass sie jemals geaendert werden.
Trotzdem sollte man sich nicht darauf verlassen.

Zitat:

Ausserdem gibt es eine Reihe von Programmen wie der TaskManager die auf diese Methode zurueckgreifen.
Der ist ja auch von MS selber. ;)

Sprint 4. Dez 2004 12:59

Re: EnumProcesses
 
Zitat:

Zitat von w3seek
OpenProcess() zu verwenden um den Dateinamen des Prozesses zu verwenden ist nicht zuverlaessig weil man ggf. nicht die noetigen Rechte hat (sieht man an den "unbekannt" eintraegen in der liste

Mit AdminRechte bekommt man in dem Beispiel von Luckie nur ein Unbekannt. Und das liegt daran, das der Leerlaufprozess nun maö keinen Namen hat. :wink:

Zitat:

ich seh gerade dass das neueste PSDK diese funktionen doch dokumentiert hat]
Dann hättest du dir die Funktion gleich genauer anschauen können, dann hättest du auch gesehen, das man dafür auch einen ProcessHandle braucht.

w3seek 4. Dez 2004 13:04

Re: EnumProcesses
 
Zitat:

Zitat von Sprint
Dann hättest du dir die Funktion gleich genauer anschauen können, dann hättest du auch gesehen, das man dafür auch einen ProcessHandle braucht.

nein, braucht man nicht. Dieser weg duerfte sogar mit sehr eingeschraenkten Rechten funktionieren. die toolhelp api benutzt uebrigens den gleichen Weg.

Die Wahrscheinlich dass diese Funktionen geaendert werden geht gegen null, erstens wurden sie endlich von M$ dokumentiert und zweitens benoetigen viele Programme, insbesondere Virenscanner und Firewalls diese Funktion...

gebt mir noch ein paar Miuten...

Luckie 4. Dez 2004 13:06

Re: EnumProcesses
 
Wie heißen denn die Funktionen?

Sprint 4. Dez 2004 13:08

Re: EnumProcesses
 
Zitat:

Zitat von Luckie
Wie heißen denn die Funktionen?

Code:
NTSTATUS NtQueryInformationProcess(
  HANDLE ProcessHandle,
  PROCESSINFOCLASS ProcessInformationClass,
  PVOID ProcessInformation,
  ULONG ProcessInformationLength,
  PULONG ReturnLength
);

w3seek 4. Dez 2004 14:00

Re: EnumProcesses
 
nein, das ganze funktioniert mit NtQuerySystemInformation().

Ich hab mal die Funktion EnumProcesses in Delphi nachgebaut, so oder sehr Aehnlich duerfte sie Microsoft implementiert haben:

Delphi-Quellcode:
const
  SystemProcessInformation = 5;

  STATUS_INFO_LENGTH_MISMATCH = Integer($C0000004);

type
  UNICODE_STRING = record
    Length: Word;
    MaximumLength: Word;
    Buffer: PWideChar;
  end;
  PUNICODE_STRING = ^UNICODE_STRING;
  TUNICODE_STRING = UNICODE_STRING;

  _SYSTEM_PROCESS_INFORMATION = record
    NextEntryOffset: ULONG;
    NumberOfThreads: ULONG;
    SpareLi1, SpareLi2, SpareLi3: TLargeInteger;
    CreateTime, UserTime, KernelTime: TLargeInteger;
    ImageName: UNICODE_STRING;
    BasePriority: ULONG;
    UniqueProcessId: THandle;
    InheritedFromUniqueProcessId: THandle;
    HandleCount: ULONG;
    SessionId: ULONG;
    SpareUl3: ULONG;
    PeekVirtualSize: ULONG;
    VirtualSize: ULONG;
    PageFaultCount: ULONG;
    PeakWorkingSetSize: ULONG;
    WorkingSetSize: ULONG;
    QuotaPeakPagedPoolUsage: ULONG;
    QuotaPagedPoolUsage: ULONG;
    QuotaPeakNonPagedPoolUsage: ULONG;
    QuotaNonPagedPoolUsage: ULONG;
    PagefileUsage: ULONG;
    PeakPagefileUsage: ULONG;
    PrivatePageCount: ULONG;
  end;
  TSYSTEM_PROCESS_INFORMATION = _SYSTEM_PROCESS_INFORMATION;
  PSYSTEM_PROCESS_INFORMATION = ^TSYSTEM_PROCESS_INFORMATION;

function NtQuerySystemInformation(SystemInformationClass: Cardinal;
                                  SystemInformation: Pointer;
                                  Length: ULONG;
                                  ResultLength: PULONG): Integer; stdcall; external 'ntdll.dll';
function RtlNtStatusToDosError(StatusCode: Integer): DWORD; stdcall; external 'ntdll.dll';

function EnumProcesses(pProcessIds: PDWORD; cb: DWORD; var pBytesReturned: DWORD): BOOL; stdcall;
const
  BUF_SIZE = $10000;
var
  ProcListBuffer: PChar;
  ProcessInfo: PSYSTEM_PROCESS_INFORMATION;
  ProcOffset: ULONG;
  BufSize: Cardinal;
  Status: Integer;
begin
  Result := false;

  // capture the process list
  BufSize := BUF_SIZE;
  repeat
    GetMem(ProcListBuffer, BufSize);
    if ProcListBuffer = nil then
    begin
      SetLastError(ERROR_NOT_ENOUGH_MEMORY);
      Exit;
    end;

    Status := NtQuerySystemInformation(SystemProcessInformation,
                                       ProcListBuffer,
                                       BufSize,
                                       nil);
    if Status = STATUS_INFO_LENGTH_MISMATCH then
    begin
      // Buffer was too small, increase the buffer size and try again
      FreeMem(ProcListBuffer);
      Inc(BufSize, BUF_SIZE);
    end
    else if Status < 0 then
    begin
      // Another error occured
      FreeMem(ProcListBuffer);
      SetLastError(RtlNtStatusToDosError(Status));
      Exit;
    end;
  until Status >= 0;

  pBytesReturned := 0;

  // we got the entire process list now, extract all PIDs
  ProcOffset := 0;
  ProcessInfo := PSYSTEM_PROCESS_INFORMATION(ProcListBuffer);
  while cb >= SizeOf(DWORD) do
  begin
    ProcessInfo := PSYSTEM_PROCESS_INFORMATION(Cardinal(ProcessInfo) + ProcOffset);
    pProcessIds^ := DWORD(ProcessInfo^.UniqueProcessId);
    ProcOffset := ProcessInfo^.NextEntryOffset;
    Inc(pProcessIds);
    Dec(cb, SizeOf(DWORD));
    Inc(pBytesReturned, SizeOf(WORD));

    if ProcOffset = 0 then
    begin
      Result := true;
      Break;
    end;
  end;

  FreeMem(ProcListBuffer);
end;
wie man erkennen kann, enthaelt die SYSTEM_PROCESS_INFORMATION structure ein Feld namens ImageName, welches ein unicode string ist, den den Prozessnamen (also den Dateinamen des Images des Prozesses) enthaelt. Das Feld Buffer in diesem Unicode string zeigt einfach auf das Ende der structure die gerade enumeriert wurde, deshalb gibt es auch ein Feld NextEntryOffset um den Beginn der naechsten structure finden zu koennen.

Der Task Manager, die PSAPI implementierung von EnumProcesses() und auch die Toolhelp32 API (welche ich fast komplett fuer ReactOS geklont habe und auch unter WinNT funktioniert) verwenden alle diese sehr nuetzliche Funktion ;)

Hoffe das bringt etwas mehr Licht in die duesteren APIs von Windows ;)

Luckie 4. Dez 2004 15:48

Re: EnumProcesses
 
Hast du mal eben eine Demo dazu?

w3seek 4. Dez 2004 15:53

Re: EnumProcesses
 
Zitat:

Zitat von Luckie
Hast du mal eben eine Demo dazu?

Zu was genau? Zur Verwendung dieser Funktion? Einfach so aufrufen wie EnumProcesses von PSAPI

Luckie 4. Dez 2004 16:03

Re: EnumProcesses
 
Wie stellst du dir jetzt vor kommt man an den Modulnamen dran?

w3seek 4. Dez 2004 16:11

Re: EnumProcesses
 
geb mir ein paar minuten ich bau mal eben ein beispiel programm

Luckie 4. Dez 2004 16:15

Re: EnumProcesses
 
Äh, ich dachte das wäre schonm da. Irgendiwe musst du die Funktion ja entwickelt haben. :gruebel:

w3seek 4. Dez 2004 16:37

Re: EnumProcesses
 
Liste der Anhänge anzeigen (Anzahl: 1)
Das was ich entwickelt hatte ist nur dazu da um zu sehen wie EnumProcesses implementiert ist, denn damit kann man sehr sehr viel anfangen:

hier das Beispielprogramm das darauf basiert als Anhang

w3seek 6. Dez 2004 09:21

Re: EnumProcesses
 
nur des Feedbacks wegen, verstanden wie das funktioniert? ;)

Luckie 6. Dez 2004 12:29

Re: EnumProcesses
 
Ich bin noch nicht dazu gekommen, mir das anzugucken. Ich hatte gerade am Sonntag noch Zeit mir das mal runterzuladen und schnell mal zu starten und bin gerade erst nach hause gekommen. ;)

w3seek 6. Dez 2004 12:39

Re: EnumProcesses
 
Zitat:

Zitat von Luckie
Ich bin noch nicht dazu gekommen, mir das anzugucken. Ich hatte gerade am Sonntag noch Zeit mir das mal runterzuladen und schnell mal zu starten und bin gerade erst nach hause gekommen. ;)

wie war die sauf... aehm trinktour? ;) nur spass

Mitchl55 27. Feb 2005 12:52

Re: EnumProcesses
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,

eine kurze Frage zum Programm!

Wie kann das sein? Ich ändere den Dateinamen in Project.exe und das was mir
angezeigt wird in der Liste ist "Project.exee" was läuft den an der Stelle
falsch? Darf ich den Programmnamen nicht ändern (compilerproblem?)? Wird dieser
dann falch angezeigt?

Wer weiß da Rat???

Beste Grüße

Mitchl

Catbytes 27. Feb 2005 14:12

Re: EnumProcesses
 
Hallo,

gibt es auch eine Möglichkeit Speicherbedarf und CPU-Auslastung der Prozesse zu ermitteln?

Luckie 27. Feb 2005 14:21

Re: EnumProcesses
 
Zitat:

Zitat von Catbytes
gibt es auch eine Möglichkeit Speicherbedarf und CPU-Auslastung der Prozesse zu ermitteln?

Neue Frage, neuer Thread bitte.

Highttower 11. Sep 2009 15:55

Re: EnumProcesses
 
Zitat:

Zitat von Luckie

URL ist tot, gibt es noch ne möglichkeit da ran zu kommen?

Vielen Dank,

Tobi

mirage228 11. Sep 2009 15:59

Re: EnumProcesses
 
http://www.michael-puff.de/Developer...essliste.shtml

Viele Grüße


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:30 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz