如何通过Python的WMI模块获取显卡SubVendor信息?
解决Python获取显卡SubVendor(厂商如MSI/EVGA/XFX)的问题
WMI的Win32_VideoController确实不提供SubVendor信息,要获取这个数据,得直接读取PCI设备的底层信息或者访问Windows注册表,以下是两种可行方案:
方案1:通过Windows SetupAPI(ctypes实现)
Windows的SetupDi系列函数可以枚举所有PCI设备,读取显卡的SubVendor ID,再映射为厂商名称。
代码示例
import ctypes from ctypes import wintypes # 定义SetupAPI所需的结构体和函数 SetupDiGetClassDevs = ctypes.WINFUNCTYPE( wintypes.HANDLE, wintypes.LPCGUID, wintypes.LPCWSTR, wintypes.HWND, wintypes.DWORD )(("SetupDiGetClassDevW", ctypes.WinDLL("setupapi.dll"))) SetupDiEnumDeviceInfo = ctypes.WINFUNCTYPE( wintypes.BOOL, wintypes.HANDLE, wintypes.DWORD, ctypes.POINTER(wintypes.SP_DEVINFO_DATA) )(("SetupDiEnumDeviceInfo", ctypes.WinDLL("setupapi.dll"))) SetupDiGetDeviceRegistryProperty = ctypes.WINFUNCTYPE( wintypes.BOOL, wintypes.HANDLE, ctypes.POINTER(wintypes.SP_DEVINFO_DATA), wintypes.DWORD, ctypes.POINTER(wintypes.DWORD), wintypes.PBYTE, wintypes.DWORD, ctypes.POINTER(wintypes.DWORD) )(("SetupDiGetDeviceRegistryPropertyW", ctypes.WinDLL("setupapi.dll"))) SetupDiDestroyDeviceInfoList = ctypes.WINFUNCTYPE( wintypes.BOOL, wintypes.HANDLE )(("SetupDiDestroyDeviceInfoList", ctypes.WinDLL("setupapi.dll"))) # PCI显卡类GUID GUID_DEVCLASS_DISPLAY = wintypes.GUID("{4d36e968-e325-11ce-bfc1-08002be10318}") SPDRP_HARDWAREID = 0x00000001 DIGCF_PRESENT = 0x00000002 # SubVendor ID到厂商名称的映射表(可根据需求补充) subvendor_map = { "1462": "MSI", "3842": "EVGA", "1682": "XFX", "1043": "ASUS", "10DE": "NVIDIA", "1028": "Dell", "103C": "HP" } def get_gpu_subvendors(): subvendors = [] # 获取所有当前存在的显示设备 hdevinfo = SetupDiGetClassDevs(ctypes.byref(GUID_DEVCLASS_DISPLAY), None, None, DIGCF_PRESENT) if hdevinfo == wintypes.HANDLE(-1).value: return subvendors devinfo_data = wintypes.SP_DEVINFO_DATA() devinfo_data.cbSize = ctypes.sizeof(devinfo_data) index = 0 while SetupDiEnumDeviceInfo(hdevinfo, index, ctypes.byref(devinfo_data)): # 获取HardwareID长度 buf_size = wintypes.DWORD(0) SetupDiGetDeviceRegistryProperty(hdevinfo, ctypes.byref(devinfo_data), SPDRP_HARDWAREID, None, None, 0, ctypes.byref(buf_size)) # 分配缓冲区并读取HardwareID buf = ctypes.create_unicode_buffer(buf_size.value) if SetupDiGetDeviceRegistryProperty(hdevinfo, ctypes.byref(devinfo_data), SPDRP_HARDWAREID, None, ctypes.cast(buf, wintypes.PBYTE), buf_size.value, None): hardware_ids = buf.value.split('\0') for hw_id in hardware_ids: if hw_id.startswith("PCI\\VEN_"): parts = hw_id.split('&') subsys_part = next((p for p in parts if p.startswith("SUBSYS_")), None) if subsys_part: # SUBSYS_YYYYXXXX,前四位是SubVendor ID subvendor_id = subsys_part[6:10] vendor_name = subvendor_map.get(subvendor_id, f"Unknown (ID: {subvendor_id})") subvendors.append(vendor_name) break index += 1 SetupDiDestroyDeviceInfoList(hdevinfo) return list(set(subvendors)) # 去重 if __name__ == "__main__": gpu_vendors = get_gpu_subvendors() for vendor in gpu_vendors: print(f"显卡SubVendor: {vendor}")
方案2:读取Windows注册表
显卡的硬件信息会存在注册表的HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\PCI路径下,我们可以遍历该路径下的显示设备项,提取SubVendor ID并映射名称。
代码示例
import winreg # SubVendor ID到厂商名称的映射表(同方案1) subvendor_map = { "1462": "MSI", "3842": "EVGA", "1682": "XFX", "1043": "ASUS", "10DE": "NVIDIA", "1028": "Dell", "103C": "HP" } def get_gpu_subvendors_from_registry(): subvendors = [] pci_path = r"SYSTEM\CurrentControlSet\Enum\PCI" try: with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, pci_path) as pci_key: index = 0 while True: try: # 遍历PCI设备子项 dev_key_name = winreg.EnumKey(pci_key, index) dev_path = f"{pci_path}\\{dev_key_name}" with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, dev_path) as dev_key: sub_index = 0 while True: try: # 遍历设备的实例项 inst_key_name = winreg.EnumKey(dev_key, sub_index) inst_path = f"{dev_path}\\{inst_key_name}" with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, inst_path) as inst_key: # 获取硬件ID hardware_ids, _ = winreg.QueryValueEx(inst_key, "HardwareID") for hw_id in hardware_ids: if hw_id.startswith("PCI\\VEN_"): parts = hw_id.split('&') subsys_part = next((p for p in parts if p.startswith("SUBSYS_")), None) if subsys_part: subvendor_id = subsys_part[6:10] vendor_name = subvendor_map.get(subvendor_id, f"Unknown (ID: {subvendor_id})") subvendors.append(vendor_name) break sub_index += 1 except OSError: break index += 1 except OSError: break except WindowsError: return subvendors return list(set(subvendors)) if __name__ == "__main__": gpu_vendors = get_gpu_subvendors_from_registry() for vendor in gpu_vendors: print(f"显卡SubVendor: {vendor}")
补充说明
- 两种方案都依赖SubVendor ID到名称的映射表,你可以根据需要补充更多厂商的ID(可通过GPU-Z查看对应显卡的SubVendor ID,或者查询PCI SIG的官方数据库)。
- GPU-Z这类工具本质也是通过读取PCI配置空间或注册表来获取SubVendor信息,和上述方案原理一致。
内容的提问来源于stack exchange,提问作者Sokoloft
相关产品推荐
相关产品推荐

