与设备交互的 Win32 服务

通过与设备交互的 INF AddService 安装的理想 Win32 服务的行为类似于 驱动程序设备交互的方式。 根据是否存在设备加载和卸载驱动程序,与设备交互的 Win32 服务应遵循此相同的 启动停止 模式,具体取决于设备是否存在。

仅当存在设备接口并启用与服务交互时,服务才应启动,并在设备接口不再启用时停止。 此设计模式可确保可靠的服务,以最大程度地减少不需要和未定义的行为。 我们将演示如何设计服务以遵循此模式。

服务安装

若要安装服务,请使用 INF AddService 指令。 这将允许你创建和启动服务。

添加使服务需要启动的设置。 这可以通过设置 StartType=0x3 来实现,这会启动服务触发器。

本部分的最后一步是使用 AddTrigger 指令在设备接口到达时启动服务 (有关 AddTrigger) 的更多详细信息,请参阅 AddService。 下面是应如何使用 AddTrigger 的示例:

[UserSvc_Install]
ServiceType   = 0x10 ; SERVICE_WIN32_OWN_PROCESS
StartType     = 3    ; SERVICE_DEMAND_START
ErrorControl  = 0    ; SERVICE_ERROR_IGNORE
ServiceBinary = %13%\oemsvc.exe
AddTrigger    = UserSvc_AddTrigger

[UserSvc_AddTrigger]
TriggerType = 1                           ; SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL
Action      = 1                           ; SERVICE_TRIGGER_ACTION_SERVICE_START
SubType     = %GUID_DEVINTERFACE_OSRFX2%  ; Interface class GUID
DataItem    = 2, "USB\VID_0547&PID_1002"  ; SERVICE_TRIGGER_DATA_TYPE_STRING

请注意,DataItem 中指定的 HardwareId 是可选的,通常仅在使用泛型类接口将触发器范围限定为更具体的设备时才需要。

服务运行时

从运行时的角度来看,服务的第一步应该是注册设备接口通知。 有关如何完成此操作的规范性指南,可在此页找到: 注册设备接口到达和设备删除通知

具体而言,应将 CM_Register_NotificationCM_NOTIFY_FILTERY_TYPE_DEVICEINTERFACE 标志一起使用,以完成设备接口通知的相应注册。

注意

当服务启动时,你不能依赖将接收设备接口通知这一事实,因为到达通知可能已经传递,尤其是在设备接口到达是服务启动的原因时。 相反,如果已存在接口,则必须获取要检查的设备接口列表。

注册设备接口的通知后,你将收到有关启用新设备接口或禁用现有设备接口的通知。 可以从通知回调发现设备接口路径。 若要查询现有设备接口的列表,以检查服务启动并注册通知之前存在的设备接口,可以通过 CM_Get_Device_Interface_List等 API 获取设备接口的列表。

注意

设备接口有可能在注册通知和检索系统上已有的设备接口列表之间到达。 在这种情况下,设备接口将同时在通知回调和设备接口列表中列出。

如果要使用 I/O API 与设备接口交互,找到所需的设备接口后,请通过 CreateFile 打开接口的句柄。

下一步是注册辅助每个句柄通知,以获取有关设备状态更改的通知,例如尝试查询删除设备或设备离开。 这可以使用带有 CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE 标志的CM_Register_Notification来完成。 按照 注册设备接口到达和设备删除通知 中的指导,确保设备离开时,可以相应地释放句柄。

应跟踪设备接口的到达和删除,以便删除服务可能要与之交互的最后一个设备接口意味着可以停止服务。 删除最后一个接口后,停止服务 (可在 此页面) 找到详细信息。 这可以通过执行以下步骤来实现:

  1. 将SERVICE_STOP_PENDING状态发布到 SCM,以指示服务正在关闭

  2. 取消初始化/清理服务使用的所有内容

  3. SERVICE_STOP 状态发布到 SCM 以完成停止操作

如果服务正在停止,请确保检查,并通过设备接口的所有现有打开句柄, (可能没有任何) 并清理它们。

设备接口可以在设备安装、设备启用/禁用、设备重新枚举、系统重启期间或在未列出的其他方案中恢复。 当设备接口恢复时,将根据其触发器启动注册触发服务。

此流将确保服务在设备接口到达时启动,并在最后一个设备接口不再存在时停止。

GitHub 上有一个示例,演示了服务如何利用此事件流。 示例可在此处找到: Win32 服务示例

此外,还可以在 AddService 页上找到有关 AddTrigger 的有用文档。