mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
[Device] Implement apis to retrieve the list of devices under each class
This commit is contained in:
@@ -4,10 +4,11 @@ from windows.winobject.device import DeviceManager
|
||||
def main():
|
||||
|
||||
for device_class in DeviceManager.enumerate_active_class():
|
||||
print("-[%s] Class %s" % (device_class.guid, device_class.name))
|
||||
print("-Class %s %s [%s]" % (device_class.name, " "*(60 - min(60,len(device_class.name))), device_class.guid))
|
||||
|
||||
# for device in device_class.devices:
|
||||
# print(" -Device : %s" % (device.name))
|
||||
for device in device_class.devices:
|
||||
if device.name != "N/A":
|
||||
print(" -Device : %s" % (device.name))
|
||||
|
||||
# for resource in device.resources:
|
||||
# print(' -%s : [0x%08x - 0x%08x] (0x%04x)' % (resource.type, resource.start, resource.end, resource.flags))
|
||||
|
||||
@@ -3166,3 +3166,21 @@ SetupDiClassNameFromGuidAParams = ((1, 'ClassGuid'),(1, 'ClassName'),(1, 'ClassN
|
||||
|
||||
SetupDiClassNameFromGuidWPrototype = WINFUNCTYPE(BOOL, POINTER(GUID), LPCWSTR, DWORD , POINTER(DWORD))
|
||||
SetupDiClassNameFromGuidWParams = ((1, 'ClassGuid'),(1, 'ClassName'),(1, 'ClassNameSize'),(1, 'RequiredSize'))
|
||||
|
||||
SetupDiGetClassDevsAPrototype = WINFUNCTYPE(HANDLE, POINTER(GUID), LPCSTR, HANDLE , DWORD)
|
||||
SetupDiGetClassDevsAParams = ((1, 'ClassGuid'), (1, 'Enumerator'), (1, 'hwndParent'), (1, 'Flags'),)
|
||||
|
||||
SetupDiGetClassDevsWPrototype = WINFUNCTYPE(HANDLE, POINTER(GUID), LPCWSTR, HANDLE , DWORD)
|
||||
SetupDiGetClassDevsWParams = ((1, 'ClassGuid'), (1, 'Enumerator'), (1, 'hwndParent'), (1, 'Flags'),)
|
||||
|
||||
SetupDiDestroyDeviceInfoListPrototype = WINFUNCTYPE(BOOL, HANDLE)
|
||||
SetupDiDestroyDeviceInfoListParams = ((1, 'DeviceInfoSet'),)
|
||||
|
||||
SetupDiEnumDeviceInfoPrototype = WINFUNCTYPE(BOOL, HANDLE, DWORD, PSP_DEVINFO_DATA)
|
||||
SetupDiEnumDeviceInfoParams = ((1, 'DeviceInfoSet'),(1, 'MemberIndex'),(1, 'DeviceInfoData'),)
|
||||
|
||||
SetupDiGetDeviceRegistryPropertyAPrototype = WINFUNCTYPE(BOOL, HANDLE, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD)
|
||||
SetupDiGetDeviceRegistryPropertyAParams = ((1, 'DeviceInfoSet'),(1, 'DeviceInfoData'),(1, 'Property'),(1, 'PropertyRegDataType'),(1, 'PropertyBuffer'),(1, 'PropertyBufferSize'),(1, 'RequiredSize'),)
|
||||
|
||||
SetupDiGetDeviceRegistryPropertyWPrototype = WINFUNCTYPE(BOOL, HANDLE, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD)
|
||||
SetupDiGetDeviceRegistryPropertyWParams = ((1, 'DeviceInfoSet'),(1, 'DeviceInfoData'),(1, 'Property'),(1, 'PropertyRegDataType'),(1, 'PropertyBuffer'),(1, 'PropertyBufferSize'),(1, 'RequiredSize'),)
|
||||
@@ -9828,3 +9828,12 @@ PWIN32_FIND_DATAW = POINTER(_WIN32_FIND_DATAW)
|
||||
WIN32_FIND_DATAW = _WIN32_FIND_DATAW
|
||||
LPWIN32_FIND_DATAW = POINTER(_WIN32_FIND_DATAW)
|
||||
|
||||
class _SP_DEVINFO_DATA(Structure):
|
||||
_fields_ = [
|
||||
("cbSize", DWORD),
|
||||
("ClassGuid", GUID),
|
||||
("DevInst", DWORD),
|
||||
("Reserved1", ULONG_PTR),
|
||||
]
|
||||
PSP_DEVINFO_DATA = POINTER(_SP_DEVINFO_DATA)
|
||||
SP_DEVINFO_DATA = _SP_DEVINFO_DATA
|
||||
+69
-22
@@ -1,19 +1,61 @@
|
||||
|
||||
import windows
|
||||
from windows import winproxy
|
||||
from windows.generated_def import windef
|
||||
import windows.generated_def as gdef
|
||||
|
||||
SPDRP_DEVICEDESC = 0x0000000
|
||||
SPDRP_FRIENDLYNAME = 0x000000C
|
||||
|
||||
|
||||
class DeviceObject(object):
|
||||
|
||||
|
||||
def __init__(self, dev_data, device_name):
|
||||
|
||||
self.dev_data = dev_data
|
||||
self._name = device_name
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@classmethod
|
||||
def from_device_info(cls, h_devs, device_data):
|
||||
|
||||
|
||||
# DO NOT STORE h_devs since it may be invalidated in the future
|
||||
try:
|
||||
device_name = winproxy.SetupDiGetDeviceRegistryPropertyW(h_devs, device_data, SPDRP_FRIENDLYNAME, None)
|
||||
if device_name:
|
||||
device_name = device_name.decode('utf-16-le').rstrip('\x00')
|
||||
else:
|
||||
device_name = winproxy.SetupDiGetDeviceRegistryPropertyW(h_devs, device_data, SPDRP_DEVICEDESC, None)
|
||||
if device_name:
|
||||
device_name = device_name.decode('utf-16-le').rstrip('\x00')
|
||||
else:
|
||||
device_name = "N/A"
|
||||
|
||||
except WindowsError as e:
|
||||
if e.winerror == gdef.ERROR_INVALID_DATA:
|
||||
return cls(device_data, "N/A")
|
||||
raise
|
||||
|
||||
|
||||
return cls(device_data, device_name)
|
||||
|
||||
class DeviceClass(object):
|
||||
|
||||
def __init__(self, guid):
|
||||
|
||||
# class GUID
|
||||
self._guid = guid
|
||||
|
||||
# associated class name
|
||||
self._name = None
|
||||
|
||||
# self._devices = None
|
||||
# self._h_devs = None
|
||||
|
||||
# List of devices registered under the class
|
||||
self._devices = None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
@@ -24,33 +66,38 @@ class DeviceClass(object):
|
||||
|
||||
@property
|
||||
def guid(self):
|
||||
return self._guid
|
||||
return self._guid
|
||||
|
||||
# @property
|
||||
# def devices(self):
|
||||
# if not self._devices:
|
||||
@property
|
||||
def devices(self):
|
||||
if not self._devices:
|
||||
|
||||
# with OpenDeviceClass(self):
|
||||
# self._devices = list(do for do in self._get_devices())
|
||||
try:
|
||||
h_devs = winproxy.SetupDiGetClassDevsA(self.guid)
|
||||
self._devices = list(do for do in self._get_devices(h_devs))
|
||||
finally:
|
||||
winproxy.SetupDiDestroyDeviceInfoList(h_devs)
|
||||
|
||||
# return self._devices
|
||||
return self._devices
|
||||
|
||||
# def _get_devices(self):
|
||||
def _get_devices(self, h_devs):
|
||||
|
||||
# if not self._h_devs:
|
||||
# return
|
||||
if not h_devs:
|
||||
return
|
||||
|
||||
# device_index = 0
|
||||
device_index = 0
|
||||
|
||||
# while True:
|
||||
while True:
|
||||
|
||||
# device_data = winproxy.SetupDiEnumDeviceInfo(self._h_devs, device_index)
|
||||
# if not device_data:
|
||||
# return # stop iterating
|
||||
try:
|
||||
device_data = winproxy.SetupDiEnumDeviceInfo(h_devs, device_index)
|
||||
except WindowsError as e:
|
||||
if e.winerror == gdef.ERROR_NO_MORE_ITEMS:
|
||||
return # stop iterating
|
||||
raise
|
||||
|
||||
|
||||
# device_index+=1
|
||||
# yield DeviceObject.from_device_info(self._h_devs, device_data)
|
||||
device_index+=1
|
||||
yield DeviceObject.from_device_info(h_devs, device_data)
|
||||
|
||||
|
||||
def _get_class_name(self):
|
||||
@@ -61,7 +108,7 @@ class DeviceManager(object):
|
||||
|
||||
@staticmethod
|
||||
def enumerate_active_class():
|
||||
return list(DeviceManager.enumerate_class())
|
||||
return list(DeviceManager.enumerate_class())
|
||||
# return list(filter(lambda dc: len(dc.devices) > 0, DeviceManager.enumerate_class()))
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -3,14 +3,16 @@ from ctypes import wintypes
|
||||
import windows.generated_def as gdef
|
||||
|
||||
from ..apiproxy import ApiProxy, NeededParameter, is_implemented
|
||||
from ..error import succeed_on_zero, fail_on_zero
|
||||
from ..error import succeed_on_zero, fail_on_zero, result_is_handle, no_error_check
|
||||
|
||||
|
||||
MAX_CLASS_NAME_LEN = 32
|
||||
MAX_DEV_LEN = 1000
|
||||
|
||||
|
||||
class SetupApiProxy(ApiProxy):
|
||||
APIDLL = "SetupApi"
|
||||
default_error_check = staticmethod(succeed_on_zero)
|
||||
default_error_check = staticmethod(fail_on_zero)
|
||||
|
||||
|
||||
@SetupApiProxy()
|
||||
@@ -31,7 +33,7 @@ def SetupDiClassNameFromGuidA(Guid):
|
||||
raw_class_name = bytes(class_name)
|
||||
return raw_class_name.decode("utf-8").rstrip("\x00")
|
||||
|
||||
@SetupApiProxy(error_check=fail_on_zero)
|
||||
@SetupApiProxy()
|
||||
def SetupDiClassNameFromGuidW(Guid):
|
||||
|
||||
"""
|
||||
@@ -50,24 +52,103 @@ def SetupDiClassNameFromGuidW(Guid):
|
||||
raw_class_name = bytes(class_name)
|
||||
return raw_class_name.decode("utf-16-le").rstrip("\x00")
|
||||
|
||||
# @SetupApiProxy()
|
||||
# def SetupDiGetClassDevsA(Guid):
|
||||
# return SetupDiGetClassDevsA.ctypes_function()
|
||||
@SetupApiProxy(error_check=result_is_handle)
|
||||
def SetupDiGetClassDevsA(Guid, Enumerator = None, hwndParent = None, Flags=0):
|
||||
"""
|
||||
Given a class GUID, return a HANDLE to the device's information set or raise an Exception
|
||||
"""
|
||||
|
||||
# @SetupApiProxy()
|
||||
# def SetupDiEnumDeviceInfo(hDevInfo, NumDevice):
|
||||
# return SetupDiEnumDeviceInfo.ctypes_function()
|
||||
return SetupDiGetClassDevsA.ctypes_function(
|
||||
ctypes.byref(Guid),
|
||||
Enumerator,
|
||||
hwndParent,
|
||||
Flags
|
||||
)
|
||||
|
||||
# @SetupApiProxy()
|
||||
# def SetupDiGetDeviceRegistryPropertyA(hDevInfo, DevData, Property, PropertyType):
|
||||
# return SetupDiGetDeviceRegistryPropertyA.ctypes_function()
|
||||
@SetupApiProxy(error_check=result_is_handle)
|
||||
def SetupDiGetClassDevsW(Guid, Enumerator = None, hwndParent = None, Flags=0):
|
||||
"""
|
||||
Given a class GUID, return a HANDLE to the device's information set or raise an Exception
|
||||
"""
|
||||
|
||||
return SetupDiGetClassDevsW.ctypes_function(
|
||||
ctypes.byref(Guid),
|
||||
Enumerator,
|
||||
hwndParent,
|
||||
Flags
|
||||
)
|
||||
|
||||
@SetupApiProxy()
|
||||
def SetupDiEnumDeviceInfo(hDevInfo, MemberIndex):
|
||||
"""
|
||||
Given a device information set, return the info associated with the index
|
||||
or raise ERROR_NO_MORE_ITEMS if there is none anymore.
|
||||
"""
|
||||
|
||||
data = gdef.winstructs.SP_DEVINFO_DATA()
|
||||
data.cbSize = ctypes.sizeof(gdef.winstructs.SP_DEVINFO_DATA)
|
||||
|
||||
success = SetupDiEnumDeviceInfo.ctypes_function(
|
||||
hDevInfo,
|
||||
MemberIndex,
|
||||
ctypes.byref(data)
|
||||
)
|
||||
|
||||
return data
|
||||
|
||||
@SetupApiProxy()
|
||||
def SetupDiGetDeviceRegistryPropertyA(hDevInfo, DevData, Property, PropertyType, PropertySize = MAX_DEV_LEN*ctypes.sizeof(wintypes.CHAR)):
|
||||
|
||||
property_buffer = ctypes.create_string_buffer(PropertySize)
|
||||
bytes_written = wintypes.DWORD(0)
|
||||
|
||||
success = SetupDiGetDeviceRegistryPropertyA.ctypes_function(
|
||||
hDevInfo,
|
||||
ctypes.byref(DevData),
|
||||
Property,
|
||||
PropertyType,
|
||||
ctypes.cast(ctypes.byref(property_buffer), gdef.winstructs.PBYTE),
|
||||
wintypes.DWORD(PropertySize),
|
||||
ctypes.byref(bytes_written),
|
||||
)
|
||||
|
||||
if not success:
|
||||
return None
|
||||
|
||||
# Truncate read data
|
||||
registry_data = bytes(property_buffer)
|
||||
registry_data = registry_data[0:bytes_written.value]
|
||||
|
||||
return registry_data
|
||||
|
||||
|
||||
# @SetupApiProxy()
|
||||
# def SetupDiGetDeviceRegistryPropertyW(hDevInfo, DevData, Property, PropertyType):
|
||||
# return SetupDiGetDeviceRegistryPropertyW.ctypes_function()
|
||||
@SetupApiProxy()
|
||||
def SetupDiGetDeviceRegistryPropertyW(hDevInfo, DevData, Property, PropertyType, PropertySize = MAX_DEV_LEN*ctypes.sizeof(wintypes.WCHAR)):
|
||||
|
||||
property_buffer = ctypes.create_unicode_buffer(PropertySize)
|
||||
bytes_written = wintypes.DWORD(0)
|
||||
|
||||
success = SetupDiGetDeviceRegistryPropertyW.ctypes_function(
|
||||
hDevInfo,
|
||||
ctypes.byref(DevData),
|
||||
Property,
|
||||
PropertyType,
|
||||
ctypes.cast(ctypes.byref(property_buffer), gdef.winstructs.PBYTE),
|
||||
wintypes.DWORD(PropertySize),
|
||||
ctypes.byref(bytes_written),
|
||||
)
|
||||
|
||||
if not success:
|
||||
return None
|
||||
|
||||
# Truncate read data
|
||||
registry_data = bytes(property_buffer)
|
||||
registry_data = registry_data[0:bytes_written.value]
|
||||
|
||||
return registry_data
|
||||
|
||||
|
||||
# @SetupApiProxy()
|
||||
# def SetupDiDestroyDeviceInfoList(hDevInfo):
|
||||
# return SetupDiDestroyDeviceInfoList.ctypes_function(hDevInfo)
|
||||
|
||||
@SetupApiProxy()
|
||||
def SetupDiDestroyDeviceInfoList(hDevInfo):
|
||||
return SetupDiDestroyDeviceInfoList.ctypes_function(hDevInfo)
|
||||
Reference in New Issue
Block a user