How can I fix “[Error 6] The handle is invalid.” with PySerial

前端 未结 5 2018
一个人的身影
一个人的身影 2020-12-11 04:25

I\'m trying to connect to my phone from my Windows 7 PC using PySerial with the following code:

import wmi
import serial

c = wmi.WMI()
modem = c.query(\"SEL         


        
5条回答
  •  眼角桃花
    2020-12-11 05:05

    I have just fixed this problem on 64bit windows (XP, Vista and 7).

    This problem is caused by the invalid handle casting which discard the upper 32-bit of 64-bit value due to old python-win32 functions. If you faced this kind of problem, please use the new python-win32 functions which is included in the win32file etc. modules. Please write the following code over site-packages\serial\serialwin32.py.

    #! python
    # Python Serial Port Extension for Win32, Linux, BSD, Jython
    # serial driver for win32
    # see __init__.py
    #
    # (C) 2001-2009 Chris Liechti 
    # this is distributed under a free software license, see license.txt
    #
    # Initial patch to use ctypes by Giovanni Bajo 
    
    import ctypes
    import win32
    import win32file
    import win32con
    import pywintypes
    
    from serialutil import *
    
    def device(portnum):
        """Turn a port number into a device name"""
        return 'COM%d' % (portnum+1) # numbers are transformed to a string
    
    class Win32Serial(SerialBase):
        """Serial port implementation for Win32 based on ctypes."""
    
        BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
                     9600, 19200, 38400, 57600, 115200)
    
        def __init__(self, *args, **kwargs):
            self.hComPort = None
            SerialBase.__init__(self, *args, **kwargs)
    
        def open(self):
            """Open port with current settings. This may throw a SerialException
               if the port cannot be opened."""
            if self._port is None:
                raise SerialException("Port must be configured before it can be used.")
            # the "\\.\COMx" format is required for devices other than COM1-COM8
            # not all versions of windows seem to support this properly
            # so that the first few ports are used with the DOS device name
            port = self.portstr
            try:
                if port.upper().startswith('COM') and int(port[3:]) > 8:
                    port = '\\\\.\\' + port
            except ValueError:
                # for like COMnotanumber
                pass
            self.hComPort = win32file.CreateFile(port,
                   win32con.GENERIC_READ | win32con.GENERIC_WRITE,
                   0, # exclusive access
                   None, # no security
                   win32con.OPEN_EXISTING,
                   win32con.FILE_ATTRIBUTE_NORMAL | win32con.FILE_FLAG_OVERLAPPED,
                   0)
            if self.hComPort == win32.INVALID_HANDLE_VALUE:
                self.hComPort = None    # 'cause __del__ is called anyway
                raise SerialException("could not open port %s: %s" % (self.portstr, ctypes.WinError()))
    
            # Setup a 4k buffer
            win32file.SetupComm(self.hComPort, 4096, 4096)
    
            # Save original timeout values:
            tos = win32file.GetCommTimeouts(self.hComPort)
            self._orgTimeouts = win32.COMMTIMEOUTS(*tos)
            self._rtsState = win32.RTS_CONTROL_ENABLE
            self._dtrState = win32.DTR_CONTROL_ENABLE
    
            self._reconfigurePort()
    
            # Clear buffers:
            # Remove anything that was there
            win32file.PurgeComm(self.hComPort,
                                win32.PURGE_TXCLEAR | win32.PURGE_TXABORT |
                                win32.PURGE_RXCLEAR | win32.PURGE_RXABORT)
    
            self._overlappedRead = pywintypes.OVERLAPPED()
            self._overlappedRead.hEvent = win32.CreateEvent(None, 1, 0, None)
            self._overlappedWrite = pywintypes.OVERLAPPED()
            #~ self._overlappedWrite.hEvent = win32.CreateEvent(None, 1, 0, None)
            self._overlappedWrite.hEvent = win32.CreateEvent(None, 0, 0, None)
            self._isOpen = True
    
        def _reconfigurePort(self):
            """Set communication parameters on opened port."""
            if not self.hComPort:
                raise SerialException("Can only operate on a valid port handle")
    
            # Set Windows timeout values
            # timeouts is a tuple with the following items:
            # (ReadIntervalTimeout,ReadTotalTimeoutMultiplier,
            #  ReadTotalTimeoutConstant,WriteTotalTimeoutMultiplier,
            #  WriteTotalTimeoutConstant)
            if self._timeout is None:
                timeouts = (0, 0, 0, 0, 0)
            elif self._timeout == 0:
                timeouts = (win32.MAXDWORD, 0, 0, 0, 0)
            else:
                timeouts = (0, 0, int(self._timeout*1000), 0, 0)
            if self._timeout != 0 and self._interCharTimeout is not None:
                timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:]
    
            if self._writeTimeout is None:
                pass
            elif self._writeTimeout == 0:
                timeouts = timeouts[:-2] + (0, win32.MAXDWORD)
            else:
                timeouts = timeouts[:-2] + (0, int(self._writeTimeout*1000))
            win32file.SetCommTimeouts(self.hComPort, timeouts)
    
            win32file.SetCommMask(self.hComPort, win32.EV_ERR)
    
            # Setup the connection info.
            # Get state and modify it:
            comDCB = win32file.GetCommState(self.hComPort)
            comDCB.BaudRate = self._baudrate
    
            if self._bytesize == FIVEBITS:
                comDCB.ByteSize     = 5
            elif self._bytesize == SIXBITS:
                comDCB.ByteSize     = 6
            elif self._bytesize == SEVENBITS:
                comDCB.ByteSize     = 7
            elif self._bytesize == EIGHTBITS:
                comDCB.ByteSize     = 8
            else:
                raise ValueError("Unsupported number of data bits: %r" % self._bytesize)
    
            if self._parity == PARITY_NONE:
                comDCB.Parity       = win32.NOPARITY
                comDCB.fParity      = 0 # Disable Parity Check
            elif self._parity == PARITY_EVEN:
                comDCB.Parity       = win32.EVENPARITY
                comDCB.fParity      = 1 # Enable Parity Check
            elif self._parity == PARITY_ODD:
                comDCB.Parity       = win32.ODDPARITY
                comDCB.fParity      = 1 # Enable Parity Check
            elif self._parity == PARITY_MARK:
                comDCB.Parity       = win32.MARKPARITY
                comDCB.fParity      = 1 # Enable Parity Check
            elif self._parity == PARITY_SPACE:
                comDCB.Parity       = win32.SPACEPARITY
                comDCB.fParity      = 1 # Enable Parity Check
            else:
                raise ValueError("Unsupported parity mode: %r" % self._parity)
    
            if self._stopbits == STOPBITS_ONE:
                comDCB.StopBits     = win32.ONESTOPBIT
            elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
                comDCB.StopBits     = win32.ONE5STOPBITS
            elif self._stopbits == STOPBITS_TWO:
                comDCB.StopBits     = win32.TWOSTOPBITS
            else:
                raise ValueError("Unsupported number of stop bits: %r" % self._stopbits)
    
            comDCB.fBinary          = 1 # Enable Binary Transmission
            # Char. w/ Parity-Err are replaced with 0xff (if fErrorChar is set to TRUE)
            if self._rtscts:
                comDCB.fRtsControl  = win32.RTS_CONTROL_HANDSHAKE
            else:
                comDCB.fRtsControl  = self._rtsState
            if self._dsrdtr:
                comDCB.fDtrControl  = win32.DTR_CONTROL_HANDSHAKE
            else:
                comDCB.fDtrControl  = self._dtrState
            comDCB.fOutxCtsFlow     = self._rtscts
            comDCB.fOutxDsrFlow     = self._dsrdtr
            comDCB.fOutX            = self._xonxoff
            comDCB.fInX             = self._xonxoff
            comDCB.fNull            = 0
            comDCB.fErrorChar       = 0
            comDCB.fAbortOnError    = 0
            comDCB.XonChar          = XON
            comDCB.XoffChar         = XOFF
            win32file.SetCommState(self.hComPort, comDCB)
    
        #~ def __del__(self):
            #~ self.close()
    
        def close(self):
            """Close port"""
            if self._isOpen:
                if self.hComPort:
                    # Restore original timeout values:
                    win32file.SetCommTimeouts(self.hComPort, self._orgTimeouts)
                    # Close COM-Port:
                    win32file.CloseHandle(self.hComPort)
                    win32file.CloseHandle(self._overlappedRead.hEvent)
                    win32file.CloseHandle(self._overlappedWrite.hEvent)
                    self.hComPort = None
                self._isOpen = False
    
        def makeDeviceName(self, port):
            return device(port)
    
        #  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
    
        def inWaiting(self):
            """Return the number of characters currently in the input buffer."""
            flags = win32.DWORD()
            comstat = win32.COMSTAT()
            if not win32file.ClearCommError(self.hComPort, ctypes.byref(flags), ctypes.byref(comstat)):
                raise SerialException('call to ClearCommError failed')
            return comstat.cbInQue
    
        def read(self, size=1):
            """Read size bytes from the serial port. If a timeout is set it may
               return less characters as requested. With no timeout it will block
               until the requested number of bytes is read."""
            if not self.hComPort: raise portNotOpenError
            if size > 0:
                win32.ResetEvent(self._overlappedRead.hEvent)
                if not win32file.ClearCommError(self.hComPort):
                    raise SerialException('call to ClearCommError failed')
                if self.timeout == 0:
                    n = min(comstat.cbInQue, size)
                    if n > 0:
                        rc,buf = win32file.ReadFile(self.hComPort, n, self._overlappedRead)
                        if win32.GetLastError() != win32.ERROR_IO_PENDING:
                            raise SerialException("ReadFile failed (%s)" % ctypes.WinError())
                        err = win32.WaitForSingleObject(self._overlappedRead.hEvent, win32.INFINITE)
                        read = buf[:rc]
                    else:
                        read = bytes()
                else:
                    rc,buf = win32file.ReadFile(self.hComPort, size, self._overlappedRead)
                    rc = win32file.GetOverlappedResult(self.hComPort, self._overlappedRead, True)
                    read = buf[:rc]
            else:
                read = bytes()
            return bytes(read)
    
        def write(self, data):
            """Output the given string over the serial port."""
            if not self.hComPort: raise portNotOpenError
            #~ if not isinstance(data, (bytes, bytearray)):
                #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
            # convert data (needed in case of memoryview instance: Py 3.1 io lib), ctypes doesn't like memoryview
            if data:
                #~ win32event.ResetEvent(self._overlappedWrite.hEvent)
                err,n = win32file.WriteFile(self.hComPort, data, self._overlappedWrite)
                if not err and win32.GetLastError() != win32.ERROR_IO_PENDING:
                    raise SerialException("WriteFile failed (%s)" % ctypes.WinError())
                # Wait for the write to complete.
                #~ win32.WaitForSingleObject(self._overlappedWrite.hEvent, win32.INFINITE)
                n = win32file.GetOverlappedResult(self.hComPort, self._overlappedWrite, True)
                if n != len(data):
                    raise writeTimeoutError
                return n
            else:
                return 0
    
        def flushInput(self):
            """Clear input buffer, discarding all that is in the buffer."""
            if not self.hComPort: raise portNotOpenError
            win32.PurgeComm(self.hComPort, win32.PURGE_RXCLEAR | win32.PURGE_RXABORT)
    
        def flushOutput(self):
            """Clear output buffer, aborting the current output and
            discarding all that is in the buffer."""
            if not self.hComPort: raise portNotOpenError
            win32.PurgeComm(self.hComPort, win32.PURGE_TXCLEAR | win32.PURGE_TXABORT)
    
        def sendBreak(self, duration=0.25):
            """Send break condition. Timed, returns to idle state after given duration."""
            if not self.hComPort: raise portNotOpenError
            import time
            win32.SetCommBreak(self.hComPort)
            time.sleep(duration)
            win32.ClearCommBreak(self.hComPort)
    
        def setBreak(self, level=1):
            """Set break: Controls TXD. When active, to transmitting is possible."""
            if not self.hComPort: raise portNotOpenError
            if level:
                win32.SetCommBreak(self.hComPort)
            else:
                win32.ClearCommBreak(self.hComPort)
    
        def setRTS(self, level=1):
            """Set terminal status line: Request To Send"""
            if not self.hComPort: raise portNotOpenError
            if level:
                self._rtsState = win32.RTS_CONTROL_ENABLE
                win32.EscapeCommFunction(self.hComPort, win32.SETRTS)
            else:
                self._rtsState = win32.RTS_CONTROL_DISABLE
                win32.EscapeCommFunction(self.hComPort, win32.CLRRTS)
    
        def setDTR(self, level=1):
            """Set terminal status line: Data Terminal Ready"""
            if not self.hComPort: raise portNotOpenError
            if level:
                self._dtrState = win32.DTR_CONTROL_ENABLE
                win32.EscapeCommFunction(self.hComPort, win32.SETDTR)
            else:
                self._dtrState = win32.DTR_CONTROL_DISABLE
                win32.EscapeCommFunction(self.hComPort, win32.CLRDTR)
    
        def _GetCommModemStatus(self):
            stat = win32.DWORD()
            win32.GetCommModemStatus(self.hComPort, ctypes.byref(stat))
            return stat.value
    
        def getCTS(self):
            """Read terminal status line: Clear To Send"""
            if not self.hComPort: raise portNotOpenError
            return win32.MS_CTS_ON & self._GetCommModemStatus() != 0
    
        def getDSR(self):
            """Read terminal status line: Data Set Ready"""
            if not self.hComPort: raise portNotOpenError
            return win32.MS_DSR_ON & self._GetCommModemStatus() != 0
    
        def getRI(self):
            """Read terminal status line: Ring Indicator"""
            if not self.hComPort: raise portNotOpenError
            return win32.MS_RING_ON & self._GetCommModemStatus() != 0
    
        def getCD(self):
            """Read terminal status line: Carrier Detect"""
            if not self.hComPort: raise portNotOpenError
            return win32.MS_RLSD_ON & self._GetCommModemStatus() != 0
    
        # - - platform specific - - - -
    
        def setXON(self, level=True):
            """Platform specific - set flow state."""
            if not self.hComPort: raise portNotOpenError
            if level:
                win32.EscapeCommFunction(self.hComPort, win32.SETXON)
            else:
                win32.EscapeCommFunction(self.hComPort, win32.SETXOFF)
    
        def outWaiting(self):
            """return how many characters the in the outgoing buffer"""
            flags = win32.DWORD()
            comstat = win32.COMSTAT()
            if not win32.ClearCommError(self.hComPort, ctypes.byref(flags), ctypes.byref(comstat)):
                raise SerialException('call to ClearCommError failed')
            return comstat.cbOutQue
    
    # assemble Serial class with the platform specific implementation and the base
    # for file-like behavior. for Python 2.6 and newer, that provide the new I/O
    # library, derive from io.RawIOBase
    try:
        import io
    except ImportError:
        # classic version with our own file-like emulation
        class Serial(Win32Serial, FileLike):
            pass
    else:
        # io library present
        class Serial(Win32Serial, io.RawIOBase):
            pass
    
    # Nur Testfunktion!!
    if __name__ == '__main__':
        s = Serial(0)
        sys.stdout.write("%s\n" % s)
    
        s = Serial()
        sys.stdout.write("%s\n" % s)
    
        s.baudrate = 19200
        s.databits = 7
        s.close()
        s.port = 0
        s.open()
        sys.stdout.write("%s\n" % s)
    

提交回复
热议问题