2

If I launch an external application from within a Python GUI application (PySide), is there a way to install an 'exited' signal, to notify when the user has exited/closed the external application?

I understand there's subprocess.poll() and subprocess.wait(), but I'm more after a signal/slot procedure, not a polling procedure. If there are other options, not using subprocess, I'd be happy to implement them as well.

This is the approach I'm toying with at the moment:

def eventFilter(self, source, event):
    if event.type() == QtCore.QEvent.Close/ChildRemoved/etc.:
        print("App closed!")
        self.AppClosedHandler()

self.App = subprocess.Popen([r'C:\WINDOWS\SYSTEM32\some_application.exe'], shell=True)
self.App.installEventFilter(self)

Unfortunately you can't install an Event Filter on a Popen.

jars121
  • 1,127
  • 2
  • 20
  • 35
  • 1
    What platforms does this have to work on? Do you have any control over the source code of the other application? Why can't you use `wait()` or `poll()`? – ekhumoro Nov 02 '15 at 23:13
  • This will have to work on Windows, primarily 64-bit 8.1. I have no control over the source code of the other application, I'm simply calling the application .exe. I could use wait() or poll(), I had just hoped there was a nice signal available. As per below, I think the QProcess.finished() signal is what I'm after. – jars121 Nov 02 '15 at 23:17
  • Please post your solution as an answer instead of editing it into your question. – ThiefMaster Nov 02 '15 at 23:38
  • 1
    related: [How to do stuff during and after a child process](http://stackoverflow.com/q/28220197/4279) – jfs Nov 03 '15 at 02:35

2 Answers2

1

If you are using Pyside then you can definitely use Qprocess. There's a signal emitted when the process finishes: Qprocess.finished

Neitsa
  • 7,693
  • 1
  • 28
  • 45
  • Thanks for the suggestion, that's exactly the functionality I'm looking for! Given the example code I've posted in the edit above, how do I install self.App as the QProcess 'process' to watch? – jars121 Nov 02 '15 at 23:01
0

Here's the solution I've ended up using. I'm using a 32-bit Python installation on a 64-bit Windows 7 platform, so I need to disable the automatic x64 redirection to enable access to System32 applications. As such, I'm using a class to temporarily disable the automatic redirection:

class DisableRedirection:
    _Disable = ctype.windll.kernel32.Wow64DisableWow64FsRedirection
    _Revert = ctypes.windll.kernel32.Wow64RevertWow64FsRedirection
    def __enter__(self):
        self.OldValue = ctypes.c_long()
        self.Success = self._Disable(ctypes.byref(self.OldValue))
    def __exit__(self, type, value, traceback):
        if self.Success:
            self._Revert(self.OldValue)
            print("Closed!")

I simply run the subprocess call within a 'with' statement, such that the subprocess is run while the redirection is taking place. When I close the external application, the redirection finishes, thus allowing me to use the exit function of the DisableRedirection class:

with DisableRedirection():
    self.App = subprocess.Popen([r'C:\WINDOWS\SYSTEM32\Application.exe'], shell=True)

So far this appears to do what I require.

jars121
  • 1,127
  • 2
  • 20
  • 35