1
2
3
4
5
6 import ctypes
7 from ctypes.wintypes import BOOL, WCHAR, HWND, DWORD, ULONG, WORD
8 import _winreg as winreg
9
10 """Utilities for working with hardware connection ports.
11 """
12
14 if value == 0:
15 raise ctypes.WinError()
16 return value
17
18 HDEVINFO = ctypes.c_void_p
19 PCWSTR = ctypes.c_wchar_p
20 HWND = ctypes.c_uint
21 PDWORD = ctypes.POINTER(DWORD)
22 ULONG_PTR = ctypes.POINTER(ULONG)
23 ULONGLONG = ctypes.c_ulonglong
24 NULL = 0
25
26 -class GUID(ctypes.Structure):
27 _fields_ = (
28 ('Data1', ctypes.c_ulong),
29 ('Data2', ctypes.c_ushort),
30 ('Data3', ctypes.c_ushort),
31 ('Data4', ctypes.c_ubyte*8),
32 )
34 return "{%08x-%04x-%04x-%s-%s}" % (
35 self.Data1,
36 self.Data2,
37 self.Data3,
38 ''.join(["%02x" % d for d in self.Data4[:2]]),
39 ''.join(["%02x" % d for d in self.Data4[2:]]),
40 )
41
43 _fields_ = (
44 ('cbSize', DWORD),
45 ('ClassGuid', GUID),
46 ('DevInst', DWORD),
47 ('Reserved', ULONG_PTR),
48 )
51 PSP_DEVINFO_DATA = ctypes.POINTER(SP_DEVINFO_DATA)
52
54 _fields_ = (
55 ('cbSize', DWORD),
56 ('InterfaceClassGuid', GUID),
57 ('Flags', DWORD),
58 ('Reserved', ULONG_PTR),
59 )
62
63 PSP_DEVICE_INTERFACE_DATA = ctypes.POINTER(SP_DEVICE_INTERFACE_DATA)
64
65 PSP_DEVICE_INTERFACE_DETAIL_DATA = ctypes.c_void_p
66
67 -class dummy(ctypes.Structure):
70 SIZEOF_SP_DEVICE_INTERFACE_DETAIL_DATA_W = ctypes.sizeof(dummy)
71
72 SetupDiDestroyDeviceInfoList = ctypes.windll.setupapi.SetupDiDestroyDeviceInfoList
73 SetupDiDestroyDeviceInfoList.argtypes = (HDEVINFO,)
74 SetupDiDestroyDeviceInfoList.restype = BOOL
75
76 SetupDiGetClassDevs = ctypes.windll.setupapi.SetupDiGetClassDevsW
77 SetupDiGetClassDevs.argtypes = (ctypes.POINTER(GUID), PCWSTR, HWND, DWORD)
78 SetupDiGetClassDevs.restype = ValidHandle
79
80 SetupDiEnumDeviceInterfaces = ctypes.windll.setupapi.SetupDiEnumDeviceInterfaces
81 SetupDiEnumDeviceInterfaces.argtypes = (HDEVINFO, PSP_DEVINFO_DATA, ctypes.POINTER(GUID), DWORD, PSP_DEVICE_INTERFACE_DATA)
82 SetupDiEnumDeviceInterfaces.restype = BOOL
83
84 SetupDiGetDeviceInterfaceDetail = ctypes.windll.setupapi.SetupDiGetDeviceInterfaceDetailW
85 SetupDiGetDeviceInterfaceDetail.argtypes = (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, PSP_DEVICE_INTERFACE_DETAIL_DATA, DWORD, PDWORD, PSP_DEVINFO_DATA)
86 SetupDiGetDeviceInterfaceDetail.restype = BOOL
87
88 SetupDiGetDeviceRegistryProperty = ctypes.windll.setupapi.SetupDiGetDeviceRegistryPropertyW
89 SetupDiGetDeviceRegistryProperty.argtypes = (HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, ctypes.c_void_p, DWORD, PDWORD)
90 SetupDiGetDeviceRegistryProperty.restype = BOOL
91
92 GUID_CLASS_COMPORT = GUID(0x86e0d1e0L, 0x8089, 0x11d0,
93 (ctypes.c_ubyte*8)(0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73))
94
95 DIGCF_PRESENT = 2
96 DIGCF_DEVICEINTERFACE = 16
97 INVALID_HANDLE_VALUE = 0
98 ERROR_INSUFFICIENT_BUFFER = 122
99 SPDRP_HARDWAREID = 1
100 SPDRP_FRIENDLYNAME = 12
101 SPDRP_LOCATION_INFORMATION = 13
102 ERROR_NO_MORE_ITEMS = 259
103 DICS_FLAG_GLOBAL = 0x00000001
104 DIREG_DEV = 0x00000001
105
107 """List com ports on the system.
108 @param onlyAvailable: Only return ports that are currently available.
109 @type onlyAvailable: bool
110 @return: Generates dicts including keys of port, friendlyName and hardwareID.
111 @rtype: generator of (str, str, str)
112 """
113 flags = DIGCF_DEVICEINTERFACE
114 if onlyAvailable:
115 flags |= DIGCF_PRESENT
116
117 buf = ctypes.create_unicode_buffer(1024)
118 g_hdi = SetupDiGetClassDevs(ctypes.byref(GUID_CLASS_COMPORT), None, NULL, flags)
119 try:
120 for dwIndex in xrange(256):
121 entry = {}
122 did = SP_DEVICE_INTERFACE_DATA()
123 did.cbSize = ctypes.sizeof(did)
124
125 if not SetupDiEnumDeviceInterfaces(
126 g_hdi,
127 None,
128 ctypes.byref(GUID_CLASS_COMPORT),
129 dwIndex,
130 ctypes.byref(did)
131 ):
132 if ctypes.GetLastError() != ERROR_NO_MORE_ITEMS:
133 raise ctypes.WinError()
134 break
135
136 dwNeeded = DWORD()
137
138 if not SetupDiGetDeviceInterfaceDetail(
139 g_hdi,
140 ctypes.byref(did),
141 None, 0, ctypes.byref(dwNeeded),
142 None
143 ):
144
145 if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
146 raise ctypes.WinError()
147
148 class SP_DEVICE_INTERFACE_DETAIL_DATA_W(ctypes.Structure):
149 _fields_ = (
150 ('cbSize', DWORD),
151 ('DevicePath', WCHAR*(dwNeeded.value - ctypes.sizeof(DWORD))),
152 )
153 def __str__(self):
154 return "DevicePath:%s" % (self.DevicePath,)
155 idd = SP_DEVICE_INTERFACE_DETAIL_DATA_W()
156 idd.cbSize = SIZEOF_SP_DEVICE_INTERFACE_DETAIL_DATA_W
157 devinfo = SP_DEVINFO_DATA()
158 devinfo.cbSize = ctypes.sizeof(devinfo)
159 if not SetupDiGetDeviceInterfaceDetail(
160 g_hdi,
161 ctypes.byref(did),
162 ctypes.byref(idd), dwNeeded, None,
163 ctypes.byref(devinfo)
164 ):
165 raise ctypes.WinError()
166
167
168 if not SetupDiGetDeviceRegistryProperty(
169 g_hdi,
170 ctypes.byref(devinfo),
171 SPDRP_HARDWAREID,
172 None,
173 ctypes.byref(buf), ctypes.sizeof(buf) - 1,
174 None
175 ):
176
177 if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
178 raise ctypes.WinError()
179 else:
180 entry["hardwareID"] = buf.value
181
182 regKey = ctypes.windll.setupapi.SetupDiOpenDevRegKey(g_hdi, ctypes.byref(devinfo), DICS_FLAG_GLOBAL, 0, DIREG_DEV, winreg.KEY_READ)
183 entry["port"] = winreg.QueryValueEx(regKey, "PortName")[0]
184 if entry["hardwareID"].startswith("BTHENUM\\"):
185
186 try:
187 addr = winreg.QueryValueEx(regKey, "Bluetooth_UniqueID")[0].split("#", 1)[1].split("_", 1)[0]
188 addr = int(addr, 16)
189 entry["bluetoothAddress"] = addr
190 if addr:
191 entry["bluetoothName"] = getBluetoothDeviceInfo(addr).szName
192 except:
193 pass
194 ctypes.windll.advapi32.RegCloseKey(regKey)
195
196
197 if not SetupDiGetDeviceRegistryProperty(
198 g_hdi,
199 ctypes.byref(devinfo),
200 SPDRP_FRIENDLYNAME,
201 None,
202 ctypes.byref(buf), ctypes.sizeof(buf) - 1,
203 None
204 ):
205
206 if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
207 raise ctypes.WinError()
208 else:
209 entry["friendlyName"] = buf.value
210
211 yield entry
212
213 finally:
214 SetupDiDestroyDeviceInfoList(g_hdi)
215
216 BLUETOOTH_MAX_NAME_SIZE = 248
217 BTH_ADDR = BLUETOOTH_ADDRESS = ULONGLONG
218
220 _fields_ = (
221 ("wYear", WORD),
222 ("wMonth", WORD),
223 ("wDayOfWeek", WORD),
224 ("wDay", WORD),
225 ("wHour", WORD),
226 ("wMinute", WORD),
227 ("wSecond", WORD),
228 ("wMilliseconds", WORD)
229 )
230
232 _fields_ = (
233 ("dwSize", DWORD),
234 ("address", BLUETOOTH_ADDRESS),
235 ("ulClassofDevice", ULONG),
236 ("fConnected", BOOL),
237 ("fRemembered", BOOL),
238 ("fAuthenticated", BOOL),
239 ("stLastSeen", SYSTEMTIME),
240 ("stLastUsed", SYSTEMTIME),
241 ("szName", WCHAR * BLUETOOTH_MAX_NAME_SIZE)
242 )
245
247 devInfo = BLUETOOTH_DEVICE_INFO(address=address)
248 res = ctypes.windll["bthprops.cpl"].BluetoothGetDeviceInfo(None, ctypes.byref(devInfo))
249 if res != 0:
250 raise ctypes.WinError(res)
251 return devInfo
252