1cef7893435aa41160dd1255c43cb8498279738ccChris Craikimport ctypes 2cef7893435aa41160dd1255c43cb8498279738ccChris Craikimport re 3cef7893435aa41160dd1255c43cb8498279738ccChris Craik 4cef7893435aa41160dd1255c43cb8498279738ccChris Craikdef ValidHandle(value, func, arguments): 5cef7893435aa41160dd1255c43cb8498279738ccChris Craik if value == 0: 6cef7893435aa41160dd1255c43cb8498279738ccChris Craik raise ctypes.WinError() 7cef7893435aa41160dd1255c43cb8498279738ccChris Craik return value 8cef7893435aa41160dd1255c43cb8498279738ccChris Craik 9cef7893435aa41160dd1255c43cb8498279738ccChris Craikimport serial 10cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom serial.win32 import ULONG_PTR, is_64bit 11cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom ctypes.wintypes import HANDLE 12cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom ctypes.wintypes import BOOL 13cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom ctypes.wintypes import HWND 14cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom ctypes.wintypes import DWORD 15cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom ctypes.wintypes import WORD 16cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom ctypes.wintypes import LONG 17cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom ctypes.wintypes import ULONG 18cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom ctypes.wintypes import LPCSTR 19cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom ctypes.wintypes import HKEY 20cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom ctypes.wintypes import BYTE 21cef7893435aa41160dd1255c43cb8498279738ccChris Craik 22cef7893435aa41160dd1255c43cb8498279738ccChris CraikNULL = 0 23cef7893435aa41160dd1255c43cb8498279738ccChris CraikHDEVINFO = ctypes.c_void_p 24cef7893435aa41160dd1255c43cb8498279738ccChris CraikPCTSTR = ctypes.c_char_p 25cef7893435aa41160dd1255c43cb8498279738ccChris CraikPTSTR = ctypes.c_void_p 26cef7893435aa41160dd1255c43cb8498279738ccChris CraikCHAR = ctypes.c_char 27cef7893435aa41160dd1255c43cb8498279738ccChris CraikLPDWORD = PDWORD = ctypes.POINTER(DWORD) 28cef7893435aa41160dd1255c43cb8498279738ccChris Craik#~ LPBYTE = PBYTE = ctypes.POINTER(BYTE) 29cef7893435aa41160dd1255c43cb8498279738ccChris CraikLPBYTE = PBYTE = ctypes.c_void_p # XXX avoids error about types 30cef7893435aa41160dd1255c43cb8498279738ccChris Craik 31cef7893435aa41160dd1255c43cb8498279738ccChris CraikACCESS_MASK = DWORD 32cef7893435aa41160dd1255c43cb8498279738ccChris CraikREGSAM = ACCESS_MASK 33cef7893435aa41160dd1255c43cb8498279738ccChris Craik 34cef7893435aa41160dd1255c43cb8498279738ccChris Craik 35cef7893435aa41160dd1255c43cb8498279738ccChris Craikdef byte_buffer(length): 36cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Get a buffer for a string""" 37cef7893435aa41160dd1255c43cb8498279738ccChris Craik return (BYTE*length)() 38cef7893435aa41160dd1255c43cb8498279738ccChris Craik 39cef7893435aa41160dd1255c43cb8498279738ccChris Craikdef string(buffer): 40cef7893435aa41160dd1255c43cb8498279738ccChris Craik s = [] 41cef7893435aa41160dd1255c43cb8498279738ccChris Craik for c in buffer: 42cef7893435aa41160dd1255c43cb8498279738ccChris Craik if c == 0: break 43cef7893435aa41160dd1255c43cb8498279738ccChris Craik s.append(chr(c & 0xff)) # "& 0xff": hack to convert signed to unsigned 44cef7893435aa41160dd1255c43cb8498279738ccChris Craik return ''.join(s) 45cef7893435aa41160dd1255c43cb8498279738ccChris Craik 46cef7893435aa41160dd1255c43cb8498279738ccChris Craik 47cef7893435aa41160dd1255c43cb8498279738ccChris Craikclass GUID(ctypes.Structure): 48cef7893435aa41160dd1255c43cb8498279738ccChris Craik _fields_ = [ 49cef7893435aa41160dd1255c43cb8498279738ccChris Craik ('Data1', DWORD), 50cef7893435aa41160dd1255c43cb8498279738ccChris Craik ('Data2', WORD), 51cef7893435aa41160dd1255c43cb8498279738ccChris Craik ('Data3', WORD), 52cef7893435aa41160dd1255c43cb8498279738ccChris Craik ('Data4', BYTE*8), 53cef7893435aa41160dd1255c43cb8498279738ccChris Craik ] 54cef7893435aa41160dd1255c43cb8498279738ccChris Craik def __str__(self): 55cef7893435aa41160dd1255c43cb8498279738ccChris Craik return "{%08x-%04x-%04x-%s-%s}" % ( 56cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.Data1, 57cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.Data2, 58cef7893435aa41160dd1255c43cb8498279738ccChris Craik self.Data3, 59cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''.join(["%02x" % d for d in self.Data4[:2]]), 60cef7893435aa41160dd1255c43cb8498279738ccChris Craik ''.join(["%02x" % d for d in self.Data4[2:]]), 61cef7893435aa41160dd1255c43cb8498279738ccChris Craik ) 62cef7893435aa41160dd1255c43cb8498279738ccChris Craik 63cef7893435aa41160dd1255c43cb8498279738ccChris Craikclass SP_DEVINFO_DATA(ctypes.Structure): 64cef7893435aa41160dd1255c43cb8498279738ccChris Craik _fields_ = [ 65cef7893435aa41160dd1255c43cb8498279738ccChris Craik ('cbSize', DWORD), 66cef7893435aa41160dd1255c43cb8498279738ccChris Craik ('ClassGuid', GUID), 67cef7893435aa41160dd1255c43cb8498279738ccChris Craik ('DevInst', DWORD), 68cef7893435aa41160dd1255c43cb8498279738ccChris Craik ('Reserved', ULONG_PTR), 69cef7893435aa41160dd1255c43cb8498279738ccChris Craik ] 70cef7893435aa41160dd1255c43cb8498279738ccChris Craik def __str__(self): 71cef7893435aa41160dd1255c43cb8498279738ccChris Craik return "ClassGuid:%s DevInst:%s" % (self.ClassGuid, self.DevInst) 72cef7893435aa41160dd1255c43cb8498279738ccChris CraikPSP_DEVINFO_DATA = ctypes.POINTER(SP_DEVINFO_DATA) 73cef7893435aa41160dd1255c43cb8498279738ccChris Craik 74cef7893435aa41160dd1255c43cb8498279738ccChris CraikPSP_DEVICE_INTERFACE_DETAIL_DATA = ctypes.c_void_p 75cef7893435aa41160dd1255c43cb8498279738ccChris Craik 76cef7893435aa41160dd1255c43cb8498279738ccChris Craiksetupapi = ctypes.windll.LoadLibrary("setupapi") 77cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiDestroyDeviceInfoList = setupapi.SetupDiDestroyDeviceInfoList 78cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiDestroyDeviceInfoList.argtypes = [HDEVINFO] 79cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiDestroyDeviceInfoList.restype = BOOL 80cef7893435aa41160dd1255c43cb8498279738ccChris Craik 81cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiClassGuidsFromName = setupapi.SetupDiClassGuidsFromNameA 82cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiClassGuidsFromName.argtypes = [PCTSTR, ctypes.POINTER(GUID), DWORD, PDWORD] 83cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiClassGuidsFromName.restype = BOOL 84cef7893435aa41160dd1255c43cb8498279738ccChris Craik 85cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiEnumDeviceInfo = setupapi.SetupDiEnumDeviceInfo 86cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiEnumDeviceInfo.argtypes = [HDEVINFO, DWORD, PSP_DEVINFO_DATA] 87cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiEnumDeviceInfo.restype = BOOL 88cef7893435aa41160dd1255c43cb8498279738ccChris Craik 89cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiGetClassDevs = setupapi.SetupDiGetClassDevsA 90cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiGetClassDevs.argtypes = [ctypes.POINTER(GUID), PCTSTR, HWND, DWORD] 91cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiGetClassDevs.restype = HDEVINFO 92cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiGetClassDevs.errcheck = ValidHandle 93cef7893435aa41160dd1255c43cb8498279738ccChris Craik 94cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiGetDeviceRegistryProperty = setupapi.SetupDiGetDeviceRegistryPropertyA 95cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiGetDeviceRegistryProperty.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD] 96cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiGetDeviceRegistryProperty.restype = BOOL 97cef7893435aa41160dd1255c43cb8498279738ccChris Craik 98cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiGetDeviceInstanceId = setupapi.SetupDiGetDeviceInstanceIdA 99cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiGetDeviceInstanceId.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, PTSTR, DWORD, PDWORD] 100cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiGetDeviceInstanceId.restype = BOOL 101cef7893435aa41160dd1255c43cb8498279738ccChris Craik 102cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiOpenDevRegKey = setupapi.SetupDiOpenDevRegKey 103cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiOpenDevRegKey.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM] 104cef7893435aa41160dd1255c43cb8498279738ccChris CraikSetupDiOpenDevRegKey.restype = HKEY 105cef7893435aa41160dd1255c43cb8498279738ccChris Craik 106cef7893435aa41160dd1255c43cb8498279738ccChris Craikadvapi32 = ctypes.windll.LoadLibrary("Advapi32") 107cef7893435aa41160dd1255c43cb8498279738ccChris CraikRegCloseKey = advapi32.RegCloseKey 108cef7893435aa41160dd1255c43cb8498279738ccChris CraikRegCloseKey.argtypes = [HKEY] 109cef7893435aa41160dd1255c43cb8498279738ccChris CraikRegCloseKey.restype = LONG 110cef7893435aa41160dd1255c43cb8498279738ccChris Craik 111cef7893435aa41160dd1255c43cb8498279738ccChris CraikRegQueryValueEx = advapi32.RegQueryValueExA 112cef7893435aa41160dd1255c43cb8498279738ccChris CraikRegQueryValueEx.argtypes = [HKEY, LPCSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD] 113cef7893435aa41160dd1255c43cb8498279738ccChris CraikRegQueryValueEx.restype = LONG 114cef7893435aa41160dd1255c43cb8498279738ccChris Craik 115cef7893435aa41160dd1255c43cb8498279738ccChris Craik 116cef7893435aa41160dd1255c43cb8498279738ccChris CraikDIGCF_PRESENT = 2 117cef7893435aa41160dd1255c43cb8498279738ccChris CraikDIGCF_DEVICEINTERFACE = 16 118cef7893435aa41160dd1255c43cb8498279738ccChris CraikINVALID_HANDLE_VALUE = 0 119cef7893435aa41160dd1255c43cb8498279738ccChris CraikERROR_INSUFFICIENT_BUFFER = 122 120cef7893435aa41160dd1255c43cb8498279738ccChris CraikSPDRP_HARDWAREID = 1 121cef7893435aa41160dd1255c43cb8498279738ccChris CraikSPDRP_FRIENDLYNAME = 12 122cef7893435aa41160dd1255c43cb8498279738ccChris CraikDICS_FLAG_GLOBAL = 1 123cef7893435aa41160dd1255c43cb8498279738ccChris CraikDIREG_DEV = 0x00000001 124cef7893435aa41160dd1255c43cb8498279738ccChris CraikKEY_READ = 0x20019 125cef7893435aa41160dd1255c43cb8498279738ccChris Craik 126cef7893435aa41160dd1255c43cb8498279738ccChris Craik# workaround for compatibility between Python 2.x and 3.x 127cef7893435aa41160dd1255c43cb8498279738ccChris CraikPorts = serial.to_bytes([80, 111, 114, 116, 115]) # "Ports" 128cef7893435aa41160dd1255c43cb8498279738ccChris CraikPortName = serial.to_bytes([80, 111, 114, 116, 78, 97, 109, 101]) # "PortName" 129cef7893435aa41160dd1255c43cb8498279738ccChris Craik 130cef7893435aa41160dd1255c43cb8498279738ccChris Craikdef comports(): 131cef7893435aa41160dd1255c43cb8498279738ccChris Craik GUIDs = (GUID*8)() # so far only seen one used, so hope 8 are enough... 132cef7893435aa41160dd1255c43cb8498279738ccChris Craik guids_size = DWORD() 133cef7893435aa41160dd1255c43cb8498279738ccChris Craik if not SetupDiClassGuidsFromName( 134cef7893435aa41160dd1255c43cb8498279738ccChris Craik Ports, 135cef7893435aa41160dd1255c43cb8498279738ccChris Craik GUIDs, 136cef7893435aa41160dd1255c43cb8498279738ccChris Craik ctypes.sizeof(GUIDs), 137cef7893435aa41160dd1255c43cb8498279738ccChris Craik ctypes.byref(guids_size)): 138cef7893435aa41160dd1255c43cb8498279738ccChris Craik raise ctypes.WinError() 139cef7893435aa41160dd1255c43cb8498279738ccChris Craik 140cef7893435aa41160dd1255c43cb8498279738ccChris Craik # repeat for all possible GUIDs 141cef7893435aa41160dd1255c43cb8498279738ccChris Craik for index in range(guids_size.value): 142cef7893435aa41160dd1255c43cb8498279738ccChris Craik g_hdi = SetupDiGetClassDevs( 143cef7893435aa41160dd1255c43cb8498279738ccChris Craik ctypes.byref(GUIDs[index]), 144cef7893435aa41160dd1255c43cb8498279738ccChris Craik None, 145cef7893435aa41160dd1255c43cb8498279738ccChris Craik NULL, 146cef7893435aa41160dd1255c43cb8498279738ccChris Craik DIGCF_PRESENT) # was DIGCF_PRESENT|DIGCF_DEVICEINTERFACE which misses CDC ports 147cef7893435aa41160dd1255c43cb8498279738ccChris Craik 148cef7893435aa41160dd1255c43cb8498279738ccChris Craik devinfo = SP_DEVINFO_DATA() 149cef7893435aa41160dd1255c43cb8498279738ccChris Craik devinfo.cbSize = ctypes.sizeof(devinfo) 150cef7893435aa41160dd1255c43cb8498279738ccChris Craik index = 0 151cef7893435aa41160dd1255c43cb8498279738ccChris Craik while SetupDiEnumDeviceInfo(g_hdi, index, ctypes.byref(devinfo)): 152cef7893435aa41160dd1255c43cb8498279738ccChris Craik index += 1 153cef7893435aa41160dd1255c43cb8498279738ccChris Craik 154cef7893435aa41160dd1255c43cb8498279738ccChris Craik # get the real com port name 155cef7893435aa41160dd1255c43cb8498279738ccChris Craik hkey = SetupDiOpenDevRegKey( 156cef7893435aa41160dd1255c43cb8498279738ccChris Craik g_hdi, 157cef7893435aa41160dd1255c43cb8498279738ccChris Craik ctypes.byref(devinfo), 158cef7893435aa41160dd1255c43cb8498279738ccChris Craik DICS_FLAG_GLOBAL, 159cef7893435aa41160dd1255c43cb8498279738ccChris Craik 0, 160cef7893435aa41160dd1255c43cb8498279738ccChris Craik DIREG_DEV, # DIREG_DRV for SW info 161cef7893435aa41160dd1255c43cb8498279738ccChris Craik KEY_READ) 162cef7893435aa41160dd1255c43cb8498279738ccChris Craik port_name_buffer = byte_buffer(250) 163cef7893435aa41160dd1255c43cb8498279738ccChris Craik port_name_length = ULONG(ctypes.sizeof(port_name_buffer)) 164cef7893435aa41160dd1255c43cb8498279738ccChris Craik RegQueryValueEx( 165cef7893435aa41160dd1255c43cb8498279738ccChris Craik hkey, 166cef7893435aa41160dd1255c43cb8498279738ccChris Craik PortName, 167cef7893435aa41160dd1255c43cb8498279738ccChris Craik None, 168cef7893435aa41160dd1255c43cb8498279738ccChris Craik None, 169cef7893435aa41160dd1255c43cb8498279738ccChris Craik ctypes.byref(port_name_buffer), 170cef7893435aa41160dd1255c43cb8498279738ccChris Craik ctypes.byref(port_name_length)) 171cef7893435aa41160dd1255c43cb8498279738ccChris Craik RegCloseKey(hkey) 172cef7893435aa41160dd1255c43cb8498279738ccChris Craik 173cef7893435aa41160dd1255c43cb8498279738ccChris Craik # unfortunately does this method also include parallel ports. 174cef7893435aa41160dd1255c43cb8498279738ccChris Craik # we could check for names starting with COM or just exclude LPT 175cef7893435aa41160dd1255c43cb8498279738ccChris Craik # and hope that other "unknown" names are serial ports... 176cef7893435aa41160dd1255c43cb8498279738ccChris Craik if string(port_name_buffer).startswith('LPT'): 177cef7893435aa41160dd1255c43cb8498279738ccChris Craik continue 178cef7893435aa41160dd1255c43cb8498279738ccChris Craik 179cef7893435aa41160dd1255c43cb8498279738ccChris Craik # hardware ID 180cef7893435aa41160dd1255c43cb8498279738ccChris Craik szHardwareID = byte_buffer(250) 181cef7893435aa41160dd1255c43cb8498279738ccChris Craik # try to get ID that includes serial number 182cef7893435aa41160dd1255c43cb8498279738ccChris Craik if not SetupDiGetDeviceInstanceId( 183cef7893435aa41160dd1255c43cb8498279738ccChris Craik g_hdi, 184cef7893435aa41160dd1255c43cb8498279738ccChris Craik ctypes.byref(devinfo), 185cef7893435aa41160dd1255c43cb8498279738ccChris Craik ctypes.byref(szHardwareID), 186cef7893435aa41160dd1255c43cb8498279738ccChris Craik ctypes.sizeof(szHardwareID) - 1, 187cef7893435aa41160dd1255c43cb8498279738ccChris Craik None): 188cef7893435aa41160dd1255c43cb8498279738ccChris Craik # fall back to more generic hardware ID if that would fail 189cef7893435aa41160dd1255c43cb8498279738ccChris Craik if not SetupDiGetDeviceRegistryProperty( 190cef7893435aa41160dd1255c43cb8498279738ccChris Craik g_hdi, 191cef7893435aa41160dd1255c43cb8498279738ccChris Craik ctypes.byref(devinfo), 192cef7893435aa41160dd1255c43cb8498279738ccChris Craik SPDRP_HARDWAREID, 193cef7893435aa41160dd1255c43cb8498279738ccChris Craik None, 194cef7893435aa41160dd1255c43cb8498279738ccChris Craik ctypes.byref(szHardwareID), 195cef7893435aa41160dd1255c43cb8498279738ccChris Craik ctypes.sizeof(szHardwareID) - 1, 196cef7893435aa41160dd1255c43cb8498279738ccChris Craik None): 197cef7893435aa41160dd1255c43cb8498279738ccChris Craik # Ignore ERROR_INSUFFICIENT_BUFFER 198cef7893435aa41160dd1255c43cb8498279738ccChris Craik if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: 199cef7893435aa41160dd1255c43cb8498279738ccChris Craik raise ctypes.WinError() 200cef7893435aa41160dd1255c43cb8498279738ccChris Craik # stringify 201cef7893435aa41160dd1255c43cb8498279738ccChris Craik szHardwareID_str = string(szHardwareID) 202cef7893435aa41160dd1255c43cb8498279738ccChris Craik 203cef7893435aa41160dd1255c43cb8498279738ccChris Craik # in case of USB, make a more readable string, similar to that form 204cef7893435aa41160dd1255c43cb8498279738ccChris Craik # that we also generate on other platforms 205cef7893435aa41160dd1255c43cb8498279738ccChris Craik if szHardwareID_str.startswith('USB'): 206cef7893435aa41160dd1255c43cb8498279738ccChris Craik m = re.search(r'VID_([0-9a-f]{4})&PID_([0-9a-f]{4})(\\(\w+))?', szHardwareID_str, re.I) 207cef7893435aa41160dd1255c43cb8498279738ccChris Craik if m: 208cef7893435aa41160dd1255c43cb8498279738ccChris Craik if m.group(4): 209cef7893435aa41160dd1255c43cb8498279738ccChris Craik szHardwareID_str = 'USB VID:PID=%s:%s SNR=%s' % (m.group(1), m.group(2), m.group(4)) 210cef7893435aa41160dd1255c43cb8498279738ccChris Craik else: 211cef7893435aa41160dd1255c43cb8498279738ccChris Craik szHardwareID_str = 'USB VID:PID=%s:%s' % (m.group(1), m.group(2)) 212cef7893435aa41160dd1255c43cb8498279738ccChris Craik 213cef7893435aa41160dd1255c43cb8498279738ccChris Craik # friendly name 214cef7893435aa41160dd1255c43cb8498279738ccChris Craik szFriendlyName = byte_buffer(250) 215cef7893435aa41160dd1255c43cb8498279738ccChris Craik if not SetupDiGetDeviceRegistryProperty( 216cef7893435aa41160dd1255c43cb8498279738ccChris Craik g_hdi, 217cef7893435aa41160dd1255c43cb8498279738ccChris Craik ctypes.byref(devinfo), 218cef7893435aa41160dd1255c43cb8498279738ccChris Craik SPDRP_FRIENDLYNAME, 219cef7893435aa41160dd1255c43cb8498279738ccChris Craik #~ SPDRP_DEVICEDESC, 220cef7893435aa41160dd1255c43cb8498279738ccChris Craik None, 221cef7893435aa41160dd1255c43cb8498279738ccChris Craik ctypes.byref(szFriendlyName), 222cef7893435aa41160dd1255c43cb8498279738ccChris Craik ctypes.sizeof(szFriendlyName) - 1, 223cef7893435aa41160dd1255c43cb8498279738ccChris Craik None): 224cef7893435aa41160dd1255c43cb8498279738ccChris Craik # Ignore ERROR_INSUFFICIENT_BUFFER 225cef7893435aa41160dd1255c43cb8498279738ccChris Craik #~ if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: 226cef7893435aa41160dd1255c43cb8498279738ccChris Craik #~ raise IOError("failed to get details for %s (%s)" % (devinfo, szHardwareID.value)) 227cef7893435aa41160dd1255c43cb8498279738ccChris Craik # ignore errors and still include the port in the list, friendly name will be same as port name 228cef7893435aa41160dd1255c43cb8498279738ccChris Craik yield string(port_name_buffer), 'n/a', szHardwareID_str 229cef7893435aa41160dd1255c43cb8498279738ccChris Craik else: 230cef7893435aa41160dd1255c43cb8498279738ccChris Craik yield string(port_name_buffer), string(szFriendlyName), szHardwareID_str 231cef7893435aa41160dd1255c43cb8498279738ccChris Craik 232cef7893435aa41160dd1255c43cb8498279738ccChris Craik SetupDiDestroyDeviceInfoList(g_hdi) 233cef7893435aa41160dd1255c43cb8498279738ccChris Craik 234cef7893435aa41160dd1255c43cb8498279738ccChris Craik# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 235cef7893435aa41160dd1255c43cb8498279738ccChris Craik# test 236cef7893435aa41160dd1255c43cb8498279738ccChris Craikif __name__ == '__main__': 237cef7893435aa41160dd1255c43cb8498279738ccChris Craik import serial 238cef7893435aa41160dd1255c43cb8498279738ccChris Craik 239cef7893435aa41160dd1255c43cb8498279738ccChris Craik for port, desc, hwid in sorted(comports()): 240cef7893435aa41160dd1255c43cb8498279738ccChris Craik print "%s: %s [%s]" % (port, desc, hwid) 241