From 6a5185b55c57f56abe67cead08925ac78fb1830b Mon Sep 17 00:00:00 2001 From: cliechti Date: Mon, 14 Oct 2013 03:35:33 +0000 Subject: modified enumeration algo so that it picks up CDC devices too git-svn-id: http://svn.code.sf.net/p/pyserial/code/trunk/pyserial@478 f19166aa-fa4f-0410-85c2-fa1106f25c8a --- serial/tools/list_ports_windows.py | 119 +++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 64 deletions(-) diff --git a/serial/tools/list_ports_windows.py b/serial/tools/list_ports_windows.py index 6014a18..f4ec8bd 100644 --- a/serial/tools/list_ports_windows.py +++ b/serial/tools/list_ports_windows.py @@ -89,6 +89,14 @@ SetupDiDestroyDeviceInfoList = setupapi.SetupDiDestroyDeviceInfoList SetupDiDestroyDeviceInfoList.argtypes = [HDEVINFO] SetupDiDestroyDeviceInfoList.restype = BOOL +SetupDiClassGuidsFromName = setupapi.SetupDiClassGuidsFromNameA +SetupDiClassGuidsFromName.argtypes = [PCTSTR, ctypes.POINTER(GUID), DWORD, PDWORD] +SetupDiClassGuidsFromName.restype = BOOL + +SetupDiEnumDeviceInfo = setupapi.SetupDiEnumDeviceInfo +SetupDiEnumDeviceInfo.argtypes = [HDEVINFO, DWORD, PSP_DEVINFO_DATA] +SetupDiEnumDeviceInfo.restype = BOOL + SetupDiGetClassDevs = setupapi.SetupDiGetClassDevsA SetupDiGetClassDevs.argtypes = [ctypes.POINTER(GUID), PCTSTR, HWND, DWORD] SetupDiGetClassDevs.restype = HDEVINFO @@ -120,9 +128,6 @@ RegQueryValueEx.argtypes = [HKEY, LPCSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD] RegQueryValueEx.restype = LONG -GUID_CLASS_COMPORT = GUID(0x86e0d1e0L, 0x8089, 0x11d0, - (BYTE*8)(0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73)) - DIGCF_PRESENT = 2 DIGCF_DEVICEINTERFACE = 16 INVALID_HANDLE_VALUE = 0 @@ -136,73 +141,59 @@ KEY_READ = 0x20019 REG_SZ = 1 # workaround for compatibility between Python 2.x and 3.x +Ports = serial.to_bytes([80, 111, 114, 116, 115]) # "Ports" PortName = serial.to_bytes([80, 111, 114, 116, 78, 97, 109, 101]) # "PortName" NA = serial.to_bytes([110, 47, 97]) # "n/a" def comports(): - """This generator scans the device registry for com ports and yields port, desc, hwid""" - g_hdi = SetupDiGetClassDevs(ctypes.byref(GUID_CLASS_COMPORT), None, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); - #~ for i in range(256): - for dwIndex in range(256): - did = SP_DEVICE_INTERFACE_DATA() - did.cbSize = ctypes.sizeof(did) - - if not SetupDiEnumDeviceInterfaces(g_hdi, None, ctypes.byref(GUID_CLASS_COMPORT), dwIndex, ctypes.byref(did)): - if ctypes.GetLastError() != ERROR_NO_MORE_ITEMS: - raise ctypes.WinError() - break - - dwNeeded = DWORD() - # get the size - if not SetupDiGetDeviceInterfaceDetail(g_hdi, ctypes.byref(did), None, 0, ctypes.byref(dwNeeded), None): - # Ignore ERROR_INSUFFICIENT_BUFFER - if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: - raise ctypes.WinError() - # allocate buffer - class SP_DEVICE_INTERFACE_DETAIL_DATA_A(ctypes.Structure): - _fields_ = [ - ('cbSize', DWORD), - ('DevicePath', CHAR*(dwNeeded.value - ctypes.sizeof(DWORD))), - ] - def __str__(self): - return "DevicePath:%s" % (self.DevicePath,) - idd = SP_DEVICE_INTERFACE_DETAIL_DATA_A() - if is_64bit(): - idd.cbSize = 8 - else: - idd.cbSize = 5 + GUIDs = (GUID*8)() + guids_size = DWORD() + if not SetupDiClassGuidsFromName(Ports, GUIDs, ctypes.sizeof(GUIDs), ctypes.byref(guids_size)): + raise ctypes.WinError() + + for index in range(guids_size.value): + #~ g_hdi = SetupDiGetClassDevs(ctypes.byref(guid), None, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE) + g_hdi = SetupDiGetClassDevs(ctypes.byref(GUIDs[index]), None, NULL, DIGCF_PRESENT) + devinfo = SP_DEVINFO_DATA() devinfo.cbSize = ctypes.sizeof(devinfo) - if not SetupDiGetDeviceInterfaceDetail(g_hdi, ctypes.byref(did), ctypes.byref(idd), dwNeeded, None, ctypes.byref(devinfo)): - raise ctypes.WinError() - - # the real com port name has to read differently... - hkey = SetupDiOpenDevRegKey(g_hdi, ctypes.byref(devinfo), DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) - port_name_buffer = byte_buffer(250) - port_name_length = ULONG(ctypes.sizeof(port_name_buffer)) - RegQueryValueEx(hkey, PortName, None, None, ctypes.byref(port_name_buffer), ctypes.byref(port_name_length)) - RegCloseKey(hkey) - - # hardware ID - szHardwareID = byte_buffer(250) - if not SetupDiGetDeviceRegistryProperty(g_hdi, ctypes.byref(devinfo), SPDRP_HARDWAREID, None, ctypes.byref(szHardwareID), ctypes.sizeof(szHardwareID) - 1, None): - # Ignore ERROR_INSUFFICIENT_BUFFER - if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: - raise ctypes.WinError() - - # friendly name - szFriendlyName = byte_buffer(250) - if not SetupDiGetDeviceRegistryProperty(g_hdi, ctypes.byref(devinfo), SPDRP_FRIENDLYNAME, None, ctypes.byref(szFriendlyName), ctypes.sizeof(szFriendlyName) - 1, None): - # Ignore ERROR_INSUFFICIENT_BUFFER - #~ if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: - #~ raise IOError("failed to get details for %s (%s)" % (devinfo, szHardwareID.value)) - # ignore errors and still include the port in the list, friendly name will be same as port name - yield string(port_name_buffer), NA, string(szHardwareID) - else: - yield string(port_name_buffer), string(szFriendlyName), string(szHardwareID) - - SetupDiDestroyDeviceInfoList(g_hdi) - + index = 0 + while SetupDiEnumDeviceInfo(g_hdi, index, ctypes.byref(devinfo)): + index += 1 + + # get the real com port name + hkey = SetupDiOpenDevRegKey(g_hdi, ctypes.byref(devinfo), DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) + #~ hkey = SetupDiOpenDevRegKey(g_hdi, ctypes.byref(devinfo), DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ) + port_name_buffer = byte_buffer(250) + port_name_length = ULONG(ctypes.sizeof(port_name_buffer)) + RegQueryValueEx(hkey, PortName, None, None, ctypes.byref(port_name_buffer), ctypes.byref(port_name_length)) + RegCloseKey(hkey) + + # unfortunately does this method also include parallel ports. + # we could check for names starting with COM or just exclude LPT + # and hope that other "unknown" names are serial ports... + if string(port_name_buffer).startswith('LPT'): + continue + + # hardware ID + szHardwareID = byte_buffer(250) + if not SetupDiGetDeviceRegistryProperty(g_hdi, ctypes.byref(devinfo), SPDRP_HARDWAREID, None, ctypes.byref(szHardwareID), ctypes.sizeof(szHardwareID) - 1, None): + # Ignore ERROR_INSUFFICIENT_BUFFER + if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: + raise ctypes.WinError() + + # friendly name + szFriendlyName = byte_buffer(250) + if not SetupDiGetDeviceRegistryProperty(g_hdi, ctypes.byref(devinfo), SPDRP_FRIENDLYNAME, None, ctypes.byref(szFriendlyName), ctypes.sizeof(szFriendlyName) - 1, None): + # Ignore ERROR_INSUFFICIENT_BUFFER + #~ if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: + #~ raise IOError("failed to get details for %s (%s)" % (devinfo, szHardwareID.value)) + # ignore errors and still include the port in the list, friendly name will be same as port name + yield string(port_name_buffer), NA, string(szHardwareID) + else: + yield string(port_name_buffer), string(szFriendlyName), string(szHardwareID) + + SetupDiDestroyDeviceInfoList(g_hdi) # test if __name__ == '__main__': -- cgit v1.2.1