4 def ValidHandle(value
):
6 raise ctypes
.WinError()
10 HDEVINFO
= ctypes
.c_int
13 PCTSTR
= ctypes
.c_char_p
15 DWORD
= ctypes
.c_ulong
16 PDWORD
= ctypes
.POINTER(DWORD
)
17 ULONG
= ctypes
.c_ulong
18 ULONG_PTR
= ctypes
.POINTER(ULONG
)
19 #~ PBYTE = ctypes.c_char_p
20 PBYTE
= ctypes
.c_void_p
22 class GUID(ctypes
.Structure
):
24 ('Data1', ctypes
.c_ulong
),
25 ('Data2', ctypes
.c_ushort
),
26 ('Data3', ctypes
.c_ushort
),
27 ('Data4', ctypes
.c_ubyte
*8),
30 return "{%08x-%04x-%04x-%s-%s}" % (
34 ''.join(["%02x" % d
for d
in self
.Data4
[:2]]),
35 ''.join(["%02x" % d
for d
in self
.Data4
[2:]]),
38 class SP_DEVINFO_DATA(ctypes
.Structure
):
43 ('Reserved', ULONG_PTR
),
46 return "ClassGuid:%s DevInst:%s" % (self
.ClassGuid
, self
.DevInst
)
47 PSP_DEVINFO_DATA
= ctypes
.POINTER(SP_DEVINFO_DATA
)
49 class SP_DEVICE_INTERFACE_DATA(ctypes
.Structure
):
52 ('InterfaceClassGuid', GUID
),
54 ('Reserved', ULONG_PTR
),
57 return "InterfaceClassGuid:%s Flags:%s" % (self
.InterfaceClassGuid
, self
.Flags
)
58 PSP_DEVICE_INTERFACE_DATA
= ctypes
.POINTER(SP_DEVICE_INTERFACE_DATA
)
60 PSP_DEVICE_INTERFACE_DETAIL_DATA
= ctypes
.c_void_p
62 SetupDiDestroyDeviceInfoList
= ctypes
.windll
.setupapi
.SetupDiDestroyDeviceInfoList
63 SetupDiDestroyDeviceInfoList
.argtypes
= [HDEVINFO
]
64 SetupDiDestroyDeviceInfoList
.restype
= BOOL
66 SetupDiGetClassDevs
= ctypes
.windll
.setupapi
.SetupDiGetClassDevsA
67 SetupDiGetClassDevs
.argtypes
= [ctypes
.POINTER(GUID
), PCTSTR
, HWND
, DWORD
]
68 SetupDiGetClassDevs
.restype
= ValidHandle
#HDEVINFO
70 SetupDiEnumDeviceInterfaces
= ctypes
.windll
.setupapi
.SetupDiEnumDeviceInterfaces
71 SetupDiEnumDeviceInterfaces
.argtypes
= [HDEVINFO
, PSP_DEVINFO_DATA
, ctypes
.POINTER(GUID
), DWORD
, PSP_DEVICE_INTERFACE_DATA
]
72 SetupDiEnumDeviceInterfaces
.restype
= BOOL
74 SetupDiGetDeviceInterfaceDetail
= ctypes
.windll
.setupapi
.SetupDiGetDeviceInterfaceDetailA
75 SetupDiGetDeviceInterfaceDetail
.argtypes
= [HDEVINFO
, PSP_DEVICE_INTERFACE_DATA
, PSP_DEVICE_INTERFACE_DETAIL_DATA
, DWORD
, PDWORD
, PSP_DEVINFO_DATA
]
76 SetupDiGetDeviceInterfaceDetail
.restype
= BOOL
78 SetupDiGetDeviceRegistryProperty
= ctypes
.windll
.setupapi
.SetupDiGetDeviceRegistryPropertyA
79 SetupDiGetDeviceRegistryProperty
.argtypes
= [HDEVINFO
, PSP_DEVINFO_DATA
, DWORD
, PDWORD
, PBYTE
, DWORD
, PDWORD
]
80 SetupDiGetDeviceRegistryProperty
.restype
= BOOL
83 GUID_CLASS_COMPORT
= GUID(0x86e0d1e0L
, 0x8089, 0x11d0,
84 (ctypes
.c_ubyte
*8)(0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73))
87 DIGCF_DEVICEINTERFACE
= 16
88 INVALID_HANDLE_VALUE
= 0
89 ERROR_INSUFFICIENT_BUFFER
= 122
91 SPDRP_FRIENDLYNAME
= 12
92 ERROR_NO_MORE_ITEMS
= 259
94 def comports(available_only
=True):
95 """This generator scans the device registry for com ports and yields port, desc, hwid.
96 If available_only is true only return currently existing ports."""
97 flags
= DIGCF_DEVICEINTERFACE
99 flags |
= DIGCF_PRESENT
100 g_hdi
= SetupDiGetClassDevs(ctypes
.byref(GUID_CLASS_COMPORT
), None, NULL
, flags
);
101 #~ for i in range(256):
102 for dwIndex
in range(256):
103 did
= SP_DEVICE_INTERFACE_DATA()
104 did
.cbSize
= ctypes
.sizeof(did
)
106 if not SetupDiEnumDeviceInterfaces(
109 ctypes
.byref(GUID_CLASS_COMPORT
),
113 if ctypes
.GetLastError() != ERROR_NO_MORE_ITEMS
:
114 raise ctypes
.WinError()
119 if not SetupDiGetDeviceInterfaceDetail(
122 None, 0, ctypes
.byref(dwNeeded
),
125 # Ignore ERROR_INSUFFICIENT_BUFFER
126 if ctypes
.GetLastError() != ERROR_INSUFFICIENT_BUFFER
:
127 raise ctypes
.WinError()
129 class SP_DEVICE_INTERFACE_DETAIL_DATA_A(ctypes
.Structure
):
132 ('DevicePath', CHAR
*(dwNeeded
.value
- ctypes
.sizeof(DWORD
))),
135 return "DevicePath:%s" % (self
.DevicePath
,)
136 idd
= SP_DEVICE_INTERFACE_DETAIL_DATA_A()
138 devinfo
= SP_DEVINFO_DATA()
139 devinfo
.cbSize
= ctypes
.sizeof(devinfo
)
140 if not SetupDiGetDeviceInterfaceDetail(
143 ctypes
.byref(idd
), dwNeeded
, None,
144 ctypes
.byref(devinfo
)
146 raise ctypes
.WinError()
149 szHardwareID
= ctypes
.create_string_buffer('\0' * 250)
150 if not SetupDiGetDeviceRegistryProperty(
152 ctypes
.byref(devinfo
),
155 ctypes
.byref(szHardwareID
), ctypes
.sizeof(szHardwareID
) - 1,
158 # Ignore ERROR_INSUFFICIENT_BUFFER
159 if ctypes
.GetLastError() != ERROR_INSUFFICIENT_BUFFER
:
160 raise ctypes
.WinError()
163 szFriendlyName
= ctypes
.create_string_buffer('\0' * 250)
164 if not SetupDiGetDeviceRegistryProperty(
166 ctypes
.byref(devinfo
),
169 ctypes
.byref(szFriendlyName
), ctypes
.sizeof(szFriendlyName
) - 1,
172 # Ignore ERROR_INSUFFICIENT_BUFFER
173 if ctypes
.GetLastError() != ERROR_INSUFFICIENT_BUFFER
:
174 raise ctypes
.WinError()
175 port_name
= re
.search(r
"\((.*)\)", szFriendlyName
.value
).group(1)
176 if len(port_name
) > 4:
177 port_name
= '\\\\.\\'+port_name
178 yield port_name
, szFriendlyName
.value
, szHardwareID
.value
180 SetupDiDestroyDeviceInfoList(g_hdi
)
183 if __name__
== '__main__':
185 for port
, desc
, hwid
in comports():
186 print "%s: %s (%s)" % (port
, desc
, hwid
)
187 print " "*10, serial
.Serial(port
) #test open
189 # list of all ports the system knows
191 for port
, desc
, hwid
in comports(False):
192 print "%-10s: %s (%s)" % (port
, desc
, hwid
)