15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import ctypes 25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import re 35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def ValidHandle(value, func, arguments): 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if value == 0: 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raise ctypes.WinError() 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return value 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import serial 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from serial.win32 import ULONG_PTR, is_64bit 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from ctypes.wintypes import HANDLE 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from ctypes.wintypes import BOOL 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from ctypes.wintypes import HWND 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from ctypes.wintypes import DWORD 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from ctypes.wintypes import WORD 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from ctypes.wintypes import LONG 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from ctypes.wintypes import ULONG 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from ctypes.wintypes import LPCSTR 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from ctypes.wintypes import HKEY 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from ctypes.wintypes import BYTE 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NULL = 0 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HDEVINFO = ctypes.c_void_p 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PCTSTR = ctypes.c_char_p 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PTSTR = ctypes.c_void_p 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)CHAR = ctypes.c_char 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)LPDWORD = PDWORD = ctypes.POINTER(DWORD) 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#~ LPBYTE = PBYTE = ctypes.POINTER(BYTE) 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)LPBYTE = PBYTE = ctypes.c_void_p # XXX avoids error about types 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ACCESS_MASK = DWORD 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)REGSAM = ACCESS_MASK 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def byte_buffer(length): 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Get a buffer for a string""" 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return (BYTE*length)() 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def string(buffer): 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) s = [] 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for c in buffer: 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if c == 0: break 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) s.append(chr(c & 0xff)) # "& 0xff": hack to convert signed to unsigned 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return ''.join(s) 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class GUID(ctypes.Structure): 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) _fields_ = [ 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ('Data1', DWORD), 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ('Data2', WORD), 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ('Data3', WORD), 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ('Data4', BYTE*8), 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ] 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def __str__(self): 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return "{%08x-%04x-%04x-%s-%s}" % ( 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.Data1, 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.Data2, 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.Data3, 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ''.join(["%02x" % d for d in self.Data4[:2]]), 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ''.join(["%02x" % d for d in self.Data4[2:]]), 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ) 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class SP_DEVINFO_DATA(ctypes.Structure): 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) _fields_ = [ 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ('cbSize', DWORD), 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ('ClassGuid', GUID), 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ('DevInst', DWORD), 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ('Reserved', ULONG_PTR), 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ] 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def __str__(self): 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return "ClassGuid:%s DevInst:%s" % (self.ClassGuid, self.DevInst) 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PSP_DEVINFO_DATA = ctypes.POINTER(SP_DEVINFO_DATA) 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PSP_DEVICE_INTERFACE_DETAIL_DATA = ctypes.c_void_p 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)setupapi = ctypes.windll.LoadLibrary("setupapi") 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiDestroyDeviceInfoList = setupapi.SetupDiDestroyDeviceInfoList 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiDestroyDeviceInfoList.argtypes = [HDEVINFO] 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiDestroyDeviceInfoList.restype = BOOL 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiClassGuidsFromName = setupapi.SetupDiClassGuidsFromNameA 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiClassGuidsFromName.argtypes = [PCTSTR, ctypes.POINTER(GUID), DWORD, PDWORD] 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiClassGuidsFromName.restype = BOOL 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiEnumDeviceInfo = setupapi.SetupDiEnumDeviceInfo 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiEnumDeviceInfo.argtypes = [HDEVINFO, DWORD, PSP_DEVINFO_DATA] 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiEnumDeviceInfo.restype = BOOL 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiGetClassDevs = setupapi.SetupDiGetClassDevsA 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiGetClassDevs.argtypes = [ctypes.POINTER(GUID), PCTSTR, HWND, DWORD] 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiGetClassDevs.restype = HDEVINFO 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiGetClassDevs.errcheck = ValidHandle 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiGetDeviceRegistryProperty = setupapi.SetupDiGetDeviceRegistryPropertyA 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiGetDeviceRegistryProperty.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD] 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiGetDeviceRegistryProperty.restype = BOOL 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiGetDeviceInstanceId = setupapi.SetupDiGetDeviceInstanceIdA 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiGetDeviceInstanceId.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, PTSTR, DWORD, PDWORD] 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiGetDeviceInstanceId.restype = BOOL 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiOpenDevRegKey = setupapi.SetupDiOpenDevRegKey 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiOpenDevRegKey.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM] 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SetupDiOpenDevRegKey.restype = HKEY 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)advapi32 = ctypes.windll.LoadLibrary("Advapi32") 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RegCloseKey = advapi32.RegCloseKey 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RegCloseKey.argtypes = [HKEY] 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RegCloseKey.restype = LONG 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RegQueryValueEx = advapi32.RegQueryValueExA 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RegQueryValueEx.argtypes = [HKEY, LPCSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD] 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RegQueryValueEx.restype = LONG 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DIGCF_PRESENT = 2 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DIGCF_DEVICEINTERFACE = 16 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)INVALID_HANDLE_VALUE = 0 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ERROR_INSUFFICIENT_BUFFER = 122 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SPDRP_HARDWAREID = 1 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)SPDRP_FRIENDLYNAME = 12 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DICS_FLAG_GLOBAL = 1 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DIREG_DEV = 0x00000001 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)KEY_READ = 0x20019 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# workaround for compatibility between Python 2.x and 3.x 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Ports = serial.to_bytes([80, 111, 114, 116, 115]) # "Ports" 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)PortName = serial.to_bytes([80, 111, 114, 116, 78, 97, 109, 101]) # "PortName" 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def comports(): 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GUIDs = (GUID*8)() # so far only seen one used, so hope 8 are enough... 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) guids_size = DWORD() 1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not SetupDiClassGuidsFromName( 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Ports, 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GUIDs, 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.sizeof(GUIDs), 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.byref(guids_size)): 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raise ctypes.WinError() 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # repeat for all possible GUIDs 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for index in range(guids_size.value): 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) g_hdi = SetupDiGetClassDevs( 1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.byref(GUIDs[index]), 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) None, 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NULL, 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DIGCF_PRESENT) # was DIGCF_PRESENT|DIGCF_DEVICEINTERFACE which misses CDC ports 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) devinfo = SP_DEVINFO_DATA() 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) devinfo.cbSize = ctypes.sizeof(devinfo) 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) index = 0 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) while SetupDiEnumDeviceInfo(g_hdi, index, ctypes.byref(devinfo)): 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) index += 1 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # get the real com port name 1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) hkey = SetupDiOpenDevRegKey( 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) g_hdi, 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.byref(devinfo), 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DICS_FLAG_GLOBAL, 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 0, 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DIREG_DEV, # DIREG_DRV for SW info 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) KEY_READ) 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) port_name_buffer = byte_buffer(250) 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) port_name_length = ULONG(ctypes.sizeof(port_name_buffer)) 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RegQueryValueEx( 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) hkey, 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PortName, 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) None, 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) None, 1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.byref(port_name_buffer), 1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.byref(port_name_length)) 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RegCloseKey(hkey) 1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # unfortunately does this method also include parallel ports. 1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # we could check for names starting with COM or just exclude LPT 1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # and hope that other "unknown" names are serial ports... 1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if string(port_name_buffer).startswith('LPT'): 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # hardware ID 1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) szHardwareID = byte_buffer(250) 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # try to get ID that includes serial number 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not SetupDiGetDeviceInstanceId( 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) g_hdi, 1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.byref(devinfo), 1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.byref(szHardwareID), 1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.sizeof(szHardwareID) - 1, 1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) None): 1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # fall back to more generic hardware ID if that would fail 1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not SetupDiGetDeviceRegistryProperty( 1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) g_hdi, 1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.byref(devinfo), 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SPDRP_HARDWAREID, 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) None, 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.byref(szHardwareID), 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.sizeof(szHardwareID) - 1, 1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) None): 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # Ignore ERROR_INSUFFICIENT_BUFFER 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raise ctypes.WinError() 2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # stringify 2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) szHardwareID_str = string(szHardwareID) 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # in case of USB, make a more readable string, similar to that form 2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # that we also generate on other platforms 2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if szHardwareID_str.startswith('USB'): 2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) m = re.search(r'VID_([0-9a-f]{4})&PID_([0-9a-f]{4})(\\(\w+))?', szHardwareID_str, re.I) 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if m: 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if m.group(4): 2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) szHardwareID_str = 'USB VID:PID=%s:%s SNR=%s' % (m.group(1), m.group(2), m.group(4)) 2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else: 2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) szHardwareID_str = 'USB VID:PID=%s:%s' % (m.group(1), m.group(2)) 2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # friendly name 2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) szFriendlyName = byte_buffer(250) 2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not SetupDiGetDeviceRegistryProperty( 2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) g_hdi, 2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.byref(devinfo), 2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SPDRP_FRIENDLYNAME, 2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) #~ SPDRP_DEVICEDESC, 2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) None, 2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.byref(szFriendlyName), 2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.sizeof(szFriendlyName) - 1, 2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) None): 2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # Ignore ERROR_INSUFFICIENT_BUFFER 2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) #~ if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: 2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) #~ raise IOError("failed to get details for %s (%s)" % (devinfo, szHardwareID.value)) 2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # ignore errors and still include the port in the list, friendly name will be same as port name 2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) yield string(port_name_buffer), 'n/a', szHardwareID_str 2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else: 2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) yield string(port_name_buffer), string(szFriendlyName), szHardwareID_str 2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SetupDiDestroyDeviceInfoList(g_hdi) 2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# test 2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)if __name__ == '__main__': 2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) import serial 2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for port, desc, hwid in sorted(comports()): 2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) print "%s: %s [%s]" % (port, desc, hwid) 241