音频属性处理程序

微型端口驱动程序会存储有关它在 PCPROPERTY_ITEM 结构中支持的每个属性的信息。 此结构包含有关该属性的以下信息:

  • 属性集 GUID 和属性 ID(或索引)

  • 指向属性的处理程序例程的函数指针

  • 指定处理程序支持的属性操作的标志

微型端口驱动程序为筛选器提供自动化表(由 PCAUTOMATION_TABLE 结构指定)。 驱动程序为筛选器的引脚类型和节点类型提供其他自动化表 - 每个引脚或节点类型都有自己的表。 每个自动化表都包含 PCPROPERTY_ITEM 结构的数组(可能为空),其中每个结构都描述了筛选器、引脚或节点的一个属性。 当客户端将属性请求发送到筛选器、引脚或节点时,端口驱动程序会将请求通过自动化表路由到相应的属性处理程序。

微型端口驱动程序可以为每个属性指定唯一的属性处理程序例程。 但是,如果驱动程序处理多个类似的属性,为方便起见,这些属性有时可以合并到单个处理程序例程中。 无论是为每个属性提供唯一处理程序还是将多个属性合并到单个处理程序中,都是由驱动程序编写人员做出的实现决策,这对于提交属性请求的客户端应透明。

用户模式客户端可以通过调用 Microsoft Win32 函数 DeviceIoControl 并将 dwIoControlCode 调用参数设置为 IOCTL_KS_PROPERTY 来发送获取、设置或基本支持属性请求。 操作系统会将此调用转换为 IRP,以将其调度到类驱动程序。 有关详细信息,请参阅 KS 属性

当客户端将 KS 属性请求(即 IOCTL_KS_PROPERTY I/O 控制 IRP)发送到筛选器句柄或引脚句柄时,KS 系统驱动程序 (Ks.sys) 会将请求传递到筛选器对象或引脚对象的端口驱动程序。 如果微型端口驱动程序为属性提供处理程序,端口驱动程序会将请求转发到处理程序。 转发请求之前,端口驱动程序会将属性请求中的信息转换为由 PCPROPERTY_REQUEST 结构指定的格式。 端口驱动程序会将此结构传递给微型端口驱动程序的处理程序。

PCPROPERTY_REQUEST 的 MajorTarget 成员指向音频设备的主要微型端口驱动程序接口。 例如,对于 WavePci 设备,这是指向微型端口驱动程序对象的 IMiniportWavePci 接口的指针。

对于发送到筛选器句柄的 KS 属性请求,PCPROPERTY_REQUEST 的 MinorTarget 成员为 NULL。 对于发送到引脚句柄的请求,MinorTarget 指向引脚的流接口。 例如,对于 WavePci 设备,这是指向流对象的 IMiniportWavePciStream 接口的指针。

PCPROPERTY_REQUEST 的 InstanceValue 成员分别指向 KS 属性请求的输入和输出缓冲区。 (缓冲区由 DeviceIoControl 函数的 lpInBufferlpOutBuffer 参数指定。)这些缓冲区分别包含属性描述符(实例数据)和属性值(操作数据),如音频驱动程序属性集中所述。 Value 成员指向输出缓冲区的开头,但实例指针是输入缓冲区开头处的偏移量。

输入缓冲区以 KSPROPERTYKSNODEPROPERTY 结构开头。 端口驱动程序将此信息从此结构复制到 PCPROPERTY_REQUEST 结构的 NodePropertyItemVerb 成员中。 如果任何数据都遵循缓冲区中的 KSPROPERTY 或 KSNODEPROPERTY 结构,则端口驱动程序会加载 Instance 成员,其中包含指向此数据的指针。 否则,它会将 Instance 设置为 NULL

如果输入缓冲区以不含节点信息的 KSPROPERTY 结构开头,则端口驱动程序会将 PCPROPERTY_REQUEST 结构的 Node 成员设置为 ULONG(-1)。 在这种情况下,端口驱动程序会从微型端口驱动程序的自动化表中为筛选器或引脚调用相应的处理程序,具体取决于属性请求的目标是由筛选器句柄还是引脚句柄指定。 (如果该表没有为属性指定处理程序,则端口驱动程序会改为处理请求。)

如果输入缓冲区以 KSNODEPROPERTY 结构开头,端口驱动程序会将节点 ID 从此结构复制到 PCPROPERTY_REQUEST 结构的 Node 成员中,并从微型端口驱动程序的自动化表中调用节点的相应处理程序。 (同样,如果该表没有为属性指定处理程序,则端口驱动程序会改为处理请求。)

端口驱动程序会检查属性请求操作标志中的 KSPROPERTY_TYPE_TOPOLOGY 位,以确定两个结构(KSPROPERTY 或 KSNODEPROPERTY)中的哪一个位于输入缓冲区的开头:

  • 如果设置了此位,则请求适用于节点属性,并且输入缓冲区以 KSNODEPROPERTY 结构开头。

  • 否则,输入缓冲区以 KSPROPERTY 结构开头。

有关 KSPROPERTY_TYPE_TOPOLOGY 的详细信息,请参阅 KSPROPERTY

PCPROPERTY_REQUEST 结构的 InstanceSizeValueSize 成员指定 InstanceValue 成员指向的缓冲区大小。 ValueSize 等于属性请求的输出缓冲区大小,但 InstanceSize 是输入缓冲区中遵循 KSPROPERTY 或 KSNODEPROPERTY 结构的数据的大小。 也就是说,InstanceSize 是输入缓冲区的大小减去 KSPROPERTY 或 KSNODEPROPERTY 结构的大小。 如果没有任何其他数据遵循此结构,则端口驱动程序会将 InstanceSize 设置为零(将 Instance 设置为 NULL)。

例如,如果客户端将 KSNODEPROPERTY_AUDIO_CHANNEL 结构指定为输入缓冲区中的实例数据,端口驱动程序会将处理程序传递给 PCPROPERTY_REQUEST 结构,其 Instance 成员指向 KSNODEPROPERTY_AUDIO_CHANNEL 结构的 Channel 成员,并且其 InstanceSize 成员包含该值

sizeof(KSNODEPROPERTY_AUDIO_CHANNEL) - sizeof(KSNODEPROPERTY)

在提交 get-property 请求以检索属性值之前,客户端应分配一个输出缓冲区,微型端口驱动程序的属性处理程序可以向其中写入属性值。 对于某些属性,输出缓冲区的大小取决于设备,客户端必须查询属性处理程序以获取所需的缓冲区大小。 在这些情况下,客户端会提交初始属性请求,其输出缓冲区指针为 nullptr,输出缓冲区长度为零。 处理程序通过返回所需的缓冲区大小以及状态代码 STATUS_BUFFER_OVERFLOW 进行响应。 然后,客户端通过分配指定大小的输出缓冲区并在第二个 get-property 请求中发送此缓冲区来检索属性值。

如果指定的缓冲区大小太小,无法接收所请求的任何信息,该方法将返回 STATUS_BUFFER_TOO_SMALL。

在某些情况下,PortCls 端口驱动程序会返回 STATUS_BUFFER_TOO_SMALL 而非 STATUS_BUFFER_OVERFLOW,以响应具有非零输出缓冲区地址和大小的属性请求。 在这种情况下,不返回所需的缓冲区大小。

有关详细信息,请参阅使用 NTSTATUS 值和以下博客文章: