summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcliechti <cliechti@f19166aa-fa4f-0410-85c2-fa1106f25c8a>2013-10-14 03:35:33 +0000
committercliechti <cliechti@f19166aa-fa4f-0410-85c2-fa1106f25c8a>2013-10-14 03:35:33 +0000
commit6a5185b55c57f56abe67cead08925ac78fb1830b (patch)
treeb3aa1ff84116df5c99da5bce1b6ef86d79e699a4
parent53d38fcbc0980d597f5aaeff7020ec068f034c29 (diff)
downloadpyserial-6a5185b55c57f56abe67cead08925ac78fb1830b.tar.gz
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
-rw-r--r--serial/tools/list_ports_windows.py119
1 files 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__':