Allgemeine Fragen zur PROFAN Programmierung
Views (Heute): 242987 (4423)
  Suchen
 Zurück zur Übersicht
 AutorThema: Auflistung aller laufenden Programme unter Windows 9x/NT
Steffen Lange
Datum:07.05.02 18:35 Antwortenals Email verschicken (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 Antwortenals Email verschicken (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 Antwortenals Email verschicken (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 Antwortenals Email verschicken (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 Antwortenals Email verschicken (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