[Tkinter-discuss] Okay, this one really has me baffled --KeyboardInterrupt signal not working!

Stewart Midwinter stewart.midwinter at gmail.com
Wed Apr 20 22:06:35 CEST 2005

Jared, maybe I've missed part of the conversation, but instead of
running an os.system command to start your process, how about using a
call to win32file's process creation?  That way you can get a process
handle that will continue to exist only so long as the process is
alive.  you can monitor for its continued existence. If you need to
kill the process, first check the handle, then kill using the PID.

you said you had problems getting access to the child process, but I
wonder if that's due to the fact that you are using an os.system
command to start the initial process. Just a thought.

Anyway, here's some code that starts a process:

    def createProcess(self, file, args, env, name, logFilename,
currentDirectory, hide):
        '''Start up a process to run some task, so that control is
returned to Scenario Manager immediately.
           "file" is the name of the batch file to be run in the
process (e.g. "diagram" > diagram.bat)
           "args" is a string containing any command-line arguments to
be passed to the batch file
           "env" is an optional environment variable
           "name" is an optional name for the process
           "logFilename" is an optional log file name
           "currentDirectory" is an optional specification of the
directory to be run in
        fname = self.createProcess.__name__
        self.__lock = threading.Lock()
        self.__terminationEvent = threading.Event()
        file = os.path.normpath(file)
        if not os.path.splitext(file)[1]:            
            file = file + '.exe'
        if not os.path.isabs(file):
            # Windows NT seems to want a full path            
            paths = string.split(self.getFromEnv('PATH', env, []),os.pathsep)
            for path in paths:
                fullPath = os.path.join(path, file)
                if os.path.isfile(fullPath):
                    file = fullPath
        args = file+' '+args
        if self.debug: print 'args ',args       
        self._hideWindow = 0 # was 1
        self.__fileSecurity = pywintypes.SECURITY_ATTRIBUTES()
        self.__fileSecurity.bInheritHandle = pywintypes.TRUE
        self.__inputFile = win32file.CreateFile(
        _nullFilename, win32file.GENERIC_READ,
        win32file.FILE_SHARE_READ , self.__fileSecurity,
        win32file.OPEN_EXISTING, win32file.FILE_ATTRIBUTE_NORMAL, 0)
        startupInfo = win32process.STARTUPINFO()
        #print 'log ',logFilename
        if logFilename:
            logfile = win32file.CreateFile(
                logFilename, win32file.GENERIC_WRITE | win32file.GENERIC_READ, 
                win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE, 
                self.__fileSecurity, win32file.CREATE_ALWAYS, 0, 0)
            startupInfo.hStdInput = self.__inputFile
            startupInfo.hStdOutput = int(logfile)
            startupInfo.hStdError = int(logfile)
            startupInfo.dwFlags = win32process.STARTF_USESTDHANDLES
            if self._hideWindow:
                startupInfo.dwFlags = (startupInfo.dwFlags |
            logfile = None
        if currentDirectory:
            directoryMessage = ' in %s' % currentDirectory
            directoryMessage = ''        
                flags = 0
                 # Session Cancel will kill the required processes.
                if hide == 0:
                    flags = flags | win32process.DETACHED_PROCESS
                msg = 'now starting process with file %s & args %s &
env %s & directory %s' % (str(file), str(args), str(env),
                if self.debug: self.write_debug(fname, msg)
                self.__processInfo = win32process.CreateProcess(
                    file, args , None, None, 
                    pywintypes.TRUE, flags, env, currentDirectory, startupInfo)
            except win32process.error, value:
                raise win32process.error(
                    value.args + (file, currentDirectory))
            if logfile is not None:
         # Close the thread handle, we don't need it
        # createProcess() must return the new process id
        print 'process %s has the following info:\n  - handle %s,
thread %s, pid %s, threadID %s ' % \
            str(self.__processInfo[3]) )
        return self.__processInfo

And here's an excerpt from a method that calls that method to start a
process. In this case, we are running an executable called tui.exe:

        info = self.createProcess('tui',
                           name = 'status-%s' % (self.scenario_name),
        #we care about the handle, the pid and maybe the threadID
        self.statusHandle, statusThread, self.statusPid,
self.statusThreadID = info
        msg = 'Status pid is %i' % self.statusPid

And here's how I cancel a process:

    def cancel(self):
        '''Cancel the execution of a process'''
        fname = self.cancel.__name__
        self.__paused = 'false'
        self.run_state = 'false'
        msg = 'trying to stop a process with self.__paused state= '
        msg = '%s %s and self.run_state= %s and process PID %s' %
(msg, self.__paused, self.run_state, str(self.statusPid))
        if self.debug: self.write_debug(fname, msg)
        self.executeLogging("Stop RUNNING")        
        if self.statusPid is not None:
            #someone might have already closed the status window
            cmd = 'kill %s' % str(self.statusPid)
            end1 = os.path.join(pwPipeworksHome, 'bin', cmd)
            if self.debug: print 'kill status window,', cmd

hope this helps.
Stewart Midwinter
stewart at midwinter.ca
stewart.midwinter at gmail.com
Skype: midtoad

More information about the Tkinter-discuss mailing list