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

使用RegisterDeviceNotification监听NFC令牌的两个技术疑问

关于使用RegisterDeviceNotification监听NFC令牌的疑问及解答

问题背景

我正尝试使用RegisterDeviceNotification实现对新NFC令牌的监听,现有以下两个疑问:

  1. 从设备管理器获取的未知智能卡(即NFC令牌)的类GUID是否正确?我已从设备管理器中未知智能卡(NFC令牌)的属性窗口提取了类GUID(见附图)。
  2. 设备类型设置为DBT_DEVTYP_DEVICEINTERFACE是否正确?如何判断DBT_DEVTYP_DEVICEINTERFACE是否适用?

我的Pascal代码

type
  PDEV_BROADCAST_DEVICEINTERFACE  = ^DEV_BROADCAST_DEVICEINTERFACE;
  {$EXTERNALSYM PDEV_BROADCAST_DEVICEINTERFACE}
  DEV_BROADCAST_DEVICEINTERFACE = record
    dbcc_size: DWORD;
    dbcc_devicetype: DWORD;
    dbcc_reserved: DWORD;
    dbcc_classguid: TGUID;
    dbcc_name: array[0..0] of Char;
  end;
  {$EXTERNALSYM DEV_BROADCAST_DEVICEINTERFACE}

procedure TMainF.BRegisterDeviceNotificationClick(Sender: TObject);
const
  testguid: TGUID = '{990a2bd7-e738-46c7-b26f-1cf8fb9f1391}';
var
  x: DEV_BROADCAST_DEVICEINTERFACE;
begin
  FillChar(x, SizeOf(x), 0);
  x.dbcc_devicetype := DBT_DEVTYP_DEVICEINTERFACE;
  x.dbcc_classguid := testguid;
  x.dbcc_size := SizeOf(x);
  p := RegisterDeviceNotification(Handle, @x, DEVICE_NOTIFY_WINDOW_HANDLE);
  if not Assigned(p) then
    RaiseLastOSError;
end;

procedure TMainF.WMDeviceChange(var Msg: TMessage);
var
  x: PDEV_BROADCAST_DEVICEINTERFACE;
begin
  x := @Msg.LParam;
  case Msg.WParam of
    DBT_DEVNODES_CHANGED: begin
      MOutput.Lines.Add('Device changed: ' + FormatDateTime('yyyymmdd hh:nn:ss.zzz', now));
      MOutput.Lines.Add(GUIDToString(x.dbcc_classguid));
    end;
    DBT_DEVICEARRIVAL: begin
      MOutput.Lines.Add('Device arrived ' + FormatDateTime('yyyymmdd hh:nn:ss.zzz', now));
      MOutput.Lines.Add(GUIDToString(x.dbcc_classguid));
    end;
    DBT_DEVICEREMOVECOMPLETE: begin
      MOutput.Lines.Add('Device removed ' + FormatDateTime('yyyymmdd hh:nn:ss.zzz', now));
      MOutput.Lines.Add(GUIDToString(x.dbcc_classguid));
    end;
  end;
end;

程序运行输出

Device changed: 20250204 16:05:34.776
{77AB164B-0F08-0021-1902-000007000000}
Device changed: 20250204 16:05:38.291
{77AB164B-0F08-0021-1902-000007000000}
Device changed: 20250204 16:05:38.358
{77AB164B-0F08-0021-1902-000007000000}

程序输出窗口

USB Device Tree Viewer设备信息

+++++++++++++++++ Device Information ++++++++++++++++++
Device Description       : 未知智能卡
Device ID                : SCFILTER\CID_804F0CA00000030603000300000000\7&43C62A7&0&ACS_ACR1252_1S_CL_READER_PICC_0_SCFILTER_CID_804F0CA00000030603000300000000
Hardware IDs             : SCFILTER\CID_804f0ca00000030603000300000000
Driver KeyName           : {990a2bd7-e738-46c7-b26f-1cf8fb9f1391}\0004
Driver Inf               : C:\Windows\inf\scunknown.inf
Legacy BusType           : Internal
Class                    : SmartCard
Class GUID               : {990a2bd7-e738-46c7-b26f-1cf8fb9f1391}
Enumerator               : SCFILTER
Location Info            : ScFilter
Address                  : 4294967295 (0xFFFFFFFF)
Manufacturer Info        : Microsoft
Capabilities             : 0x84 (Removable, SurpriseRemovalOK)
Status                   : 0x01806000 (DN_DISABLEABLE, DN_REMOVABLE, DN_NT_ENUMERATOR, DN_NT_DRIVER)
Problem Code             : 0
EnhancedPowerMgmtEnabled : 0
Power State              : D3 (supported: D0, D3, wake from D0)

疑问解答

1. 类GUID是否正确?

从你提供的USB Device Tree Viewer信息来看,Class GUID字段明确显示为{990a2bd7-e738-46c7-b26f-1cf8fb9f1391},这个GUID是Windows系统定义的智能卡设备类标准GUID,所以你提取的类GUID是正确的。

但程序输出的GUID与注册值不符,原因是DBT_DEVNODES_CHANGED消息的LParam并不指向DEV_BROADCAST_DEVICEINTERFACE结构——该消息没有关联的设备细节数据,你强行将其转为PDEV_BROADCAST_DEVICEINTERFACE会读取到错误内存数据,导致GUID显示异常。

2. 设备类型设置是否正确?

DBT_DEVTYP_DEVICEINTERFACE是正确的选择,原因如下:

  • 当需要监听某一类设备的插拔事件时,尤其是像智能卡这类通过设备接口类暴露的设备,该类型基于设备接口GUID匹配设备,适合批量监听同类型设备。
  • 判断适用规则:如果目标设备属于已定义的设备接口类(比如智能卡类),或需要监听符合特定接口标准的设备,就用DBT_DEVTYP_DEVICEINTERFACE;若监听单个特定设备(通过设备实例路径),则用DBT_DEVTYP_DEVICEINSTANCE;监听卷设备用DBT_DEVTYP_VOLUME。

另外你的代码存在两个关键问题:

  1. DEV_BROADCAST_DEVICEINTERFACE结构的dbcc_size计算错误:该结构末尾是可变长度的dbcc_name数组,注册时需计算完整结构大小,对于Unicode版本应设置为SizeOf(DEV_BROADCAST_DEVICEINTERFACE) - SizeOf(Char) + 1,当前仅设为SizeOf(x)会导致结构不完整,可能引发注册失败或事件接收异常。
  2. WMDeviceChange消息处理逻辑错误:仅DBT_DEVICEARRIVAL和DBT_DEVICEREMOVECOMPLETE的LParam指向DEV_BROADCAST_HDR结构,需先检查该结构的dbch_devicetype是否为DBT_DEVTYP_DEVICEINTERFACE,再强转为PDEV_BROADCAST_DEVICEINTERFACE;DBT_DEVNODES_CHANGED无有效LParam数据,不能直接读取其中的GUID。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 15:15:07