You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ctypes如何解析SetupDiGetDeviceRegistryPropertyW返回的缓冲区

问题原因

打印得到指针对象是因为直接输出了ctypes指针实例本身,没有读取指针指向的内存内容,同时代码存在几处逻辑错误会导致解析失败:

  • 仅定义了ANSI版本SetupDiGetDeviceRegistryPropertyA的参数约束,未定义Wide版本SetupDiGetDeviceRegistryPropertyW的argtypes/restype,ctypes会按默认规则传参,容易触发内存访问异常
  • 传入PropertyRegDataType参数时传了None,该参数要求传入DWORD指针接收注册表值类型,传空会导致函数调用不符合API约定
  • SPDRP_HARDWAREID对应的注册表值类型是REG_MULTI_SZ(多字符串格式),内容是多个以\0分隔的硬件ID字符串,末尾以双\0结尾,不是单个WCHAR字符串,直接转单WCHAR指针无法正确读取全部内容
  • POINTER(w.WCHAR)是指向单个宽字符的指针类型,直接打印该类型变量只会输出对象的内存地址表示,不会自动解引用读取连续的字符串内容
正确修复方法

第一步:补全W版本API的参数定义

在原有API定义部分补充以下代码:

SetupAPI.SetupDiGetDeviceRegistryPropertyW.argtypes = HDEVINFO, PSP_DEVINFO_DATA, w.DWORD, w.PDWORD, w.PBYTE, w.DWORD, w.PDWORD
SetupAPI.SetupDiGetDeviceRegistryPropertyW.restype = w.BOOL

第二步:修正参数传递与缓冲区解析逻辑

替换原循环内的属性读取、解析代码:

PropertyRegDataType = w.DWORD()  # 原代码传None为错误写法
# 第一次调用获取所需缓冲区大小
SetupAPI.SetupDiGetDeviceRegistryPropertyW(
    hDevInfo,
    ct.byref(devinfo),
    SPDRP_HARDWAREID,
    ct.byref(PropertyRegDataType),
    None, 
    PropertyBufferSize ,
    ct.byref(RequiredSize))

PropertyBuffer = (w.BYTE * RequiredSize.value)()
if not SetupAPI.SetupDiGetDeviceRegistryPropertyW(
    hDevInfo,
    ct.byref(devinfo),
    SPDRP_HARDWAREID,
    ct.byref(PropertyRegDataType),
    PropertyBuffer, 
    ct.sizeof(PropertyBuffer),
    None):
    MemberIndex += 1
    continue

# 解析REG_MULTI_SZ格式内容,直接转字节按UTF-16LE解码最稳妥
raw_content = bytes(PropertyBuffer).decode('utf-16-le')
hardware_id_list = [item for item in raw_content.split('\0') if item]
print("当前设备硬件ID列表:", hardware_id_list)

# 从硬件ID中提取VID/PID
for id_str in hardware_id_list:
    if id_str.startswith('USB\\VID_') and '&PID_' in id_str:
        vid = id_str.split('VID_')[1][:4]
        pid = id_str.split('PID_')[1][:4]
        print(f"厂商ID: 0x{vid.upper()}, 产品ID: 0x{pid.upper()}")

补充:单字符串属性的正确读取方式

如果读取的是SPDRP_FRIENDLYNAME、SPDRP_DEVICEDESC这类REG_SZ类型的单字符串属性,cast指针后取.value即可拿到完整Python字符串:

str_ptr = ct.cast(PropertyBuffer, w.LPWSTR)
device_name = str_ptr.value
print(device_name)

不要直接用ct.POINTER(w.WCHAR)转换字符串缓冲区,该类型是指向单个WCHAR的指针,没有自动读取连续字符串的能力,用w.LPWSTR(ctypes预定义的宽字符串指针)的value属性,才会自动读取到\0终止符位置的完整字符串。

内容的提问来源于stack exchange,提问作者user19212551

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 05:48:41