Module hwPortUtils
[hide private]
[frames] | no frames]

Source Code for Module hwPortUtils

  1  #hwPortUtils.py 
  2  #A part of NonVisual Desktop Access (NVDA) 
  3  # Original serial scanner code from http://pyserial.svn.sourceforge.net/viewvc/*checkout*/pyserial/trunk/pyserial/examples/scanwin32.py 
  4  # Modifications and enhancements by James Teh 
  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   
13 -def ValidHandle(value):
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 )
33 - def __str__(self):
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
42 -class SP_DEVINFO_DATA(ctypes.Structure):
43 _fields_ = ( 44 ('cbSize', DWORD), 45 ('ClassGuid', GUID), 46 ('DevInst', DWORD), 47 ('Reserved', ULONG_PTR), 48 )
49 - def __str__(self):
50 return "ClassGuid:%s DevInst:%s" % (self.ClassGuid, self.DevInst)
51 PSP_DEVINFO_DATA = ctypes.POINTER(SP_DEVINFO_DATA) 52
53 -class SP_DEVICE_INTERFACE_DATA(ctypes.Structure):
54 _fields_ = ( 55 ('cbSize', DWORD), 56 ('InterfaceClassGuid', GUID), 57 ('Flags', DWORD), 58 ('Reserved', ULONG_PTR), 59 )
60 - def __str__(self):
61 return "InterfaceClassGuid:%s Flags:%s" % (self.InterfaceClassGuid, self.Flags)
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):
68 _fields_=(("d1", DWORD), ("d2", WCHAR)) 69 _pack_ = 1
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 # HDEVINFO 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
106 -def listComPorts(onlyAvailable=True):
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 # get the size 138 if not SetupDiGetDeviceInterfaceDetail( 139 g_hdi, 140 ctypes.byref(did), 141 None, 0, ctypes.byref(dwNeeded), 142 None 143 ): 144 # Ignore ERROR_INSUFFICIENT_BUFFER 145 if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER: 146 raise ctypes.WinError() 147 # allocate buffer 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 # hardware ID 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 # Ignore ERROR_INSUFFICIENT_BUFFER 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 # This is a bluetooth port. 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 # friendly name 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 # Ignore ERROR_INSUFFICIENT_BUFFER 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
219 -class SYSTEMTIME(ctypes.Structure):
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
231 -class BLUETOOTH_DEVICE_INFO(ctypes.Structure):
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 )
243 - def __init__(self, **kwargs):
244 super(BLUETOOTH_DEVICE_INFO, self).__init__(dwSize=ctypes.sizeof(self), **kwargs)
245
246 -def getBluetoothDeviceInfo(address):
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