Win32com - Windows Scripting Shell - Process - Id

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
7-X
User
Beiträge: 3
Registriert: Mittwoch 16. Januar 2013, 11:15

Hallo!

Ich habe eine Frage zu Windows-Scripting Host WSH und Python.

Ich möchte mit der WSH ein externes Programm (Konsolenanwendung) starten (Ablauf automatisieren) und benötige dabei die Prozess-Id dieses Externen Programms. Das Programm liest binäre Daten aus einer Datei und erstellt ein Textfile, was einige Zeit dauert. Dabei läuft die Ausgabe des Programms in einem Windows-Konsolenfenster ab. Ungünstigerweise muss man zum Abschluss des Programms die Enter-Taste drücken. Änderungen an diesem Programm kann ich nicht machen, da der Quelltext nicht (mehr) verfügbar ist.

Ich kann zwar mit Sendkeys eine Tasteneingabe senden, doch kann ich nicht immer sicher stellen, dass diese Konsole gerade den Fokus hat.

Noch problematischer ist es, wenn das Programm im Hintergrund läuft (z.B. wenn der Benutzer abgemeldet ist). Da kann ich den Fokus nicht auf diese Konsole setzen. Hier ein Beispiel:

Code: Alles auswählen

import win32api
import win32com.client
import win32gui
import win32process

shell = win32com.client.Dispatch("WScript.Shell")
shell.Run('eineSpezielleExe.exe')

win32api.Sleep(1000)

hwnd2 = win32gui.GetForegroundWindow()
_, pid2 = win32process.GetWindowThreadProcessId(hwnd2)

print(hwnd2)
print(pid2)

win32api.Sleep(10000)

shell.AppActivate(pid2)

win32api.Sleep(1000)
shell.SendKeys("{ENTER}")


Nun meine Frage: Gibt es eine Möglichkeit, die Prozess-Id auch ohne der Funktion GetWindowThreadProcessId(hwnd) zu ermitteln? Also z.B. als Rückgabewert von shell.Run('eineSpezielleExe.exe')?
Wie kann man einen Prozess mit einer bestimmten PId killen? So könnte ich ohne Sendkeys auskommen, da die gewünschte Textdatei schon vor dem Zeitpunkt der Benutzereingabe (Enter) fertig gestellt ist. Ich müsste demzufolge nur überprüfen, ob die Datei schon vollständig ist und könnte so das Fenster schließen.

Matthias
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Vielleicht hilft Dir subprocess weiter, damit könntest Du STDIN/STDOUT abfangen und z.B. das Enter hineinschreiben. subprocess liefert Dir auch die PID mit.

Ansonsten ein Bsp. fürs killen eines Prozesses nach Namen --> http://stackoverflow.com/a/7956651
Das liese sich mit ctypes recht einfach in Python nachbilden. Wahrscheinlich gibts die WINAPI-Funktionen auch schon fertig gewrappt im win32-Modul. (nutze selbst eher ctypes für basale WINAPI-Interaktionen)
BlackJack

@7-X: Man kann mit `os.kill()` Prozesse beenden.

Ich frage mich allerdings bei dem gezeigten Quelltext warum überhaupt die ganzen Windows-spezifischen Module verwendet werden. Das sollte doch eigentlich auch mit Mitteln der Standardbibliothek lösbar sein, oder? Also mit dem `subprocess`-Modul. Die `Popen`-Objekte haben eine `terminate()`-Methode um den Prozess zu beenden. Ungetestet:

Code: Alles auswählen

from subprocess import Popen
from time import sleep


def main():
    process = Popen(['eineSpezielleExe.exe'])
    sleep(10000)
    process.terminate()


if __name__ == '__main__':
    main()
Wenn man es etwas robuster gestalten möchte, könnte man sich das externe Modul `psutils` anschauen. Damit kann man zum Beispiel die offenen Datei-Handles eines Prozesses ermitteln, und so vielleicht relativ einfach überprüfen ob die Datei vom Prozess schon fertig geschrieben wurde.
7-X
User
Beiträge: 3
Registriert: Mittwoch 16. Januar 2013, 11:15

Danke, so einfach kann's gehen.
Antworten