Allgemeine Fragen zur PROFAN Programmierung

Views (Heute): 242987 (4423)

| Suchen
| Zurück zur Übersicht

Autor | Thema: Auflistung aller laufenden Programme unter Windows 9x/NT
Steffen Lange
| Datum:07.05.02 18:35 (stelas@web.de) |
Für so eine Art "Task-Manager", der nur das Starten bestimmter Programme zulassen bzw. verbieten soll, suche ich für folgendes Problem eine Profan-gerechte Lösung mit API-Mitteln: Wie kann man alle aktiven Prozesse (also alle aktiven Programme) mit Programmpfad(!) ermitteln? Als erstes müßte man alle Prozess-IDs herausbekommen. Und dann könnte man über API-Funcs die Eigenschaften (wie Programmpfad, Prozessname, Heapgröße etc.) herauskriegen. Ein paar Anmerkungen zu Lösungsversuchen, die wohl in einer Sackgasse enden: 1.) Hier wurden ja schon vielfach Lösungen besprochen über FindWindow (oder ähnliches) laufende Programme durch ihre Titelleiste zu identifizieren. Damit bekommt man jedoch nicht heraus, ob bestimmte Programme aktiv sind, die kein Hauptfenster besitzen bzw. deren Titelleistenbeschriftung sich je nach Aktion (welche das Programm gerade ausführt) ändert. 2.) Für die einzelnen Module die ein Prozess startet, läßt sich die Modul-ID ja über GetModule (in kernel32) herausbekommen, wenn man den Modulnamen weiß (z.B. winmm). Mit Hilfe der ID kann man dann mit GetModuleFileName (ebenfalls in kernel32) den Pfad zu der zugehörenden Datei herausbekommen. Leider gibt es kein Pendant dieser Funktionen für Prozesse. 3.) Mit den Lösungsansätzen 1 und 2 lassen sich auch nicht alle aktiven Prozesse auflisten (Was ich ja erreichen will!), sondern es wäre nur die Abfrage möglich, ob Prozess XYZ gerade aktiv ist. 4.) In der Win9x-API gibt es eine Toolhelp-Bibliothek, welche wohl die einfache Auflistung von allen laufenden Prozessen ermöglicht. Diese gibt es jedoch leider nicht für NT und ein Ansprechen durch Profan ist aufgrund fehlender Callback- Unterstützung wohl auch nicht möglich. Also, vielen Dank im voraus. CU Steffen.
Sebastian König
| Datum:07.05.02 20:22 (feedback@sekoenig.de) |
Hallo, > 4.) In der Win9x-API gibt es eine Toolhelp-Bibliothek, > welche wohl die einfache Auflistung von allen laufenden > Prozessen ermöglicht. Diese gibt es jedoch leider > nicht für NT und ein Ansprechen durch Profan ist aufgrund > fehlender Callback-Unterstützung wohl auch nicht möglich. Man kann die Toolhelp-Funktionen problemlos mit Profan² benutzen; Callback-Funktionen werden nicht benötigt. (Selbst wenn dies der Fall wäre, könnte man sie zur Not mit Maschinencode in Bereichsvariablen bereitstellen. :-). Ich habe vor einiger Zeit mal folgenden Code zur Toolhelp-Bibliothek in die Mailingliste gepostet:
    'processes.prf - Aufzählen aller aktiven Prozesse (Win9x/ME)
    'Autor: Sebastian König
    'eMail: feedback@sekoenig.de

    '---Benötigte API-Funktionen:
    DEF CreateToolhelp32Snapshot(2) !"KERNEL32","CreateToolhelp32Snapshot"
    DEF Process32First(2) !"KERNEL32","Process32First"
    DEF Process32Next(2) !"KERNEL32","Process32Next"
    DEF CloseHandle(1) !"KERNEL32","CloseHandle"

    declare hSnapshot&
    declare PROCESSENTRY32#

    'Struktur mit Prozess-Informationen:
    dim PROCESSENTRY32#,296
    long PROCESSENTRY32#,0 = 296

    window 0,0-640,480
    windowtitle "Enumerieren aller aktiven Prozesse"

    '---Snapshot erstellen (2 = TH32CS_SNAPPROCESS):
    let hSnapshot& = CreateToolhelp32Snapshot(2,0)

    '---Ersten Prozess aufzählen:
    Process32First(hSnapshot&,PROCESSENTRY32#)
    print @string$(PROCESSENTRY32#,36)

    '---Alle weiteren Prozesse aufzählen:
    while @neq(Process32Next(hSnapshot&,PROCESSENTRY32#),0)
     print @string$(PROCESSENTRY32#,36)
    wend

    print ""
    print "--> Taste zum Beenden"
    waitkey

    '---Aufräumen:
    dispose PROCESSENTRY32#
    CloseHandle(hSnapshot&)

    end
Ich hoffe, er hilft Dir bei Deinem Problem etwas weiter. Leider ist es in der Tat so, dass die Toolhelp-Funktionen unter NT-basierten (abgesehen von Windows XP) nicht verfügbar sind. Hier hilft jedoch die PSAPI weiter. Mit der Funktion EnumProcesses (die übrigens - und das ist eigentlich untypisch für Windows Enum*()-Funktionen - auch ohne Callback auskommt, kann man die Process-ID's aller aktiven Prozesse in ein Array (also in Profan array#) schreiben. Anschließend kann man zu jedem Prozess weitere Informationen ermitteln. Hier ein kurzes Beispiel (leider funktioniert das Ermittlen des Dateinames nicht so, wie es im MSDN dokumentiert ist; ich werde mich bei Gelegenheit nochmal damit beschäftigen):
    'processes2.prf - Aufzählen aller aktiven Prozesse (WinNT/2000/XP)
    'Autor: Sebastian König
    'eMail: feedback@sekoenig.de

    '---Benötigte API-Funktionen:
    DEF EnumProcesses(3) !"PSAPI","EnumProcesses"
    DEF OpenProcess(3) !"KERNEL32","OpenProcess"
    DEF CloseHandle(1) !"KERNEL32","CloseHandle"

    declare processes#,num_p&,id&,handle&
    declare i%

    '---Array mit Process-ID's:
    dim processes#,1024 'Genug Platz für 256 Prozesse

    window 0,0-640,480
    windowtitle "Enumerieren aller aktiven Prozesse"

    '---Array füllen:
    EnumProcesses(processes#,256,Addr(num_p&))

    let i% = 0

    '---Daten auslesen:
    while @lt(i%,num_p&)
     let id& = @long(processes#,@mul(i%,4))

     if @neq(id&,0)
      '---Handle ermitteln:
      let handle& = OpenProcess($000F0000,0,id&) '$000F0000 = STANDARD_RIGHTS_REQUIRED

      'Das Ermitteln des Dateinames funktioniert leider noch nicht... :-(
      print id&

      '---Handle freigeben:
      CloseHandle(handle&)

     endif

     inc i% 'nächster Prozess
    wend

    print ""
    print "--> Taste zum Beenden"
    waitkey

    '---Aufräumen:
    dispose processes#

    end
In Deinem Programm musst Du dann später nur mit GetVersionEx() ermitteln, unter welchem System das Programm läuft und den entsprechenden Weg einschlagen... MfG Sebastian
Steffen Lange
| Datum:09.05.02 19:51 (stelas@web.de) |
Hallo nochmal! Vielen Dank an Sebastian für Deinen processes.prf-Quellcode zur Ansteuerung der Toolhelp32-Funktion. Folgende Prozedur habe ich nun zur Terminierung eines beliebigen Prozesses geschrieben: Def @GetExitCodeProcess(2) !"KERNEL32.DLL","GetExitCodeProcess" Def @TerminateProcess(2) !"KERNEL32.DLL","TerminateProcess" Declare exitcode# Proc Terminate_Process Parameters hprocessid& Dim exitcode#,4 @GetExitCodeProcess(hprocessid&,exitcode#) ' Rückgabewert 1 bei Erfolg @TerminateProcess(hprocessid&,@Long(exitcode#,0)) ' Rückgabewert 1 bei Erfolg Dispose exitcode# EndProc Die Prozess-IDs kann man ja mit Hilfe der PROCESSENTRY32-Struktur (in processes.prf) so ermitteln: <...> hprocessid&=@Long(processentry32#,8) ' lt. Win32-API-Hilfe <...> Nur wenn ich von Prozess XYZ mit der Toolhelp32-Funktion die Prozess-ID ermittle und sie an meine Terminate_Process-Prozedur übergebe, passiert nix! Nach weiterem Studium in der Win32-API-Hilfe liegt das wohl daran, daß mein Programm (Prozess) nicht über PROCESS_ALL_ACCESS Rechte (ACLs) verfügt. Nur wird in der API-Hilfe im Kapitel "Access Masks and Access Rights" auf die "Developer's Reference" verwiesen, welche ich bei MS jedoch (noch immer! :-( ) nicht gefunden habe. Also, weiß jemand eine Lösung auf mein PROCESS_ALL_ACCESS-Problem oder kann mir sagen wo ich ich die Developer Referenz finde???? CU Steffen.
Philipp Sternberg
| Datum:08.05.02 21:32 (ps@burghardt-ib.de) |
Also ich hab die ToolHelp32 Funktionen auch schon erfolgreich unter Windows 2000 eingesetzt, da sind sie auch vorhanden ! (Und da haben sie bei mir edlerweise für jeden Prozess auch noch dass instanzhandle wiedergegeben...) Philipp Sternberg
Sebastian König
| Datum: 09.05.02 20:13 (feedback@sekoenig.de) |
Hallo, > Nur wenn ich von Prozess XYZ mit der Toolhelp32-Funktion die > Prozess-ID ermittle und sie an meine Terminate_Process- > Prozedur übergebe, passiert nix! > > Nach weiterem Studium in der Win32-API-Hilfe liegt das wohl > daran, daß mein Programm (Prozess) nicht über > PROCESS_ALL_ACCESS Rechte (ACLs) verfügt. unzureichende Zugriffsrechte können in der Tat ein Problem sein, der Fehler liegt hier jedoch zunächst an einer anderen Stelle: TerminateProcess erwartet als 1. Parameter ein Prozess-Handle und nicht eine Prozess-ID. Das Handle erhältst Du über die Funktion OpenProcess(). Nach dem Terminieren sollte das Handle dann mit CloseHandle() wieder freigegeben werden. Hier ein kurzes Beispiel:
    DEF OpenProcess(3) !"KERNEL32","OpenProcess"
    DEF CloseHandle(1) !"KERNEL32","CloseHandle"
    '...
    let handle& = OpenProcess($000F0001,0,id&)
    '$000F0000 = STANDARD_RIGHTS_REQUIRED | PROCESS_TERMINATE
    TerminateProcess(handle&,0)
    CloseHandle(handle&)
    '...
BTW: Es macht eigentlich in diesem Zusammenhang keinen Sinn, GetExitCodeProcess() aufzurufen, da Du ExitCode ja mit dem Aufruf von TerminateProcess() explizit setzt. (Die Dokumentation im MSDN ist an dieser Stelle etwas verwirrend, da dort in der Tat steht, man solle GetExitCodeProces() zum Ermitteln verwenden. Ich denke jedoch, dass dies nur ein genereller Hinweis sein soll. In den M$-Beispiel-Codes wird der ExitCode jedenfalls nicht vor dem Terminieren ermittelt... MfG Sebastian

| Zurück zur Übersicht