⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 process.py

📁 Wxpython Implemented on Windows CE, Source code
💻 PY
📖 第 1 页 / 共 5 页
字号:
        #XXX Should maybe try with os.pipe. Dunno what that does for
        #    inheritability though.
        hChildStdinRd, hChildStdinWr = win32pipe.CreatePipe(saAttr, 0) 
        hChildStdoutRd, hChildStdoutWr = win32pipe.CreatePipe(saAttr, 0) 
        hChildStderrRd, hChildStderrWr = win32pipe.CreatePipe(saAttr, 0) 

        try:
            # Duplicate the parent ends of the pipes so they are not
            # inherited. 
            hChildStdinWrDup = win32api.DuplicateHandle(
                win32api.GetCurrentProcess(),
                hChildStdinWr,
                win32api.GetCurrentProcess(),
                0,
                0, # not inherited
                DUPLICATE_SAME_ACCESS)
            win32api.CloseHandle(hChildStdinWr)
            self._hChildStdinWr = hChildStdinWrDup
            hChildStdoutRdDup = win32api.DuplicateHandle(
                win32api.GetCurrentProcess(),
                hChildStdoutRd,
                win32api.GetCurrentProcess(),
                0,
                0, # not inherited
                DUPLICATE_SAME_ACCESS)
            win32api.CloseHandle(hChildStdoutRd)
            self._hChildStdoutRd = hChildStdoutRdDup
            hChildStderrRdDup = win32api.DuplicateHandle(
                win32api.GetCurrentProcess(),
                hChildStderrRd,
                win32api.GetCurrentProcess(),
                0,
                0, # not inherited
                DUPLICATE_SAME_ACCESS)
            win32api.CloseHandle(hChildStderrRd)
            self._hChildStderrRd = hChildStderrRdDup

            # Set the translation mode and buffering.
            if self._mode == 't':
                flags = os.O_TEXT
            else:
                flags = 0
            fdChildStdinWr = msvcrt.open_osfhandle(self._hChildStdinWr, flags)
            fdChildStdoutRd = msvcrt.open_osfhandle(self._hChildStdoutRd, flags)
            fdChildStderrRd = msvcrt.open_osfhandle(self._hChildStderrRd, flags)

            self.stdin = _FileWrapper(descriptor=fdChildStdinWr,
                                      handle=self._hChildStdinWr)
            logres.info("[%s] ProcessOpen._start(): create child stdin: %r",
                        id(self), self.stdin)
            self.stdout = _FileWrapper(descriptor=fdChildStdoutRd,
                                       handle=self._hChildStdoutRd)
            logres.info("[%s] ProcessOpen._start(): create child stdout: %r",
                        id(self), self.stdout)
            self.stderr = _FileWrapper(descriptor=fdChildStderrRd,
                                       handle=self._hChildStderrRd)
            logres.info("[%s] ProcessOpen._start(): create child stderr: %r",
                        id(self), self.stderr)

            # Start the child process.
            si = win32process.STARTUPINFO() 
            si.dwFlags = win32process.STARTF_USESHOWWINDOW
            si.wShowWindow = 0 # SW_HIDE
            si.hStdInput = hChildStdinRd
            si.hStdOutput = hChildStdoutWr
            si.hStdError = hChildStderrWr
            si.dwFlags |= win32process.STARTF_USESTDHANDLES

            cmd = _fixupCommand(cmd, self._env)

            creationFlags = win32process.CREATE_NEW_PROCESS_GROUP
            try:
                self._hProcess, hThread, self._processId, threadId\
                    = _SaferCreateProcess(
                        None,           # app name
                        cmd,            # command line 
                        None,           # process security attributes 
                        None,           # primary thread security attributes 
                        1,              # handles are inherited 
                        creationFlags,  # creation flags 
                        self._env,      # environment
                        self._cwd,      # current working directory
                        si)             # STARTUPINFO pointer 
            except win32api.error, ex:
                raise ProcessError(msg=ex.args[2], errno=ex.args[0])
            win32api.CloseHandle(hThread)

        finally:
            # Close child ends of pipes on the parent's side (the
            # parent's ends of the pipe are closed in the _FileWrappers.)
            win32file.CloseHandle(hChildStdinRd)
            win32file.CloseHandle(hChildStdoutWr)
            win32file.CloseHandle(hChildStderrWr)

    def wait(self, timeout=None): 
        """Wait for the started process to complete.
        
        "timeout" (on Windows) is a floating point number of seconds after
            which to timeout.  Default is win32event.INFINITE.
        "timeout" (on Unix) is akin to the os.waitpid() "options" argument
            (os.WNOHANG may be used to return immediately if the process has
            not exited). Default is 0, i.e. wait forever.

        If the wait time's out it will raise a ProcessError. Otherwise it
        will return the child's exit value (on Windows) or the child's exit
        status excoded as per os.waitpid() (on Linux):
            "a 16-bit number, whose low byte is the signal number that killed
            the process, and whose high byte is the exit status (if the
            signal number is zero); the high bit of the low byte is set if a
            core file was produced."
        In the latter case, use the os.W*() methods to interpret the return
        value.
        """
        # XXX Or should returning the exit value be move out to another
        #    function as on Win32 process control? If so, then should
        #    perhaps not make WaitForSingleObject semantic
        #    transformation.
        # TODO:
        #   - Need to rationalize the .wait() API for Windows vs. Unix.
        #     It is a real pain in the current situation.
        if sys.platform.startswith("win"):
            if timeout is None:
                timeout = win32event.INFINITE
            else:
                timeout = timeout * 1000.0 # Win32 API's timeout is in millisecs

            #rc = win32event.WaitForSingleObject(self._hProcess, timeout)
            rc = win32event.WaitForSingleObject(self._hProcess, int(timeout)) # MATT -- Making timeout an integer
            if rc == win32event.WAIT_FAILED:
                raise ProcessError("'WAIT_FAILED' when waiting for process to "\
                                   "terminate: %r" % self._cmd, rc)
            elif rc == win32event.WAIT_TIMEOUT:
                raise ProcessError("'WAIT_TIMEOUT' when waiting for process to "\
                                   "terminate: %r" % self._cmd, rc)

            retval = win32process.GetExitCodeProcess(self._hProcess)
        else:
            # os.waitpid() will raise:
            #       OSError: [Errno 10] No child processes
            # on subsequent .wait() calls. Change these semantics to have
            # subsequent .wait() calls return the exit status and return
            # immediately without raising an exception.
            # (XXX It would require synchronization code to handle the case
            # of multiple simultaneous .wait() requests, however we can punt
            # on that because it is moot while Linux still has the problem
            # for which _ThreadFixer() exists.)
            if self.__retvalCache is not None:
                retval = self.__retvalCache
            else:
                if timeout is None:
                    timeout = 0
                pid, sts = os.waitpid(self._pid, timeout)
                if pid == self._pid:
                    self.__retvalCache = retval = sts
                else:
                    raise ProcessError("Wait for process timed out.",
                                       self.WAIT_TIMEOUT)
        _unregisterProcess(self)
        return retval

    def kill(self, exitCode=0, gracePeriod=1.0, sig=None):
        """Kill process.
        
        "exitCode" [deprecated, not supported] (Windows only) is the
            code the terminated process should exit with.
        "gracePeriod" (Windows only) is a number of seconds the process is
            allowed to shutdown with a WM_CLOSE signal before a hard
            terminate is called.
        "sig" (Unix only) is the signal to use to kill the process. Defaults
            to signal.SIGKILL. See os.kill() for more information.

        Windows:
            Try for an orderly shutdown via WM_CLOSE.  If still running
            after gracePeriod (1 sec. default), terminate.
        """
        if sys.platform.startswith("win"):
            import win32gui
            # Send WM_CLOSE to windows in this process group.
            win32gui.EnumWindows(self._close_, 0)

            # Send Ctrl-Break signal to all processes attached to this
            # console. This is supposed to trigger shutdown handlers in
            # each of the processes.
            try:
                win32api.GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,
                                                  self._processId)
            except AttributeError:
                log.warn("The win32api module does not have "\
                         "GenerateConsoleCtrlEvent(). This may mean that "\
                         "parts of this process group have NOT been killed.")
            except win32api.error, ex:
                if ex.args[0] not in (6, 87):
                    # Ignore the following:
                    #   api_error: (87, 'GenerateConsoleCtrlEvent', 'The parameter is incorrect.')
                    #   api_error: (6, 'GenerateConsoleCtrlEvent', 'The handle is invalid.')
                    # Get error 6 if there is no console.
                    raise
            
            # Last resort: call TerminateProcess if it has not yet.
            retval = 0
            try:
                self.wait(gracePeriod)
            except ProcessError, ex:
                log.info("[%s] Process.kill: calling TerminateProcess", id(self))
                win32process.TerminateProcess(self._hProcess, -1)
                win32api.Sleep(100) # wait for resources to be released

        else:
            if sig is None:
                sig = signal.SIGKILL
            try:
                os.kill(self._pid, sig)
            except OSError, ex:
                if ex.errno != 3:
                    # Ignore:   OSError: [Errno 3] No such process
                    raise

        _unregisterProcess(self)

    def _close_(self, hwnd, dummy):
        """Callback used by .kill() on Windows.

        EnumWindows callback - sends WM_CLOSE to any window owned by this
        process.
        """
        threadId, processId = win32process.GetWindowThreadProcessId(hwnd)
        if processId == self._processId:
            import win32gui
            win32gui.PostMessage(hwnd, WM_CLOSE, 0, 0)


class ProcessProxy(Process):
    """Create a process and proxy communication via the standard handles.
    """
    #XXX To add to docstring:
    #   - stdout/stderr proxy handling
    #   - stdin proxy handling
    #   - termination
    #   - how to .start(), i.e. basic usage rules
    #   - mention that pased in stdin/stdout/stderr objects have to
    #     implement at least .write (is .write correct for stdin)?
    #   - if you pass in stdin, stdout, and/or stderr streams it is the
    #     user's responsibility to close them afterwards.
    #   - 'cmd' arg can be a command string or an arg vector
    #   - etc.
    #TODO:
    #   - .suspend() and .resume()? See Win32::Process Perl module.
    #
    def __init__(self, cmd, mode='t', cwd=None, env=None,
                 stdin=None, stdout=None, stderr=None):
        """Create a Process with proxy threads for each std handle.

        "cmd" is the command string or argument vector to run.
        "mode" (Windows only) specifies whether the pipes used to communicate
            with the child are openned in text, 't', or binary, 'b', mode.
            This is ignored on platforms other than Windows. Default is 't'.
        "cwd" optionally specifies the directory in which the child process
            should be started. Default is None, a.k.a. inherits the cwd from
            the parent.
        "env" is optionally a mapping specifying the environment in which to
            start the child. Default is None, a.k.a. inherits the environment
            of the parent.
        "stdin", "stdout", "stderr" can be used to specify objects with
            file-like interfaces to handle read (stdout/stderr) and write
            (stdin) events from the child. By default a process.IOBuffer
            instance is assigned to each handler. IOBuffer may be
            sub-classed. See the IOBuffer doc string for more information.
        """
        # Keep a reference to ensure it is around for this object's destruction.
        self.__log = log
        log.info("ProcessProxy.__init__(cmd=%r, mode=%r, cwd=%r, env=%r, "\
                 "stdin=%r, stdout=%r, stderr=%r)",
                 cmd, mode, cwd, env, stdin, stdout, stderr)
        self._cmd = cmd
        if not self._cmd:
            raise ProcessError("You must specify a command.")
        self._mode = mode
        if self._mode not in ('t', 'b'):
            raise ProcessError("'mode' must be 't' or 'b'.")
        self._cwd = cwd
        self._env = env
        if stdin is None:
            self.stdin = IOBuffer(name='<stdin>')
        else:
            self.stdin = stdin
        if stdout is None:
            self.stdout = IOBuffer(name='<stdout>')
        else:
            self.stdout = stdout
        if stderr is None:
            self.stderr = IOBuffer(name='<stderr>')
        else:
            self.stderr = stderr
        self._closed = 0

        if sys.platform.startswith("win"):
            self._startOnWindows()
        else:
            self.__retvalCache = None
            self._startOnUnix()

        _registerProcess(self)

    def __del__(self):
        #XXX Should probably not rely upon this.
        logres.info("[%s] 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -